Opencv直方图规定化(直方图匹配)

概念
在某些指定的情况下,需要将直方图映射为指定的分布形式。这就是直方图规定化。不同图像之间的像素数目可能不同,为了使两个图像直方图能够匹配,需要使用概率形式表示每个灰度值在图像像素中所占的比例。在理想状态下,经过直方图匹配操作后,图像直方图的分布形式应与目标分布一致。
上代码:

void drawHist(Mat &hist, int type, string name)  //归一化并绘制直方图函数
{
     
	int hist_w = 512;
	int hist_h = 400;
	int width = 2;
	Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3);

	/*double minVal, maxVal;
	Point minLoc, maxLoc;
	minMaxLoc(hist, &minVal, &maxVal, &minLoc, &maxLoc);
	double tt = 0;
	for (int r = 0; r < hist.rows; r++)
	{
		for (int c = 0; c < hist.cols; c++)
		{
			tt += hist.at(r,c);
		}
	}*/

	normalize(hist, hist, 1, 0, type, -1, Mat());

	//minMaxLoc(hist, &minVal, &maxVal, &minLoc, &maxLoc);

	for (int i = 1; i <= hist.rows; i++)
	{
     
		rectangle(histImage, Point(width*(i - 1), hist_h - 1),
			Point(width*i - 1, hist_h - cvRound(20 * hist_h*hist.at<float>(i - 1)) - 1),
			Scalar(255, 255, 255), -1);
	}
	imshow(name, histImage);
}
//主函数
int main()
{
     
	Mat img1 = imread("src.png");
	Mat img2 = imread("template.png");
	if (img1.empty() || img2.empty())
	{
     
		cout << "找不到图像!" << endl;
		return -1;
	}
	Mat hist1, hist2;
	//计算两张图像直方图
	const int channels[1] = {
      0 };
	float inRanges[2] = {
      0,255 };
	const float* ranges[1] = {
      inRanges };
	const int bins[1] = {
      256 };
	calcHist(&img1, 1, channels, Mat(), hist1, 1, bins, ranges);
	calcHist(&img2, 1, channels, Mat(), hist2, 1, bins, ranges);
	//归一化两张图像的直方图
	drawHist(hist1, NORM_L1, "hist1");
	drawHist(hist2, NORM_L1, "hist2");
	//计算两张图像直方图的累积概率
	float hist1_cdf[256] = {
      hist1.at<float>(0) };
	float hist2_cdf[256] = {
      hist2.at<float>(0) };
	for (int i = 1; i < 256; i++)
	{
     
		hist1_cdf[i] = hist1_cdf[i - 1] + hist1.at<float>(i);
		hist2_cdf[i] = hist2_cdf[i - 1] + hist2.at<float>(i);
	}
	//构建累积概率误差矩阵
	float diff_cdf[256][256];
	for (int i = 0; i < 256; i++)
	{
     
		for (int j = 0; j < 256; j++)
		{
     
			diff_cdf[i][j] = fabs(hist1_cdf[i] - hist2_cdf[j]);
		}
	}

	//生成LUT映射表
	Mat lut(1, 256, CV_8U);
	for (int i = 0; i < 256; i++)
	{
     
		// 查找源灰度级为i的映射灰度
		// 和i的累积概率差值最小的规定化灰度
		float min = diff_cdf[i][0];
		int index = 0;
		//寻找累积概率误差矩阵中每一行中的最小值
		for (int j = 1; j < 256; j++)
		{
     
			if (min > diff_cdf[i][j])
			{
     
				min = diff_cdf[i][j];
				index = j;
			}
		}
		lut.at<uchar>(i) = (uchar)index;
	}
	Mat result, hist3;
	LUT(img1, lut, result);
	imshow("待匹配img", img1);
	imshow("匹配的模板img", img2);
	imshow("直方图匹配(规定化)结果", result);
	calcHist(&result, 1, channels, Mat(), hist3, 1, bins, ranges);
	drawHist(hist3, NORM_L1, "hist3");  //绘制匹配后的图像直方图
	waitKey(0);
	return 0;
}

你可能感兴趣的:(OpenCV,opencv,计算机视觉,算法)