基于动态阈值的白平衡算法 照片校色

话不多说,原理见上一篇博客,结果耶很好,直接贴代码:


/*这个是基于动态阈值的自动白平衡算法做的照片颜色校正的程序*/
/*Automatic White Balance Method*/
/*输入包含照片名字的txt文本,输出加前缀的较色后的照片*/
/*时间:2015.8.24*/
#include <opencv2/core/core.hpp>  
#include <opencv2/highgui/highgui.hpp>  
#include <opencv2/face.hpp>
#include <opencv2/xphoto/white_balance.hpp>
#include <opencv2/xphoto.hpp>
#include <opencv2/imgproc/imgproc.hpp>  
#include <iostream>  
#include <vector>  
using namespace std;
using namespace cv;
double baidianave(Mat frame,int n)
{  
	int a[256];
	for (int i=0;i<256;i++)
	{
		a[i]=0;
	}
	double sum=0;
	double ave;
	for (int i=0;i<n;i++)
	{
		int d=frame.at<double>(0,i);
		a[d]++;
	}
	int n0=255;
	for (int k=255;k>0;k--)
	{
		sum+=a[k];
		if (sum>frame.rows*frame.cols/10)
		{
			break;
		}
		n0--;
	}
	sum=0;
	for (int i=n0;i<256;i++)
	{
		sum+=a[i]*i;
	}
	ave=sum/(frame.rows*frame.cols/10);
	return ave;
}
double baidianave(Mat frame)
{ 
	int a[256];
//cvZero(a);
	for (int i=0;i<256;i++)
	{
		a[i]=0;
	}
	double sum=0;
	double ave;
	for (int i=0;i<frame.rows;i++)
	{
		for (int j=0;j<frame.cols;j++)
		{
			int d=(int)frame.at<uchar>(i,j);
			a[d]++;
		}
	}

	int n0=255;
	for (int k=255;k>0;k--)
	{
		sum+=a[k];
		if (sum>frame.rows*frame.cols/10)
		{
			break;
		}
		n0--;
	}
	sum=0;
	for (int i=n0;i<256;i++)
	{
		sum+=a[i]*i;
	}
	ave=sum/(frame.rows*frame.cols/10);
	return ave;

}


