《基于单幅图像的快速去雾》论文C++实现

论文原文

清华大学写的文章:基于单幅图像的快速去雾算法,作者:刘倩,陈茂华,周东华。

算法过程

实际上有了这个算法流程就可以写出代码了,不过为了加深理解可以看下面的一些推导。

一些推导

我们知道去雾的步骤主要就是估计全局大气光值A和透射率t(x),具体可先看这篇文章:https://blog.csdn.net/just_sort/article/details/89634180 。因此,本文就是根据输入图像估计A和L(x),然后根据雾天退化模型求取去雾后的图像。

估计透射率t(x)

根据上面链接的文章可以知道 t ( x ) > = 1 H ( x ) A t(x)>=1-\frac{H(x)}{A} t(x)>=1AH(x)…(2),且论文使用了 L ( x ) L(x) L(x)来代替 A ( 1 t ( x ) ) A(1-t(x)) A(1t(x)),即: L ( x ) = A ( 1 t ( x ) ) L(x)=A(1-t(x)) L(x)=A(1t(x))…(1)。我们取H(x)三个通道的最小值并记为: M ( x ) = m i n c r , g , b ( H c ( x ) ) M(x)=min_{c\in r,g,b}(H^c(x)) M(x)=mincr,g,b(Hc(x)) …(3),所以公式2变换为 t ( x ) > = 1 M ( x ) A t(x)>=1-\frac{M(x)}{A} t(x)>=1AM(x)…(4),对公式(4)右边进行均值滤波 m e a d i a n s a ( 1 M ( x ) A ) = 1 m e d i a n s a ( M ( x ) ) A = 1 y Ω ( x ) M ( y ) A s a 2 meadian_{s_a}(1-\frac{M(x)}{A})=1-\frac{median_{s_a}(M(x))}{A}=1-\frac{\sum_{y\in\Omega(x)M(y)}}{As_a^2} meadiansa(1AM(x))=1Amediansa(M(x))=1Asa2yΩ(x)M(y)…(5)。其中 s a s_a sa代表均值滤波的窗口大小, Ω ( x ) \Omega(x) Ω(x)表示像素x的 s a × s a s_a\times s_a sa×sa的邻域。均值滤波后的结果可以反映 t ( x ) t(x) t(x)的大致趋势,但与真实的 t ( x ) t(x) t(x)还差一定的绝对值,于是,得出透射率的粗略估计值 t ( x ) = 1 M a v e ( x ) A + φ M a v e ( x ) A = 1 δ M a v e ( x ) A t(x)=1-\frac{M_{ave}(x)}{A}+\varphi\frac{M_{ave}(x)}{A}=1-\delta\frac{M_{ave}(x)}{A} t(x)=1AMave(x)+φAMave(x)=1δAMave(x)…(6)。其中 M a v e ( x ) = m e d i a n s a ( M ( x ) ) , δ = 1 φ , φ [ 0 , 1 ] M_{ave}(x)=median_{s_a}(M(x)),\delta=1-\varphi,\varphi\in[0,1] Mave(x)=mediansa(M(x)),δ=1φ,φ[0,1],因此 φ [ 0 , 1 ] \varphi\in[0,1] φ[0,1]。为了防止去雾后图像出现整体画面偏暗,这里根据图像的均值来调整 δ \delta δ,即 δ = ρ m a v e \delta=\rho m_{ave} δ=ρmave,其中 m a v e m_{ave} mave是M(x)中所有元素的均值, ρ \rho ρ是调节因子。因此可以得到透射率的计算公式 t ( x ) = m a x ( 1 m i n ( ρ m a v , 0.9 ) M a v e ( x ) A , 1 M ( x ) A ) t(x)=max(1-min(\rho m_{av}, 0.9)\frac{M_{ave}(x)}{A}, 1-\frac{M(x)}{A}) t(x)=max(1min(ρmav,0.9)AMave(x),1AM(x))…(7)。结合公式(1)推出: L ( x ) = m i n ( m i n ( ρ m a v , 0.9 ) M a v e ( x ) , M ( x ) ) L(x)=min(min(\rho m_{av}, 0.9)M_{ave}(x), M(x)) L(x)=min(min(ρmav,0.9)Mave(x),M(x))

估计全球大气光值

公式5中第一个等式的左侧的表达式取值范围为[0, 1],由此得出 A &gt; = m a x ( M a v e ( x ) ) A&gt;=max(M_{ave}(x)) A>=max(Mave(x)),一般情况下又存在 A &lt; = m a x ( m a x c r , g , b ( H c ( x ) ) ) A&lt;=max(max_{c\in r,g,b(H^c(x))}) A<=max(maxcr,g,b(Hc(x)))(KaiMing He的暗通道先验理论)。这样就初步确定了全局大气光的范围,为了能快速获取全局大气光,文章直接取两者的平均值作为全局大气光值,即是:
A = 1 / 2 ( m a x ( H ( x ) ) + m a x ( M a v e ( x ) ) ) A = 1/2(max(H(x))+max(M_{ave}(x))) A=1/2(max(H(x))+max(Mave(x)))…(9)。

