直方图规定化

直方图的应用很多,这里我提供一个直方图规定化的应用程序,是将原图匹配到目标图的直方图,然后看看原图,目标图,匹配后的结果图 三者对应的直方图的曲线是否符合要求

在这里插入图片描述
蓝线:原图直方图;绿线:目标图直方图;红线:匹配后的结果直方图
在这里插入图片描述
看代码:

#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <string>

using namespace cv;

bool histMatch_Value(Mat matSrc, Mat matDst, Mat &matRet);
int histogram_Matching();
Mat MyHistMatch(Mat &srcImage, Mat &TargetImage);
void drawHist(Mat a, Mat b, Mat c);

int main()
{
	histogram_Matching();

	return 0;
}

int histogram_Matching()
{
	Mat matSrc = imread("road.jpg"); // 源图像
	Mat matDst = imread("cj.jpg"); // 目标图像

	Mat srcBGR[3];
	Mat dstBGR[3];
	Mat retBGR[3];
	split(matSrc, srcBGR);
	split(matDst, dstBGR);
/*	/
		//方法一效果差点
	retBGR[0] = MyHistMatch(srcBGR[0], dstBGR[0]);
	retBGR[1] = MyHistMatch(srcBGR[1], dstBGR[1]);
	retBGR[2] = MyHistMatch(srcBGR[2], dstBGR[2]);

	/*/
	//方法二
	histMatch_Value(srcBGR[0], dstBGR[0], retBGR[0]);
	histMatch_Value(srcBGR[1], dstBGR[1], retBGR[1]);
	histMatch_Value(srcBGR[2], dstBGR[2], retBGR[2]);
	/	
	Mat matResult;
	merge(retBGR, 3, matResult);
	imshow("src", matSrc);
	imshow("dst", matDst);
	imshow("Ret", matResult);

	drawHist( matSrc,  matDst, matResult);

	cvWaitKey();
	return 0;
}

bool histMatch_Value(Mat matSrc, Mat matDst, Mat &matRet)
{
	if (matSrc.empty() || matDst.empty() || 1 != matSrc.channels() || 1 != matDst.channels())
		return false;
	int nHeight = matDst.rows;
	int nWidth = matDst.cols;
	int nDstPixNum = nHeight * nWidth;
	int nSrcPixNum = 0;

	int arraySrcNum[256] = { 0 };                // 源图像各灰度统计个数
	int arrayDstNum[256] = { 0 };                // 目标图像个灰度统计个数
	double arraySrcProbability[256] = { 0.0 };   // 源图像各个灰度概率
	double arrayDstProbability[256] = { 0.0 };   // 目标图像各个灰度概率
												 // 统计源图像
	for (int j = 0; j < nHeight; j++)
	{
		for (int i = 0; i < nWidth; i++)
		{
			arrayDstNum[matDst.at<uchar>(j, i)]++;
		}
	}
	// 统计目标图像
	nHeight = matSrc.rows;
	nWidth = matSrc.cols;
	nSrcPixNum = nHeight * nWidth;
	for (int j = 0; j < nHeight; j++)
	{
		for (int i = 0; i < nWidth; i++)
		{
			arraySrcNum[matSrc.at<uchar>(j, i)]++;
		}
	}
	// 计算概率
	for (int i = 0; i < 256; i++)
	{
		arraySrcProbability[i] = (double)(1.0 * arraySrcNum[i] / nSrcPixNum);
		arrayDstProbability[i] = (double)(1.0 * arrayDstNum[i] / nDstPixNum);
	}
	// 构建直方图均衡映射
	int L = 256;
	int arraySrcMap[256] = { 0 };
	int arrayDstMap[256] = { 0 };
	for (int i = 0; i < L; i++)
	{
		double dSrcTemp = 0.0;
		double dDstTemp = 0.0;
		for (int j = 0; j <= i; j++)
		{
			dSrcTemp += arraySrcProbability[j];
			dDstTemp += arrayDstProbability[j];
		}
		arraySrcMap[i] = (int)((L - 1) * dSrcTemp + 0.5);// 减去1,然后四舍五入
		arrayDstMap[i] = (int)((L - 1) * dDstTemp + 0.5);// 减去1,然后四舍五入
	}
	// 构建直方图匹配灰度映射
	int grayMatchMap[256] = { 0 };
	for (int i = 0; i < L; i++) // i表示源图像灰度值
	{
		int nValue = 0;    // 记录映射后的灰度值
		int nValue_1 = 0;  // 记录如果没有找到相应的灰度值时,最接近的灰度值
		int k = 0;
		int nTemp = arraySrcMap[i];
		for (int j = 0; j < L; j++) // j表示目标图像灰度值
		{
			// 因为在离散情况下,之前图均衡化函数已经不是严格单调的了,
			// 所以反函数可能出现一对多的情况,所以这里做个平均。
			if (nTemp == arrayDstMap[j])
			{
				nValue += j;
				k++;
			}
			if (nTemp < arrayDstMap[j])
			{
				nValue_1 = j;
				break;
			}
		}
		if (k == 0)// 离散情况下,反函数可能有些值找不到相对应的,这里去最接近的一个值
		{
			nValue = nValue_1;
			k = 1;
		}
		grayMatchMap[i] = nValue / k;
	}
	// 构建新图像
	matRet = Mat::zeros(nHeight, nWidth, CV_8UC1);
	for (int j = 0; j < nHeight; j++)
	{
		for (int i = 0; i < nWidth; i++)
		{
			matRet.at<uchar>(j, i) = grayMatchMap[matSrc.at<uchar>(j, i)];
		}
	}
	return true;
}


