OpenCV-实现直方图均衡化(对比cv::equalizeHist)

简介: OpenCV-实现直方图均衡化(对比cv::equalizeHist)

实现原理

      通过图像数据的直方图,可以快速判断图像的亮度和质量。而直方图均衡化就是通过图像变换使得直方图均匀分布,起到对比度增强的效果。在图像处理的课本中,针对离散形式的图像数据,最常用的一种方法就是累计概率分布。首先统计0-255灰度值所占像素个数;再计算出像素个数与总像素的比,表示为出现的概率;从0开始进行累计概率分布,即从0慢慢累加各层概率值直到1;则均衡化图像的灰度值=原灰度值所对应的累计概率*255。


      基于上述原理,我自定义了一个简单的直方图均衡化函数EqualizeHist,并定义了直方图简易绘制函数drawHistImg,用来作直观对比。

功能函数代码

// 直方图均衡化
cv::Mat EqualizeHist(cv::Mat src)
{
  cv::Mat h = cv::Mat::zeros(1, 256, CV_32FC1);
  cv::Mat hs = cv::Mat::zeros(1, 256, CV_32FC1);
  cv::Mat hp = cv::Mat::zeros(1, 256, CV_32FC1);
  cv::Mat result = cv::Mat::zeros(src.size(), src.type());
  int sum = 0;
  for (int i = 0; i < src.rows; ++i)
  {
    for (int j = 0; j < src.cols; ++j)
    {
      h.at<float>(0, src.at <uchar>(i, j))++;
      sum++;
    }
  }
  for (int i = 0; i < 256; ++i)
  {
    hs.at<float>(0, i) = h.at<float>(0, i) / sum;
    if (i == 0)
    {
      hp.at<float>(0, i) = hs.at<float>(0, i);
    }
    else {
      hp.at<float>(0, i) = hp.at<float>(0, i - 1) + hs.at<float>(0, i);
    }
  }
  for (int i = 0; i < src.rows; ++i)
  {
    for (int j = 0; j < src.cols; ++j)
    {
      result.at <uchar>(i, j) = uchar(round(255 * hp.at<float>(0, src.at<uchar>(i, j))));
    }
  }
  return result;
}
// 绘制简易直方图
cv::Mat drawHistImg(cv::Mat &src)
{
  cv::Mat hist = cv::Mat::zeros(1, 256, CV_32FC1);
  for (int i = 0; i < src.rows; ++i)
  {
    for (int j = 0; j < src.cols; ++j)
    {
      hist.at<float>(0, src.at <uchar>(i, j))++;
    }
  }
  cv::Mat histImage = cv::Mat::zeros(540, 1020, CV_8UC1);
  const int bins = 255;
  double maxValue;
  cv::Point2i maxLoc;
  cv::minMaxLoc(hist, 0, &maxValue, 0, &maxLoc);
  int scale = 4;
  int histHeight = 540;
  for (int i = 0; i < bins; i++)
  {
    float binValue = (hist.at<float>(i));
    int height = cvRound(binValue * histHeight / maxValue);
    cv::rectangle(histImage, cv::Point(i * scale, histHeight),
      cv::Point((i + 1) * scale-1, histHeight - height), cv::Scalar(255), -1);
  }
  return histImage;
}

函数原型

      官方OpenCV库中也有自带的直方图均衡化函数:

void equalizeHist( InputArray src, OutputArray dst );

参数说明

  1. InputArray类型的src,输入图像,如Mat类型。
  2. OutputArray类型的dst,输出图像。


C++测试代码