代码实现

#include <opencv2/opencv.hpp>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace cv;
using namespace std;

int getMax(Mat src) {
	int row = src.rows;
	int col = src.cols;
	int temp = 0;
	for (int i = 0; i < row; i++) {
		for (int j = 0; j < col; j++) {
			temp = max((int)src.at<uchar>(i, j), temp);
		}
		if (temp == 255) return temp;
	}
	return temp;
}

Mat dehaze(Mat src) {
	double eps;
	int row = src.rows;
	int col = src.cols;
	Mat M = Mat::zeros(row, col, CV_8UC1);
	Mat M_max = Mat::zeros(row, col, CV_8UC1);
	Mat M_ave = Mat::zeros(row, col, CV_8UC1);
	Mat L = Mat::zeros(row, col, CV_8UC1);
	Mat dst = Mat::zeros(row, col, CV_8UC3);
	double m_av, A;
	//get M
	double sum = 0;
	for (int i = 0; i < row; i++) {
		for (int j = 0; j < col; j++) {
			uchar r, g, b, temp1, temp2;
			b = src.at<Vec3b>(i, j)[0];
			g = src.at<Vec3b>(i, j)[1];
			r = src.at<Vec3b>(i, j)[2];
			temp1 = min(min(r, g), b);
			temp2 = max(max(r, g), b);
			M.at<uchar>(i, j) = temp1;
			M_max.at<uchar>(i, j) = temp2;
			sum += temp1;
		}
	}
	m_av = sum / (row * col * 255);
	eps = 0.85 / m_av;
	boxFilter(M, M_ave, CV_8UC1, Size(51, 51));
	double delta = min(0.9, eps*m_av);
	for (int i = 0; i < row; i++) {
		for (int j = 0; j < col; j++) {
			L.at<uchar>(i, j) = min((int)(delta * M_ave.at<uchar>(i, j)), (int)M.at<uchar>(i, j));
		}
	}
	A = (getMax(M_max) + getMax(M_ave)) * 0.5;
	for (int i = 0; i < row; i++) {
		for (int j = 0; j < col; j++) {
			int temp = L.at<uchar>(i, j);
			for (int k = 0; k < 3; k++) {
				int val = A * (src.at<Vec3b>(i, j)[k] - temp) / (A - temp);
				if (val > 255) val = 255;
				if (val < 0) val = 0;
				dst.at<Vec3b>(i, j)[k] = val;
			}
		}
	}
	return dst;
}

int main() {
	Mat src = imread("F:\\fog\\1.jpg");
	Mat dst = dehaze(src);
	cv::imshow("origin", src);
	cv::imshow("result", dst);
	cv::imwrite("F:\\fog\\res.jpg", dst);
	waitKey(0);
	return 0;
}

一些效果图

小结

算法里面有2个参数可以自己调节,滤波的半径和 ρ \rho ρ。具体调整方式和取值方式可以参见:http://www.cnblogs.com/Imageshop/p/3410279.html 。欢迎关注我的数字图像处理论文复现工程:https://github.com/BBuf/-Image-processing-algorithm

全部评论

相关推荐

01-14 10:23
已编辑
湖南师范大学 计调
太久没更新,前几天看到一条评论,说“牛客就是当年那群做题区毕业了开始找工作还收不住那股味”的群体。字里行间透着居高临下的评判,不是,他该不会以为自己很幽默?很犀利吧?作为在牛客混了不算短日子的用户,我感到的不只是被冒犯,更是一种深刻的悲哀——这种以“松弛感”为名,对另一种生存策略的轻蔑,颇有一种自己考不上大学早早出来混社会,嘲笑考上大学的人是书呆子,然后大言不惭地说:死读书有什么用,人脉和资源才是硬道理。我不知道说这个话的人,手头究竟握着多少真正管用的人脉与资源,也不知道他这么傲慢地说出“那股味”的时候,是站在哪一个巨人的肩膀上,才能如此“松弛从容”地俯视众生,还能品评出别人身上“没收住”的余...
淬月星辉:这种评论把正常的努力扭曲成卷😂,说白了就是自己不努力,看着身边努力的人一个个都事业有成了,自己的心里开始不平衡了,就发这种酸言酸语。牛客可以说是我用过那么多平台里社区氛围最好的论坛了,用了大半年了,基本上没见过有人吵架的,都是在互帮互助提建议,帮忙看简历的,帮忙选offer的,帮忙指点学习路线的,分享工作经验和趣事的,我觉得这才是互联网该有的样子。
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务