Mat MyHistMatch(Mat &srcImage, Mat &TargetImage)
{

	int nRows = srcImage.rows;
	int nCols = srcImage.cols;

	int nSrcSumPix[256];
	int nTargetSumPix[256];
	double nSrcProDis[256];
	double nTargetProDis[256];
	//int srcGrayLevel[256];
	int HistMatchMap[256];
	double nSrcSumProDis[256];
	double nTargetSumProDis[256];
	int EqualizeSrcSumPix[256];
	int EqualizeTargetSumPix[256];
	int matchFlag = 0;

	for (int i = 0; i < 256; i++)
	{
		nSrcSumPix[i] = 0;
		nTargetSumPix[i] = 0;
		nSrcProDis[i] = 0.0;
		nTargetProDis[i] = 0.0;
		//srcGrayLevel[i] = 0;
		HistMatchMap[i] = 0;
		nSrcSumProDis[i] = 0.0;
		nTargetSumProDis[i] = 0.0;
		EqualizeSrcSumPix[i] = 0;
		EqualizeTargetSumPix[i] = 0;
	}


	for (int i = 0; i < nRows; i++)
	{
		for (int j = 0; j < nCols; j++)
		{
			nSrcSumPix[(int)srcImage.at<uchar>(i, j)]++;
			nTargetSumPix[(int)TargetImage.at<uchar>(i, j)]++;
		}
	}


	for (int i = 0; i < 256; i++)
	{
		nSrcProDis[i] = (double)nSrcSumPix[i] / (nRows * nCols);
		nTargetProDis[i] = (double)nTargetSumPix[i] / (nRows * nCols);
	}


	nSrcSumProDis[0] = nSrcProDis[0];
	nTargetSumProDis[0] = nTargetProDis[0];


	for (int i = 1; i < 256; i++)
	{
		nSrcSumProDis[i] = nSrcSumProDis[i - 1] + nSrcProDis[i];
		nTargetSumProDis[i] = nTargetSumProDis[i - 1] + nTargetProDis[i];
	}


	for (int i = 0; i < 256; i++)
	{
		EqualizeSrcSumPix[i] = cvRound((double)nSrcSumProDis[i] * 255);
		EqualizeTargetSumPix[i] = cvRound((double)nTargetSumProDis[i] * 255);
	}



	for (int i = 0; i < 256; i++)
	{
		int minMatchPara = 20;
		for (int j = 0; j < 256; j++)
		{

			if (minMatchPara > abs(EqualizeSrcSumPix[i] - EqualizeTargetSumPix[j]))
			{
				minMatchPara = abs(EqualizeSrcSumPix[i] - EqualizeTargetSumPix[j]);
				matchFlag = j;
			}
		}
		HistMatchMap[i] = matchFlag;
	}



	Mat resultImage(nRows, nCols, srcImage.type());
	for (int i = 0; i < nRows; i++)
	{

		for (int j = 0; j < nCols; j++)
		{

			resultImage.at<uchar>(i, j) = HistMatchMap[(int)srcImage.at<uchar>(i, j)];
		}
	}
	return resultImage;
}

void drawHist(Mat a, Mat b, Mat c)
{
	Mat matSrc;
	Mat matDst; 
	Mat matResult;
	cvtColor(a, matSrc,COLOR_BGR2GRAY);
	cvtColor(b, matDst, COLOR_BGR2GRAY);
	cvtColor(c, matResult, COLOR_BGR2GRAY);
	imshow("Src1",matSrc);
	//imshow("Dst1", matDst);
	imshow("ret1", matResult);
	int Channels[] = { 0 };
	int nHistSize[] = { 256 };//256 points
	float range[] = { 0, 255 };
	const float* fHistRanges[] = { range };
	Mat histR, histG, histB;
	// 计算直方图
	calcHist(&matSrc, 1, Channels, Mat(), histB, 1, nHistSize, fHistRanges, true, false);
	calcHist(&matDst, 1, Channels , Mat(), histG, 1, nHistSize, fHistRanges, true, false);
	calcHist(&matResult, 1, Channels , Mat(), histR, 1, nHistSize, fHistRanges, true, false);

	// 创建直方图画布
	int nHistWidth = 640;
	int nHistHeight = 480;
	int nBinWidth = cvRound((double)nHistWidth / nHistSize[0]);//400/256=2
	Mat matHistImage(nHistHeight, nHistWidth, CV_8UC3, Scalar(255, 255, 255));
	// 直方图归一化
	normalize(histB, histB, 0.0, matHistImage.rows, NORM_MINMAX, -1, Mat());
	normalize(histG, histG, 0.0, matHistImage.rows, NORM_MINMAX, -1, Mat());
	normalize(histR, histR, 0.0, matHistImage.rows, NORM_MINMAX, -1, Mat());
	// 在直方图中画出直方图
	for (int i = 1; i < nHistSize[0]; i++)
	{
		line(matHistImage,
			Point(nBinWidth * (i - 1), nHistHeight - cvRound(histB.at<float>(i - 1))),
			Point(nBinWidth * (i), nHistHeight - cvRound(histB.at<float>(i))),
			Scalar(255, 0, 0),
			2,
			8,
			0);
		line(matHistImage,
			Point(nBinWidth * (i - 1), nHistHeight - cvRound(histG.at<float>(i - 1))),
			Point(nBinWidth * (i), nHistHeight - cvRound(histG.at<float>(i))),
			Scalar(0, 255, 0),
			2,
			8,
			0);
		line(matHistImage,
			Point(nBinWidth * (i - 1), nHistHeight - cvRound(histR.at<float>(i - 1))),
			Point(nBinWidth * (i), nHistHeight - cvRound(histR.at<float>(i))),
			Scalar(0, 0, 255),
			2,
			8,
			0);
	}
	// 显示直方图
	imshow("histogram", matHistImage);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值