当前位置:   article > 正文

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

cv.equalizehist

作者:翟天保Steven
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处

实现原理

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

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

功能函数代码

  1. // 直方图均衡化
  2. cv::Mat EqualizeHist(cv::Mat src)
  3. {
  4. cv::Mat h = cv::Mat::zeros(1, 256, CV_32FC1);
  5. cv::Mat hs = cv::Mat::zeros(1, 256, CV_32FC1);
  6. cv::Mat hp = cv::Mat::zeros(1, 256, CV_32FC1);
  7. cv::Mat result = cv::Mat::zeros(src.size(), src.type());
  8. int sum = 0;
  9. for (int i = 0; i < src.rows; ++i)
  10. {
  11. for (int j = 0; j < src.cols; ++j)
  12. {
  13. h.at<float>(0, src.at <uchar>(i, j))++;
  14. sum++;
  15. }
  16. }
  17. for (int i = 0; i < 256; ++i)
  18. {
  19. hs.at<float>(0, i) = h.at<float>(0, i) / sum;
  20. if (i == 0)
  21. {
  22. hp.at<float>(0, i) = hs.at<float>(0, i);
  23. }
  24. else {
  25. hp.at<float>(0, i) = hp.at<float>(0, i - 1) + hs.at<float>(0, i);
  26. }
  27. }
  28. for (int i = 0; i < src.rows; ++i)
  29. {
  30. for (int j = 0; j < src.cols; ++j)
  31. {
  32. result.at <uchar>(i, j) = uchar(round(255 * hp.at<float>(0, src.at<uchar>(i, j))));
  33. }
  34. }
  35. return result;
  36. }
  37. // 绘制简易直方图
  38. cv::Mat drawHistImg(cv::Mat &src)
  39. {
  40. cv::Mat hist = cv::Mat::zeros(1, 256, CV_32FC1);
  41. for (int i = 0; i < src.rows; ++i)
  42. {
  43. for (int j = 0; j < src.cols; ++j)
  44. {
  45. hist.at<float>(0, src.at <uchar>(i, j))++;
  46. }
  47. }
  48. cv::Mat histImage = cv::Mat::zeros(540, 1020, CV_8UC1);
  49. const int bins = 255;
  50. double maxValue;
  51. cv::Point2i maxLoc;
  52. cv::minMaxLoc(hist, 0, &maxValue, 0, &maxLoc);
  53. int scale = 4;
  54. int histHeight = 540;
  55. for (int i = 0; i < bins; i++)
  56. {
  57. float binValue = (hist.at<float>(i));
  58. int height = cvRound(binValue * histHeight / maxValue);
  59. cv::rectangle(histImage, cv::Point(i * scale, histHeight),
  60. cv::Point((i + 1) * scale-1, histHeight - height), cv::Scalar(255), -1);
  61. }
  62. return histImage;
  63. }

函数原型

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

void equalizeHist( InputArray src, OutputArray dst );

参数说明

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

