【图像处理】基于OpenCV底层实现的直方图匹配

image processing 系列:

  1. 【图像处理】图片旋转
  2. 【图像处理】高斯滤波、中值滤波、均值滤波

直方图匹配算法,又称直方图规定化。简单说,就是根据某函数、或者另外一张图片的引导,使得原图改变。

感觉解释的最好的是:http://www.360doc.com/content/13/1106/16/10724725_327179043.shtml

完整代码:github (里面同时包含OSTU / 大津算法、直方图均衡化等算法,还包括两种测试图片)。

因为我个人兴趣爱好(放P就是老师逼的。。。),不允许使用 OpenCV 封装好的直方图函数。根据实例讲解,了解了直方图匹配算法底层的操作(多说一句,这个例子可以是我见过最好的直方图匹配算法讲解,也是很难见的此算法的例子,必读)。

注:实例讲解中 0->3 的意义是,原图中灰度级为 0 的像素点全部转化为原图中的 3 灰度级。


上代码(其中,srcImg 是原图,dstImg 是需要匹配的图,flag 标记两者是 RGB  图还是灰度图):

cv::Mat ycMatchHist(cv::Mat srcImg, cv::Mat dstImg, int flag)
{
	// ****** 如果是 RGB 图片则转为灰度图片操作 ******
	Mat out(srcImg);
	if (flag == YC_RGB)
	{
		cvtColor(srcImg, out, CV_BGR2GRAY);
	}
	else if (flag == YC_GRAY)
	{
	}
	int grayLevel[colvl];
	for(int i=0; i<colvl; i++)	grayLevel[i] = i;

	int grayArr[colvl];
	int srcRow = srcImg.rows;
	int srcCol = srcImg.cols;
	int dstRow = dstImg.rows;
	int dstCol = dstImg.cols;
	float srcCdfArr[colvl]  = {0.f};
	float dstCdfArr[colvl]  = {0.f};
	float tmp;

	// *** 求解源图片的累积直方图(概率)分布 *** 
	memset(grayArr, 0, sizeof(grayArr));
	for(size_t nrow = 0; nrow < srcRow; nrow++)  
       for(size_t ncol = 0; ncol < srcCol; ncol++)
	   {
		   int tag = srcImg.at<uchar>(nrow, ncol);
		   grayArr[tag]++;
	   }

	tmp = 0;
	for(int i=0; i<colvl; i++)
	{
		tmp += grayArr[i];
		srcCdfArr[i] = tmp / (srcRow * srcCol);
		// std::cout<<srcCdfArr[i]<<std::endl;
	}

	// *** 求解目标图片的累积直方图(概率)分布 *** 
	memset(grayArr, 0, sizeof(grayArr));
	for(size_t nrow = 0; nrow < dstRow; nrow++)  
       for(size_t ncol = 0; ncol < dstCol; ncol++)
	   {
		   int tag = dstImg.at<uchar>(nrow, ncol);
		   grayArr[tag]++;
	   }

	tmp = 0;
	for(int i=0; i<colvl; i++)
	{
		tmp += grayArr[i];
		dstCdfArr[i] = tmp / (dstRow * dstCol);
	}

	// *** 直方图匹配算法 ***
	int histMap[colvl];
	int minTag;
	for(int i=0; i<colvl; i++)
	{
		float minMap = 10.f;
		for(int j=0; j<colvl; j++)
		{
			if (minMap > abs(srcCdfArr[i] - dstCdfArr[j]))
			{
				minMap = abs(srcCdfArr[i] - dstCdfArr[j]);
				minTag = j;
			}
		}
		histMap[i] = minTag;
	}

	for(size_t nrow = 0; nrow < out.rows; nrow++)  
       for(size_t ncol = 0; ncol < out.cols; ncol++)
	   {
		   int tag = out.at<uchar>(nrow, ncol);
		   out.at<uchar>(nrow, ncol) = histMap[tag];
	   }

	return out;
}

实验结果如下:

原图为【图像处理】基于OpenCV底层实现的直方图匹配_第1张图片

需要匹配的图是【图像处理】基于OpenCV底层实现的直方图匹配_第2张图片

最终输出的是图【图像处理】基于OpenCV底层实现的直方图匹配_第3张图片

匹配图片的灰度累积直方图为:【图像处理】基于OpenCV底层实现的直方图匹配_第4张图片

最终输出的灰度累积直方图为:【图像处理】基于OpenCV底层实现的直方图匹配_第5张图片

两者很接近了,证明匹配算法是可行的(当然如果我说错了,欢迎打脸,共同进步哈哈~)

你可能感兴趣的:(C++,实例,opencv,直方图,直方图匹配)