opencv图像处理初步(二):实现色彩还原—(白平衡)


 0、说明

目前很多摄像头特别是网络摄像头对色彩的处理情况存在色差,比如一个橙子(是黄色的),但是拍出来的效果会泛白,有点像梨子的颜色,因此要用到色彩校正。

一般色彩校正使用白平衡,白平衡一般又分为:灰世界完美反射、等,这里不做具体陈述。

此处提供了一种方法,总体原理为(对每个通道而言):

1)对偏暗和偏亮的颜色进行特定的处理:指定一个特定的像素值;

2)对其他像素值进行小幅度拉伸;

3)最后三个通道合并即为最终结果。

注意:偏暗和偏亮得界限是不对称的,可以同通过改变代码中的s实现。

具体计算方式可以看源码(c语言实现,非c++)。

1、效果

 

2、代码实现

2.1我的实现(调整参数s以符合自己效果)

/*
对偏暗和偏亮的的像素进行处理,对其他像素进行拉伸
偏暗和偏亮的判定可以通过调整下面的s进行调整,注意偏暗和偏亮是不对称的
*/
#include 
#include 

using namespace cv;
using namespace std;

void color_balance(IplImage *img)
{
	int histo[256] = { 0 };//直方图统计每个像素值的数目
	int num_of_pixels = img->width*img->height;
    //统计每个像素值的数目
	for (int y = 0; y < img->height; ++y)
	{
		uchar *data = (uchar*)(img->imageData + y*img->widthStep);//定义的大小和图像尺寸一致
		for (int x = 0; x < img->width; ++x)
		{
			histo[data[x]] += 1;
		}
	}

    //统计当前像素值和之前像素值的总数
	for (int i = 1; i < 256; ++i)
		histo[i] = histo[i] + histo[i - 1];

	double s = 0.0265;//此参数可以调整,最好在0.1以下(0= cvRound(num_of_pixels*(1 - s / 2)))
	{
		vmax = vmax - 1;
	}

	if (vmax < 255 - 1)
		vmax = vmax + 1;

    //处理图像中像素值大于vmin和小于vmax的像素,
    //即处理偏亮和偏暗的区域
	for (int y = 0; y < img->height; ++y)
	{

		uchar *data = (uchar*)(img->imageData + y*img->widthStep);
		for (int x = 0; x < img->width; ++x)
		{
			if (data[x] < vmin)
				data[x] = vmin;
			if (data[x] > vmax)
				data[x] = vmax;
		}
	}

    //对其他的像素进行处理(拉伸),其实可以合并到上一步,简化时间复杂度,这里分开只是为了让过程更清楚
	for (int y = 0; y < img->height; ++y)
	{

		uchar *data = (uchar*)(img->imageData + y*img->widthStep);
		for (int x = 0; x < img->width; ++x)
		{
			data[x] = cvRound((data[x] - vmin)*255.0 / (vmax - vmin));
		}
	}
}


int main()
{
	IplImage *srcImg = cvLoadImage("02.jpg");//读取图片
	IplImage *dstImg = cvCreateImage(cvGetSize(srcImg), 8, 3);
	IplImage *redCh = cvCreateImage(cvGetSize(srcImg), 8, 1);//R通道
	IplImage *greenCh = cvCreateImage(cvGetSize(srcImg), 8, 1);//G通道
	IplImage *blueCh = cvCreateImage(cvGetSize(srcImg), 8, 1);//B通道
	cvSplit(srcImg, blueCh, greenCh, redCh, NULL);//把原图拆分RGB通道
	color_balance(redCh);//对R通道进行色彩平衡
	color_balance(greenCh);//对G通道进行色彩平衡
	color_balance(blueCh);//对B通道进行色彩平衡
	cvMerge(blueCh, greenCh, redCh, NULL, dstImg);//合并操作后的通道,为最终结果
    
    //显示操作
	cvNamedWindow("src", CV_WINDOW_AUTOSIZE);
	cvShowImage("src", srcImg);

	cvNamedWindow("dst", CV_WINDOW_AUTOSIZE);
	cvShowImage("dst", dstImg);
	cvWaitKey(0);

	return 0;
}

2.2其他方法(灰世界—>这个代码对有些情况下效果不好) 

#include 
#include 
 
using namespace cv;
 
int main()
{
	Mat imageSource = imread("02.jpg");
	imshow("原始图像", imageSource);
	vector imageRGB;
 
	//RGB三通道分离
	split(imageSource, imageRGB);
 
	//求原始图像的RGB分量的均值
	double R, G, B;
	B = mean(imageRGB[0])[0];
	G = mean(imageRGB[1])[0];
	R = mean(imageRGB[2])[0];
 
	//需要调整的RGB分量的增益
	double KR, KG, KB;
	KB = (R + G + B) / (3 * B);
	KG = (R + G + B) / (3 * G);
	KR = (R + G + B) / (3 * R);
 
	//调整RGB三个通道各自的值
	imageRGB[0] = imageRGB[0] * KB;
	imageRGB[1] = imageRGB[1] * KG;
	imageRGB[2] = imageRGB[2] * KR;
 
	//RGB三通道图像合并
	merge(imageRGB, imageSource);
	imshow("白平衡调整后", imageSource);
	waitKey();
	return 0;
}