C++测试代码

  1. #include <iostream>
  2. #include <time.h>
  3. #include <opencv2/opencv.hpp>
  4. using namespace std;
  5. using namespace cv;
  6. cv::Mat EqualizeHist(cv::Mat src);
  7. cv::Mat drawHistImg(cv::Mat &hist);
  8. int main()
  9. {
  10. cv::Mat src = imread("test.jpg",0);
  11. cv::Mat src1 = imread("test.jpg");
  12. clock_t start1, start2, end1,end2;
  13. // 绘制原图直方图
  14. cv::Mat hI = drawHistImg(src);
  15. // 自定义直方图均衡化
  16. start1 = clock();
  17. cv::Mat result1 = EqualizeHist(src);
  18. end1 = clock();
  19. double dif1 = (end1 - start1) / CLOCKS_PER_SEC;
  20. cout << "time1:" << dif1 << endl;
  21. // 绘制均衡化后直方图
  22. cv::Mat hrI = drawHistImg(result1);
  23. // 官方直方图均衡化函数
  24. start2 = clock();
  25. cv::Mat result2;
  26. equalizeHist(src, result2);
  27. end2 = clock();
  28. double dif2 = (end2 - start2) / CLOCKS_PER_SEC;
  29. cout << "time2:" << dif2 << endl;
  30. // 绘制均衡化后直方图
  31. cv::Mat hr2I = drawHistImg(result2);
  32. // 彩色直方图均衡化,三通道分别作均衡再合并
  33. vector<cv::Mat> rgb,rgb_;
  34. cv::Mat r, g, b;
  35. cv::split(src1, rgb);
  36. equalizeHist(rgb[0], b);
  37. equalizeHist(rgb[1], g);
  38. equalizeHist(rgb[2], r);
  39. rgb_.push_back(b);
  40. rgb_.push_back(g);
  41. rgb_.push_back(r);
  42. cv::Mat src1_;
  43. cv::merge(rgb_, src1_);
  44. imshow("original", src1);
  45. imshow("result", src1_);
  46. waitKey(0);
  47. return 0;
  48. }
  49. // 直方图均衡化
  50. cv::Mat EqualizeHist(cv::Mat src)
  51. {
  52. cv::Mat h = cv::Mat::zeros(1, 256, CV_32FC1);
  53. cv::Mat hs = cv::Mat::zeros(1, 256, CV_32FC1);
  54. cv::Mat hp = cv::Mat::zeros(1, 256, CV_32FC1);
  55. cv::Mat result = cv::Mat::zeros(src.size(), src.type());
  56. int sum = 0;
  57. for (int i = 0; i < src.rows; ++i)
  58. {
  59. for (int j = 0; j < src.cols; ++j)
  60. {
  61. h.at<float>(0, src.at <uchar>(i, j))++;
  62. sum++;
  63. }
  64. }
  65. for (int i = 0; i < 256; ++i)
  66. {
  67. hs.at<float>(0, i) = h.at<float>(0, i) / sum;
  68. if (i == 0)
  69. {
  70. hp.at<float>(0, i) = hs.at<float>(0, i);
  71. }
  72. else {
  73. hp.at<float>(0, i) = hp.at<float>(0, i - 1) + hs.at<float>(0, i);
  74. }
  75. }
  76. for (int i = 0; i < src.rows; ++i)
  77. {
  78. for (int j = 0; j < src.cols; ++j)
  79. {
  80. result.at <uchar>(i, j) = uchar(round(255 * hp.at<float>(0, src.at<uchar>(i, j))));
  81. }
  82. }
  83. return result;
  84. }
  85. // 绘制简易直方图
  86. cv::Mat drawHistImg(cv::Mat &src)
  87. {
  88. cv::Mat hist = cv::Mat::zeros(1, 256, CV_32FC1);
  89. for (int i = 0; i < src.rows; ++i)
  90. {
  91. for (int j = 0; j < src.cols; ++j)
  92. {
  93. hist.at<float>(0, src.at <uchar>(i, j))++;
  94. }
  95. }
  96. cv::Mat histImage = cv::Mat::zeros(540, 1020, CV_8UC1);
  97. const int bins = 255;
  98. double maxValue;
  99. cv::Point2i maxLoc;
  100. cv::minMaxLoc(hist, 0, &maxValue, 0, &maxLoc);
  101. int scale = 4;
  102. int histHeight = 540;
  103. for (int i = 0; i < bins; i++)
  104. {
  105. float binValue = (hist.at<float>(i));
  106. int height = cvRound(binValue * histHeight / maxValue);
  107. cv::rectangle(histImage, cv::Point(i * scale, histHeight),
  108. cv::Point((i + 1) * scale-1, histHeight - height), cv::Scalar(255), -1);
  109. }
  110. return histImage;
  111. }

测试效果

图1 灰度原图

       其直方图如下: 

图2 直方图
图3 均衡化后灰度图

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

       自定义函数:

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

        官方函数:

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

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

图6 彩色原图
图7 彩色均衡化效果

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

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/116221
推荐阅读
相关标签
  

闽ICP备14008679号