直方图规范化的opencv的实现

                <link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-62cd27f8b9.css">
                    <div class="htmledit_views">

直方图规范化也叫规定化。通过直方图的规定,能够把两幅图像的色调拉成一样。

数学原理在网上很多可以找到。这里说一下实现过程步骤和opencv的C++实现。


上表一行行看下来,大部分应该没什么问题。SML映射看的是原始累计直方图的值最相近的规定累计直方图的位置,(比如0.14在下面找最接近的是0.19,是就是3).

然后下面就很简单了,灰度0映射到灰度3,灰度1映射到灰度4。。。

代码还是比较简单的,就是网上搜了一下也没有,OPENCV本身也没有封装。就自己写了一个,和大家共享。


  
  
  1. #include <opencv2/core/core.hpp>
  2. #include <opencv2/imgproc/imgproc.hpp>
  3. #include <opencv2/highgui/highgui.hpp>
  4. #include <iostream>
  5. using namespace std;
  6. using namespace cv;
  7. bool Cal_Hist(Mat Gray_img, MatND &hist){
  8. int bins = 256;
  9. int hist_size[] = { bins };
  10. float range[] = { 0, 256 };
  11. const float* ranges[] = { range };
  12. int channels[] = { 0 };
  13. //计算直方图
  14. calcHist(&Gray_img, 1, channels, Mat(), // do not use mask
  15. hist, 1, hist_size, ranges,
  16. true, // the histogram is uniform
  17. false);
  18. if (hist.data == 0) return false;
  19. return true;
  20. }
  21. void DrawGrayHist(const char* pTitle, MatND& hist)
  22. {
  23. int hist_height = 256;
  24. int bins = 256;
  25. double max_val; //直方图的最大值
  26. int scale = 2; //直方图的宽度
  27. minMaxLoc(hist, 0, &max_val, 0, 0); //计算直方图最大值
  28. Mat hist_img = Mat::zeros(hist_height, bins*scale, CV_8UC3); //创建一个直方图图像并初始化为0
  29. for ( int i = 0; i<bins; i++)
  30. {
  31. float bin_val = hist.at< float>(i); // 第i灰度级上的数
  32. int intensity = cvRound(bin_val*hist_height / max_val); //要绘制的高度
  33. //填充第i灰度级的数据
  34. rectangle(hist_img, Point(i*scale, hist_height - 1),
  35. Point((i + 1)*scale - 1, hist_height - intensity),
  36. CV_RGB( 255, 255, 255));
  37. }
  38. imshow(pTitle, hist_img);
  39. }
  40. void one_channel_hist_specify(Mat input_img, Mat dst_img, Mat &output_img)//单通道
  41. {
  42. int i,j;
  43. //计算输入,规定图像的直方图
  44. MatND input_hist, dst_hist;
  45. Cal_Hist(input_img, input_hist);
  46. Cal_Hist(dst_img, dst_hist);
  47. //计算概率直方图
  48. MatND input_p_hist, dst_p_hist;
  49. input_p_hist = MatND::zeros(input_hist.size[ 0], input_hist.size[ 1], CV_32FC1); //原始概率直方图
  50. dst_p_hist = MatND::zeros(dst_hist.size[ 0], dst_hist.size[ 1], CV_32FC1); //规定概率直方图
  51. float input_totalnum = 0;
  52. float dst_totalnum = 0;
  53. for (i = 0; i < input_hist.rows; i++)
  54. input_totalnum += input_hist.at< float>(i);
  55. for (i = 0; i < dst_hist.rows; i++)
  56. dst_totalnum += dst_hist.at< float>(i);
  57. for (i = 0; i < input_hist.rows; i++)
  58. input_p_hist.at< float>(i) = input_hist.at< float>(i) / input_totalnum;
  59. for (i = 0; i < dst_hist.rows; i++)
  60. dst_p_hist.at< float>(i) = dst_hist.at< float>(i) / dst_totalnum;
  61. //计算累计直方图
  62. MatND input_c_hist, dst_c_hist;
  63. input_c_hist = MatND::zeros(input_hist.size[ 0], input_hist.size[ 1], CV_32FC1); //原始累计直方图
  64. dst_c_hist = MatND::zeros(dst_hist.size[ 0], dst_hist.size[ 1], CV_32FC1); //规定累计直方图
  65. float input_accum_p = 0;
  66. float dst_accum_p = 0;
  67. for (i = 0; i < input_hist.rows; i++)
  68. {
  69. input_accum_p += input_p_hist.at< float>(i);
  70. input_c_hist.at< float>(i) = input_accum_p;
  71. }
  72. for (i = 0; i < dst_hist.rows; i++)
  73. {
  74. dst_accum_p += dst_p_hist.at< float>(i);
  75. dst_c_hist.at< float>(i) = dst_accum_p;
  76. }
  77. //计算单映射规则
  78. MatND SML = MatND::zeros(input_hist.size[ 0], input_hist.size[ 1], CV_32FC1); //SML单映射规则
  79. for (i = 0; i < input_c_hist.rows; i++)
  80. {
  81. int minind = 0;
  82. float minval = 1;
  83. for (j = 0; j < dst_c_hist.rows; j++)
  84. {
  85. float abssub = abs(input_c_hist.at< float>(i)-dst_c_hist.at< float>(j));
  86. if (abssub < minval)
  87. {
  88. minval = abssub;
  89. minind = j;
  90. }
  91. }
  92. SML.at< float>(i) = minind;
  93. }
  94. //计算输出图像
  95. Mat outimg = Mat::zeros(input_img.size[ 0], input_img.size[ 1], CV_8U);
  96. for (i = 0; i < input_img.rows; i++)
  97. {
  98. for (j = 0; j < input_img.cols; j++)
  99. {
  100. outimg.at<uchar>(i, j) = SML.at< float>(input_img.at<uchar>(i, j));
  101. }
  102. }
  103. outimg.copyTo(output_img);
  104. //计算输出图像直方图
  105. //MatND output_hist;
  106. //Cal_Hist(output_img, output_hist);
  107. //DrawGrayHist("input_hist", input_hist);
  108. //DrawGrayHist("dst_hist", dst_hist);
  109. //DrawGrayHist("output_hist", output_hist);
  110. }
  111. void three_channel_hist_specify(Mat input_img, Mat dst_img, Mat &output_img)//三通道
  112. {
  113. //Mat src = imread("path", 1); //读入目标图像
  114. Mat out_img(input_img.rows, input_img.cols, CV_8UC3); //用来存储目的图片的矩阵
  115. //Mat数组来存车分离后的三个通道,每个通道都初始化为0;
  116. Mat input_planes[] = { Mat::zeros(input_img.size(), CV_8UC1), Mat::zeros(input_img.size(), CV_8UC1), Mat::zeros(input_img.size(), CV_8UC1) };
  117. Mat dst_planes[] = { Mat::zeros(dst_img.size(), CV_8UC1), Mat::zeros(dst_img.size(), CV_8UC1), Mat::zeros(dst_img.size(), CV_8UC1) };
  118. //多通道分成3个单通道,BGR
  119. split(input_img, input_planes);
  120. split(dst_img, dst_planes);
  121. Mat B_output_img, G_output_img, R_output_img;
  122. one_channel_hist_specify(input_planes[ 0], dst_planes[ 0], B_output_img);
  123. one_channel_hist_specify(input_planes[ 1], dst_planes[ 1], G_output_img);
  124. one_channel_hist_specify(input_planes[ 2], dst_planes[ 2], R_output_img);
  125. Mat output_planes[ 3];
  126. output_planes[ 0] = B_output_img;
  127. output_planes[ 1] = G_output_img;
  128. output_planes[ 2] = R_output_img;
  129. merge(output_planes, 3, out_img); //通道合并
  130. out_img.copyTo(output_img);
  131. }
  132. int main()
  133. {
  134. Mat src, gray, src2, gray2;
  135. //src=imread("D://input//buti.jpg");
  136. src = imread( "F:\\大海.jpg");
  137. cvtColor(src, gray, CV_RGB2GRAY); //转换成灰度图
  138. src2 = imread( "F:\\沙漠.jpg");
  139. cvtColor(src2, gray2, CV_RGB2GRAY); //转换成灰度图
  140. MatND hist2;
  141. imshow( "Source", src);
  142. //imshow( "Gray Histogram", hist_img );
  143. imshow( "Source2", src2);
  144. Mat output_img;
  145. three_channel_hist_specify(src, src2, output_img);
  146. imshow( "5", output_img);
  147. //DrawGrayHist("2", hist2);
  148. waitKey();
  149. return 0;
  150. }

原图:

规定图:

转化结果:



        </div>

猜你喜欢

转载自blog.csdn.net/liufanghuangdi/article/details/80903722