图像颜色增强算法Opencv

算法来源于GIMP中的Color-enhance插件,主要思路就是对HSV空间的V值进行重新量化。其代码是开源的,但用起来不太方便,所以我用Opencv重新改写了一下。

一、算法主要步骤:

1.图像转换到CMY空间,每个像素点(三通道,包含C、M、Y三个值)各减去最小值,即C -=min(C,M,Y),M -=min(C,M,Y),Y -=min(C,M,Y)。

2.1中得到的图像转换到HSV空间。

3.计算V的极大极小值,重新量化V值:newPixel = oldPixel / 255- vMin) / (vMax - vMin)。

4.按原步骤,将图像转换回去,得到颜色增强的图像。

二、代码详解

环境:win10 x64,vs2013+OpenCV2.4.13

1.图像转换到CMY空间,每个像素点(三通道,包含C、M、Y三个值)各减去最小值

	vector BGR;
	split(img, BGR);
	
	BGR[0] = 255 - BGR[0];
	BGR[1] = 255 - BGR[1];
	BGR[2] = 255 - BGR[2];

	Mat CMY(img.size(), CV_8UC3);
	merge(BGR, CMY);
	Mat minMat(img.size(), CV_8UC1);

	for (int i = 0; i < height; i++)
	{
		Vec3b *pImg = CMY.ptr(i);
		uchar *pMin = minMat.ptr(i);

		for (int j = 0; j < width; j++)
		{
			min = pImg[j][0];
			if (pImg[j][1] < min) min = pImg[j][1];
			if (pImg[j][2] < min) min = pImg[j][2];
			pMin[j] = min;
			for (int k = 0; k < 3; k++)
			{
				pImg[j][k] -= min;

			}
		}
	}

2.计算V的极大极小值。

void find_vhi_vlo(const Mat &img, double &vhi, double &vlo)
{
	int width = img.cols;
	int height = img.rows;

	uchar min;

	vector BGR;
	split(img, BGR);
	//conver to CMY
	BGR[0] = 255 - BGR[0];
	BGR[1] = 255 - BGR[1];
	BGR[2] = 255 - BGR[2];

	Mat CMY(img.size(), CV_8UC3);
	merge(BGR, CMY);

	for (int i = 0; i < height; i++)
	{
		Vec3b *pImg = CMY.ptr(i);
		for (int j = 0; j < width; j++)
		{
			min = pImg[j][0];
			if (pImg[j][1] < min) min = pImg[j][1];
			if (pImg[j][2] < min) min = pImg[j][2];
			for (int k = 0; k < 3; k++)
			{
				pImg[j][k] -= min;


			}
		}
	}
	Mat HSV = Mat(CMY.size(), CV_8UC3);
	cvtColor(CMY, HSV, COLOR_BGR2HSV);
	vector vHSV;
	split(HSV, vHSV);

	////find Vmin and Vmax

	double vMin = 1.0;
	double vMax = .0;
	for (int i = 0; i < height; i++)
	{
		uchar *pImg = vHSV[2].ptr(i);
		for (int j = 0; j < width; j++)
		{
			double v = (double)pImg[j] / 255.0;
			if (v > vMax)	vMax = v;
			if (v < vMin)	vMin = v;
		}
	}
	vhi = vMax;
	vlo = vMin;
}

3.重新量化V值:newPixel = oldPixel / 255- vMin) / (vMax - vMin)。

void quantizing_v(Mat &img, double vMax, double vMin)
{
	if (vMax == vMin)	return;
	if (img.channels() != 1)	return;

	int width = img.cols;
	int height = img.rows;

	
	for (int i = 0; i < height; i++)
	{
		uchar *pImg = img.ptr(i);
		for (int j = 0; j < width; j++)
		{
			double newPixel = ((double)pImg[j] / vdelta - vMin) / (vMax - vMin);
			int tmp = int(newPixel * 255);
			if (tmp >255)
				pImg[j] = 255;
			else if (tmp < 0)
				pImg[j] = 0;
			else
				pImg[j] = (uchar)tmp;
		}
	}
}


4.按原步骤,将图像转换回去,得到颜色增强的图像。

	cvtColor(hsv, dst, COLOR_HSV2BGR);

	for (int i = 0; i < height; i++)
	{
		Vec3b *pDst = dst.ptr(i);
		uchar *pMin = minMat.ptr(i);

		for (int j = 0; j < width; j++)
		{
			for (int k = 0; k<3; k++)
			{
				int tmp = pDst[j][k] + pMin[j];
				if (tmp > 255)
					pDst[j][k] = 0;
				else
					pDst[j][k] = 255 - tmp;
			}

		}
	}

增强效果

图像颜色增强算法Opencv_第1张图片图像颜色增强算法Opencv_第2张图片图像颜色增强算法Opencv_第3张图片

图像颜色增强算法Opencv_第4张图片

图像颜色增强算法Opencv_第5张图片

图像颜色增强算法Opencv_第6张图片


四、不足

当然,这个算法比较简单,当图像亮度极大值比较小时,容易出现严重失真。并且,因为是全局处理的,当处理人像时,人的肤色部分容易出现过饱和现象。

图像颜色增强算法Opencv_第7张图片

图像颜色增强算法Opencv_第8张图片

附自己写的工程,结构比较乱,勉强能用。

测试工程

、改进

如果采用以上算法,对大像素图片的处理比较耗时消耗Cpu,幸好opencv提供了GPU的加速功能,利用OpenCV+Cuda,可以很好的实现加速功能,降低Cpu消耗。


自己写的供参考

你可能感兴趣的:(Opencv)