直方图规范化的opencv的实现

    xiaoxiao2021-12-14  19

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

    数学原理在网上很多可以找到。这里说一下实现过程步骤和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个单通道,BGR split(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; }

    原图:

    规定图:

    转化结果:

    转载请注明原文地址: https://ju.6miu.com/read-969435.html

    最新回复(0)