AWB图像增强算法 Opencv实现

/*
Automatic white balance
直方图法,去掉两端高亮度和低亮度的像素点(1%)后,将剩余像素再归一化到原始区间[min_pre, max_pre]
t' = (t - min_cur) / (max_cur - min_cur) * (max_pre - min_pre)

若BGR三个通道分别去掉首尾1%的像素后,再分别归一化到[min_pre, max_pre],颜色会出现问题
因为三通道去掉首尾后保留的像素区间不一样
比如对两通道边界处理了丢弃了255,而对另一通道没有处理,则只剩下该通道的颜色了

故对BGR三通道所有的值一起去掉首尾1%,用同区间处理BGR三通道
*/
// 图像预处理, 确定min_pre, max_pre, min_cur, max_cur
void image_process(Mat img, float s, int histSize, vector<float>& a)
{
	vector<Mat> channels;
	split(img, channels);

	Mat A1, A2;
	vconcat(channels[0], channels[1], A1);
	vconcat(A1, channels[2], A2);

	Mat hist;
	float range[] = { 0,256 };
	const float *histRanges = { range };
	float interval = 256.0f / histSize;
	calcHist(&A2, 1, 0, Mat(), hist, 1, &histSize, &histRanges, true, false);

	// cout << hist.type() << endl;				// CV_32F
	int image_size = A2.rows * A2.cols;
	vector<float> Hist;
	float sum = 0.0f;
	for (int i = 0; i < hist.rows; ++i)			// 直方图区间的累计和
	{
		sum += hist.at<float>(i);
		Hist.push_back(sum / image_size);
	}

	double min_pre_value, max_pre_value;
	minMaxIdx(A2, &min_pre_value, &max_pre_value);

	int lmin = 0;
	int lmax = histSize - 1;
	while (lmin < histSize)						// 去除最小的s范围内的元素
	{
		if (Hist[lmin] >= s)
		{
			break;
		}
		lmin += 1;
	}
	while (lmax > 0)							// 去除最大的s范围内的元素
	{
		if (Hist[lmax] <= (1 - s))
		{
			break;
		}
		lmax -= 1;
	}

	float min_cur_value, max_cur_value;
	min_cur_value = lmin * interval;
	max_cur_value = lmax * interval;

	a = { min_cur_value, max_cur_value, (float)min_pre_value, (float)max_pre_value };
}

// 按公式t' = (t - min_cur) / (max_cur - min_cur) * (max_pre - min_pre)修改像素值
void awb(Mat& src, Mat& dst, vector<float>& a)
{
	dst = src.clone();
	for (int i = 0; i < dst.rows; ++i)
	{
		for (int j = 0; j < dst.cols; ++j)
		{
			for (int k = 0; k < 3; k++)
			{
				if (dst.at<Vec3b>(i, j)[k] >= (int)round(a[0]) && dst.at<Vec3b>(i, j)[k] <= (int)round(a[1]))
				{
					dst.at<Vec3b>(i, j)[k] = (int)round((dst.at<Vec3b>(i, j)[k] - a[0]) * (a[3] - a[2]) / (a[1] - a[0]) + a[2]);
				}
				else if (dst.at<Vec3b>(i, j)[k] < (int)round(a[0]))
				{
					dst.at<Vec3b>(i, j)[k] = (int)round(a[2]);
				}
				else
				{
					dst.at<Vec3b>(i, j)[k] = (int)round(a[3]);
				}
			}
		}
	}
}
int main()
{
	Mat srcImg = imread("pic.jpg");
	namedWindow("srcImg", CV_WINDOW_NORMAL);
	imshow("srcImg", srcImg);

	vector<float> a;
    Mat awbImg;
	image_process(srcImg, 0.01f, 2000, a);
	awb(srcImg, awbImg, a);
	namedWindow("awbImg", CV_WINDOW_NORMAL);
	imshow("awbImg", awbImg);

	waitKey(0);
	return 0;
}

 实验结果:

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值