opencv 图像去雾的C++实现

去雾原理原理是根据何凯明博士的《Single Image Haze Removal Using Dark Channel Prior》这篇文章,介绍见https://www.cnblogs.com/Imageshop/p/3281703.html。及Python代码见:OpenCV—Python 暗通道图像去雾算法_opencv 暗通道 函数-CSDN博客

本文主要介绍C++实现,工程文件见:https://download.csdn.net/download/qq_34902877/12017480

1、求暗通道

       窗口的大小size,这个对结果来说是个关键的参数,窗口越大,其包含暗通道的概率越大,暗通道也就越黑,去雾的效果越不明显,一般窗口大小在11-51之间,即半径在5-25之间。

Mat DarkChannel(Mat srcImg, int size)
{
	vector<Mat> chanels;
	split(srcImg, chanels);

	//求RGB三通道中的最小像像素值
	Mat minChannel = (cv::min)((cv::min)(chanels[0], chanels[1]), chanels[2]);
	Mat kernel = getStructuringElement(MORPH_RECT, Size(size, size));

	Mat dark(minChannel.rows, minChannel.cols, CV_32FC1);
	erode(minChannel, dark, kernel);	//图像腐蚀
	return dark;
}

2、求全球大气光值A

void AtmLight(Mat src, Mat dark, float outA[3])
{
	int row = src.rows;
	int col = src.cols;
	int imgSize = row*col;

	//将暗图像和原图转为列向量
	vector<float> darkVector = dark.reshape(1, imgSize);
	Mat srcVector = src.reshape(3, imgSize);

	//按照亮度的大小取前0.1%的像素(亮度高)
	int numpx = int(max(floor(imgSize / 1000), 1.0));
	vector<int> indices = argsort(darkVector);
	vector<int> dstIndices(indices.begin() + (imgSize - numpx), indices.end());

	for (int i = 0; i < numpx; ++i)
	{
		outA[0] += srcVector.at<Vec3f>(dstIndices[i], 0)[0];
		outA[1] += srcVector.at<Vec3f>(dstIndices[i], 0)[1];
		outA[2] += srcVector.at<Vec3f>(dstIndices[i], 0)[2];
	}
	outA[0] /= numpx;
	outA[1] /= numpx;
	outA[2] /= numpx;
}

3、计算计算透射率预估值

 中的omega具有着明显的意义,其值越小,去雾效果越不明显

Mat TransmissionEstimate(Mat src, float outA[3], int size, float omega)
{
	Mat imgA = Mat::zeros(src.rows, src.cols, CV_32FC3);

	vector<Mat> chanels;
	split(src, chanels);
	for (int i = 0; i < 3; ++i)
	{
		chanels[i] = chanels[i] / outA[i];
	}

	merge(chanels, imgA);
	Mat transmission = 1 - omega*DarkChannel(imgA, size);	//计算透射率预估值
	return transmission;
}

4、导向滤波

Mat Guidedfilter(Mat src, Mat te, int r, float eps)
{
	Mat meanI, meanT, meanIT, meanII, meanA, meanB;
	boxFilter(src, meanI, CV_32F, Size(r, r));
	boxFilter(te, meanT, CV_32F, Size(r, r));
	boxFilter(src.mul(te), meanIT, CV_32F, Size(r, r));
	Mat covIT = meanIT - meanI.mul(meanT);

	boxFilter(src.mul(src), meanII, CV_32F, Size(r, r));
	Mat varI = meanII - meanI.mul(meanI);

	Mat a = covIT / (varI + eps);
	Mat b = meanT - a.mul(meanI);
	boxFilter(a, meanA, CV_32F, Size(r, r));
	boxFilter(b, meanB, CV_32F, Size(r, r));

	Mat t = meanA.mul(src) + meanB;

	return t;
}

5、通过导向滤波计算透射率

Mat TransmissionRefine(Mat src, Mat te)
{
	Mat gray;
	cvtColor(src, gray, CV_BGR2GRAY);
	gray.convertTo(gray, CV_32F);
	gray /= 255;

	int r = 60;
	float eps = 0.0001;
	Mat t = Guidedfilter(gray, te, r, eps);
	return t;
}

6、图像去雾

Mat Defogging(Mat src, Mat t, float outA[3], float tx)
{
	Mat dst = Mat::zeros(src.rows, src.cols, CV_32FC3);
	t = (cv::max)(t, tx);				//设置阈值当投射图t 的值很小时,会导致图像整体向白场过度

	vector<Mat> chanels;
	split(src, chanels);
	for (int i = 0; i < 3; ++i)
	{
		chanels[i] = (chanels[i] - outA[i]) / t + outA[i];
	}
	merge(chanels, dst);

	dst *= 255;				//归一化还原
	return dst;
}

结果展示:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值