int main(int argc, char* argv[])
{
	if (2 != argc) 
	{
	cout << "Please enter the image list!" <<endl;
	return -1;
	}
	vector<string>  file_names;
	FILE *file_list =  fopen(argv[1],"r");
	char buf[255];
	memset(&buf,0,sizeof(buf));

	while(fgets(buf,255,file_list))
	{
	if(buf[strlen(buf)-1] == '\n') 
	    buf[strlen(buf)-1] = '\0';
	file_names.push_back(string(buf));

	}

	fclose(file_list);
	int count = file_names.size();
	for(int  i=0; i<count; i++)
	{
		string img_nm = file_names[i];
		string img_mask = "c2" + img_nm;
		int pos = img_nm.rfind('.');
		string img_fmt = img_nm.substr(pos+1);
		if("jpg" != img_fmt)
		{
		  cout << "Unknown format: " << img_fmt << endl;
		  continue;
		}
		Mat frame= imread(img_nm,1);
		// cout<<frame.rows<<"  "<<frame.cols<<endl;
		// cvShowImage("处理前图像",frame);
		int heightyiban=frame.rows;
		int widthyiban=frame.cols;
		double Mb,Db;//图像分成四部分,每部分Cb的均值和均方差
		double Mr,Dr;//Cr的均值和均方差	
		Mat imageYCrCb =  Mat::zeros(frame.size(), CV_8UC3);
		Mat imageCb = Mat::zeros(frame.size(), CV_8UC1);
		Mat imageCr = Mat::zeros(frame.size(), CV_8UC1);
		Mat imageY = Mat::zeros(frame.size(), CV_8UC1);
		cvtColor(frame,imageYCrCb,CV_BGR2YCrCb); 

		std::vector<cv::Mat>ybr(imageYCrCb.channels());
		split(imageYCrCb,ybr);

		Mat imageb=Mat::zeros(frame.size(), CV_8UC1);
		Mat imagec=Mat::zeros(frame.size(), CV_8UC1);
		ybr[1].copyTo(imageb);
		ybr[2].copyTo(imagec);
		Mat  savg,sfangcha;//全局scalar 变量用来放平均值和方差
		meanStdDev(ybr[2],savg,sfangcha);
		Mb=savg.at<double>(0);
		Db=sfangcha.at<double>(0);//求出第一部分cb的均值和均方差
		meanStdDev(ybr[1],savg,sfangcha);
		Mr=savg.at<double>(0);
		// cout<<"Mr:  "<<Mr[0]<<endl;
		Dr=sfangcha.at<double>(0);;//求出第一部分cr的均值和均方差
		// cout<<"Dr:  "<<Dr[0]<<endl;
		double b,c;
		if (Mb<0)//计算mb+db*sign(mb)
		{ 
			b=Mb+Db*(-1);
		}
		else
			b=Mb+Db;

		
		if (Mr<0)//计算1.5*mr+dr*sign(mb);
		{
			c=1.5*Mr+Dr*(-1);
		}
		else
			c=1.5*Mr+Dr;
		double Ymax=baidianave(ybr[0]);
		//下面是对第一部分进行白点的选择
		Mat Bbaidian=Mat::zeros(1,6000000,CV_64FC1);
		Mat Gbaidian=Mat::zeros(1,6000000,CV_64FC1);
		Mat Rbaidian=Mat::zeros(1,6000000,CV_64FC1);

		//CvScalar s1;
		int n1=0;
		// cout<<"b[0]:   "<<b[0]<<"  c[0]:  "<<c[0]<<endl;
		for (int i=0;i<heightyiban;i++)
		{
			for (int j=0;j<widthyiban;j++)
			{
				if (((ybr[2].at<uchar>(i,j)-b)<(1.5*Db))&&((ybr[1].at<uchar>(i,j)-c)<(1.5*Dr)))
				{
		 	
					double d1=frame.at<Vec3b>(i,j)[0];
					Bbaidian.at<double>(0,n1)=d1;
					
					double d2=frame.at<Vec3b>(i,j)[1];
					Gbaidian.at<double>(0,n1)=d2;
				
					double d3=frame.at<Vec3b>(i,j)[2];
					Rbaidian.at<double>(0,n1)=d3;
					n1++;
				}
			}
		}

	
		double Bave1=baidianave(Bbaidian,n1);
		double Gave1=baidianave(Gbaidian,n1);
		double Rave1=baidianave(Rbaidian,n1);
		// cout<<"Bave1:  "<<Bave1<<"    Gave1:  "<<Gave1<<"      Rave1:   "<<Rave1<<"  Ymax:  "<<Ymax<<endl;
		double Bgain1=Ymax/(Bave1);
		double Ggain1=Ymax/(Gave1);
		double Rgain1=Ymax/(Rave1);
		// cout<<Bgain1<<"  "<<Ggain1<<"  "<<Rgain1<<endl; 
		for (int i=0;i<heightyiban;i++)
		{
			for (int j=0;j<widthyiban;j++)
			{
				int tb=Bgain1*frame.at<Vec3b>(i,j)[0];
				int tg=Ggain1*frame.at<Vec3b>(i,j)[1];
				int tr=Rgain1*frame.at<Vec3b>(i,j)[2];
				if (tb>255)
				{
					tb=255;
				}
				if (tg>255)
				{
					tg=255;
				}
				if (tr>255)
				{
					tr=255;
				}				
				frame.at<Vec3b>(i,j)[0]=tb;
				frame.at<Vec3b>(i,j)[1]=tg;
				frame.at<Vec3b>(i,j)[2]=tr;
			}
		}
		imwrite(img_mask.c_str(),frame);		
		cout<<"Finish!"<<endl;
	}
	
	return 0;
}


  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值