#include <iostream>
#include <time.h>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
cv::Mat EqualizeHist(cv::Mat src);
cv::Mat drawHistImg(cv::Mat &hist);
int main()
{
  cv::Mat src = imread("test.jpg",0);
  cv::Mat src1 = imread("test.jpg");
  clock_t start1, start2, end1,end2;
  // 绘制原图直方图
  cv::Mat hI = drawHistImg(src);
  // 自定义直方图均衡化
  start1 = clock();
  cv::Mat result1 = EqualizeHist(src);
  end1 = clock();
  double dif1 = (end1 - start1) / CLOCKS_PER_SEC;
  cout << "time1:" << dif1 << endl;
  // 绘制均衡化后直方图
  cv::Mat hrI = drawHistImg(result1);
  // 官方直方图均衡化函数
  start2 = clock();
  cv::Mat result2;
  equalizeHist(src, result2);
  end2 = clock();
  double dif2 = (end2 - start2) / CLOCKS_PER_SEC;
  cout << "time2:" << dif2 << endl;
  // 绘制均衡化后直方图
  cv::Mat hr2I = drawHistImg(result2);
  // 彩色直方图均衡化,三通道分别作均衡再合并
  vector<cv::Mat> rgb,rgb_;
  cv::Mat r, g, b;
  cv::split(src1, rgb);
  equalizeHist(rgb[0], b);
  equalizeHist(rgb[1], g);
  equalizeHist(rgb[2], r);
  rgb_.push_back(b);
  rgb_.push_back(g);
  rgb_.push_back(r);
  cv::Mat src1_;
  cv::merge(rgb_, src1_);
  imshow("original", src1);
  imshow("result", src1_);
  waitKey(0);
  return 0;
}
// 直方图均衡化
cv::Mat EqualizeHist(cv::Mat src)
{
  cv::Mat h = cv::Mat::zeros(1, 256, CV_32FC1);
  cv::Mat hs = cv::Mat::zeros(1, 256, CV_32FC1);
  cv::Mat hp = cv::Mat::zeros(1, 256, CV_32FC1);
  cv::Mat result = cv::Mat::zeros(src.size(), src.type());
  int sum = 0;
  for (int i = 0; i < src.rows; ++i)
  {
    for (int j = 0; j < src.cols; ++j)
    {
      h.at<float>(0, src.at <uchar>(i, j))++;
      sum++;
    }
  }
  for (int i = 0; i < 256; ++i)
  {
    hs.at<float>(0, i) = h.at<float>(0, i) / sum;
    if (i == 0)
    {
      hp.at<float>(0, i) = hs.at<float>(0, i);
    }
    else {
      hp.at<float>(0, i) = hp.at<float>(0, i - 1) + hs.at<float>(0, i);
    }
  }
  for (int i = 0; i < src.rows; ++i)
  {
    for (int j = 0; j < src.cols; ++j)
    {
      result.at <uchar>(i, j) = uchar(round(255 * hp.at<float>(0, src.at<uchar>(i, j))));
    }
  }
  return result;
}
// 绘制简易直方图
cv::Mat drawHistImg(cv::Mat &src)
{
  cv::Mat hist = cv::Mat::zeros(1, 256, CV_32FC1);
  for (int i = 0; i < src.rows; ++i)
  {
    for (int j = 0; j < src.cols; ++j)
    {
      hist.at<float>(0, src.at <uchar>(i, j))++;
    }
  }
  cv::Mat histImage = cv::Mat::zeros(540, 1020, CV_8UC1);
  const int bins = 255;
  double maxValue;
  cv::Point2i maxLoc;
  cv::minMaxLoc(hist, 0, &maxValue, 0, &maxLoc);
  int scale = 4;
  int histHeight = 540;
  for (int i = 0; i < bins; i++)
  {
    float binValue = (hist.at<float>(i));
    int height = cvRound(binValue * histHeight / maxValue);
    cv::rectangle(histImage, cv::Point(i * scale, histHeight),
      cv::Point((i + 1) * scale-1, histHeight - height), cv::Scalar(255), -1);
  }
  return histImage;
}

测试效果

图1 灰度原图

      其直方图如下:

图2 直方图

图3 均衡化后灰度图

      两个函数运行时间都在0.001s以下,其均衡化后直方图略有差异,但都实现了均衡效果。

      自定义函数:

图4 自定义函数均衡化后直方图

官方函数:

图5 官方函数均衡化后直方图

        对彩色图的三通道分别进行直方图均衡化,实现彩色均衡效果:

图6 彩色原图

图7 彩色均衡化效果

     如果函数有什么可以改进完善的地方,非常欢迎大家指出,一同进步何乐而不为呢~

      如果文章帮助到你了,可以点个赞让我知道,我会很快乐~加油!

相关文章
|
5月前
|
机器学习/深度学习 人工智能 算法
Python在计算机视觉(CV)中扮演重要角色,得益于其丰富的库如OpenCV、Pillow和Scikit-image。
【7月更文挑战第5天】Python在计算机视觉(CV)中扮演重要角色,得益于其丰富的库如OpenCV、Pillow和Scikit-image。CV涉及图像处理、模式识别和机器学习,用于图像理解和生成。Python的跨平台特性和活跃社区使其成为CV的理想工具。基本流程包括图像获取、预处理、特征提取、分类识别及图像生成。例如,面部识别通过预处理图像,使用如`cv2.CascadeClassifier`进行检测;物体检测类似,但需适应不同目标;图像生成则利用GAN创造新图像。
75 4
|
4月前
|
计算机视觉 索引
OpenCV读取视频失败<无可用信息,未为 opencv_world453.dll 加载任何符号> cv::VideoCapture
本文介绍了解决OpenCV读取视频失败的错误,指出问题通常由视频路径错误或摄像头索引错误导致,并提供了相应的解决方法。
OpenCV读取视频失败<无可用信息,未为 opencv_world453.dll 加载任何符号> cv::VideoCapture
|
4月前
|
计算机视觉
OpenCV 图像类型标识符 CV_<bit_depth><S|U|F>C<number_of_channels>
OpenCV 图像类型标识符 CV_<bit_depth><S|U|F>C<number_of_channels>
50 0
|
计算机视觉
OpenCV-模板匹配cv::matchTemplate
OpenCV-模板匹配cv::matchTemplate
121 0
|
计算机视觉
OpenCV-矩形边框cv::boundingRect
OpenCV-矩形边框cv::boundingRect
123 0
|
计算机视觉
OpenCV-中值滤波cv::medianBlur
OpenCV-中值滤波cv::medianBlur
|
7月前
|
计算机视觉
OpenCV报错: cv::Exception,位于内存位置 0x00000078226FEE58 处。
OpenCV报错: cv::Exception,位于内存位置 0x00000078226FEE58 处。
|
7月前
|
计算机视觉 Python
opencv cv::Range()和cv::Rect()用于crop来获得感兴趣区域
opencv cv::Range()和cv::Rect()用于crop来获得感兴趣区域
280 0
|
计算机视觉
OpenCV-绘制标记符cv::drawMarker
OpenCV-绘制标记符cv::drawMarker
258 2
|
计算机视觉 容器
OpenCV-图像金字塔cv::buildPyramid
OpenCV-图像金字塔cv::buildPyramid
OpenCV-图像金字塔cv::buildPyramid

热门文章

最新文章