直方图规范化的opencv的实现

来源:互联网 发布:h3c路由配置端口ip网关 编辑:程序博客网 时间:2024/06/05 18:58

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

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


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

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

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

#include <opencv2/core/core.hpp>  #include <opencv2/imgproc/imgproc.hpp>  #include <opencv2/highgui/highgui.hpp>  #include <iostream>  using namespace std;using namespace cv;bool Cal_Hist(Mat Gray_img, MatND &hist){int bins = 256;int hist_size[] = { bins };float range[] = { 0, 256 };const float* ranges[] = { range };int channels[] = { 0 };//计算直方图  calcHist(&Gray_img, 1, channels, Mat(), // do not use mask    hist, 1, hist_size, ranges,true, // the histogram is uniform    false);if (hist.data == 0) return false;return true;}void DrawGrayHist(const char* pTitle, MatND& hist){int hist_height = 256;int bins = 256;double max_val;  //直方图的最大值  int scale = 2;   //直方图的宽度  minMaxLoc(hist, 0, &max_val, 0, 0); //计算直方图最大值  Mat hist_img = Mat::zeros(hist_height, bins*scale, CV_8UC3); //创建一个直方图图像并初始化为0   for (int i = 0; i<bins; i++){float bin_val = hist.at<float>(i); // 第i灰度级上的数      int intensity = cvRound(bin_val*hist_height / max_val);  //要绘制的高度    //填充第i灰度级的数据  rectangle(hist_img, Point(i*scale, hist_height - 1),Point((i + 1)*scale - 1, hist_height - intensity),CV_RGB(255, 255, 255));}imshow(pTitle, hist_img);}void one_channel_hist_specify(Mat input_img, Mat dst_img, Mat &output_img)//单通道{int i,j; //计算输入,规定图像的直方图MatND input_hist, dst_hist;Cal_Hist(input_img, input_hist);Cal_Hist(dst_img, dst_hist);//计算概率直方图MatND input_p_hist, dst_p_hist;input_p_hist = MatND::zeros(input_hist.size[0], input_hist.size[1], CV_32FC1);//原始概率直方图dst_p_hist = MatND::zeros(dst_hist.size[0], dst_hist.size[1], CV_32FC1);//规定概率直方图float input_totalnum = 0;float dst_totalnum = 0;for (i = 0; i < input_hist.rows; i++)input_totalnum += input_hist.at<float>(i);for (i = 0; i < dst_hist.rows; i++)dst_totalnum += dst_hist.at<float>(i);for (i = 0; i < input_hist.rows; i++)input_p_hist.at<float>(i) = input_hist.at<float>(i) / input_totalnum;for (i = 0; i < dst_hist.rows; i++)dst_p_hist.at<float>(i) = dst_hist.at<float>(i) / dst_totalnum;//计算累计直方图MatND input_c_hist, dst_c_hist;input_c_hist = MatND::zeros(input_hist.size[0], input_hist.size[1], CV_32FC1);//原始累计直方图dst_c_hist = MatND::zeros(dst_hist.size[0], dst_hist.size[1], CV_32FC1);//规定累计直方图float input_accum_p = 0;float dst_accum_p = 0;for (i = 0; i < input_hist.rows; i++){input_accum_p += input_p_hist.at<float>(i);input_c_hist.at<float>(i) = input_accum_p;}for (i = 0; i < dst_hist.rows; i++){dst_accum_p += dst_p_hist.at<float>(i);dst_c_hist.at<float>(i) = dst_accum_p;}//计算单映射规则MatND SML = MatND::zeros(input_hist.size[0], input_hist.size[1], CV_32FC1);//SML单映射规则for (i = 0; i < input_c_hist.rows; i++){int minind = 0;float minval = 1;for (j = 0; j < dst_c_hist.rows; j++){float abssub = abs(input_c_hist.at<float>(i)-dst_c_hist.at<float>(j));if (abssub < minval){minval = abssub;minind = j;}}SML.at<float>(i) = minind;}//计算输出图像Mat outimg = Mat::zeros(input_img.size[0], input_img.size[1], CV_8U);for (i = 0; i < input_img.rows; i++){for (j = 0; j < input_img.cols; j++){outimg.at<uchar>(i, j) = SML.at<float>(input_img.at<uchar>(i, j));}}outimg.copyTo(output_img);//计算输出图像直方图//MatND output_hist;//Cal_Hist(output_img, output_hist);//DrawGrayHist("input_hist", input_hist);//DrawGrayHist("dst_hist", dst_hist);//DrawGrayHist("output_hist", output_hist);}void three_channel_hist_specify(Mat input_img, Mat dst_img, Mat &output_img)//三通道{//Mat src = imread("path", 1);  //读入目标图像  Mat out_img(input_img.rows, input_img.cols, CV_8UC3); //用来存储目的图片的矩阵  //Mat数组来存车分离后的三个通道,每个通道都初始化为0;  Mat input_planes[] = { Mat::zeros(input_img.size(), CV_8UC1), Mat::zeros(input_img.size(), CV_8UC1), Mat::zeros(input_img.size(), CV_8UC1) };Mat dst_planes[] = { Mat::zeros(dst_img.size(), CV_8UC1), Mat::zeros(dst_img.size(), CV_8UC1), Mat::zeros(dst_img.size(), CV_8UC1) };//多通道分成3个单通道,BGRsplit(input_img, input_planes);split(dst_img, dst_planes);Mat B_output_img, G_output_img, R_output_img;one_channel_hist_specify(input_planes[0], dst_planes[0], B_output_img);one_channel_hist_specify(input_planes[1], dst_planes[1], G_output_img);one_channel_hist_specify(input_planes[2], dst_planes[2], R_output_img);Mat output_planes[3];output_planes[0] = B_output_img;output_planes[1] = G_output_img;output_planes[2] = R_output_img;merge(output_planes,3, out_img);  //通道合并out_img.copyTo(output_img);}int main(){Mat src, gray, src2, gray2;//src=imread("D://input//buti.jpg");    src = imread("F:\\大海.jpg");cvtColor(src, gray, CV_RGB2GRAY);  //转换成灰度图  src2 = imread("F:\\沙漠.jpg");cvtColor(src2, gray2, CV_RGB2GRAY);  //转换成灰度图  MatND hist2;imshow("Source", src);//imshow( "Gray Histogram", hist_img );    imshow("Source2", src2);Mat output_img;three_channel_hist_specify(src, src2, output_img);imshow("5", output_img);//DrawGrayHist("2", hist2);waitKey();return 0;}

原图:

规定图:

转化结果:



2 0