![92450fe2384ccc83ed1653bd4e70be58.png](https://i-blog.csdnimg.cn/blog_migrate/7687ca317cd55ea33095837cbb077a1c.jpeg)
代码开源在 https:// github.com/BBuf/Image-p rocessing-algorithm ,感兴趣给我来个星星呗。
1. 前言
这是OpenCV图像处理算法朴素实现专栏的第17篇文章。今天为大家带来一篇之前看到的用于单幅图像去雾的算法,作者来自清华大学,论文原文见附录。
2. 雾天退化模型
之前在介绍何凯明博士的暗通道去雾论文OpenCV图像处理专栏六 | 来自何凯明博士的暗通道去雾算法(CVPR 2009最佳论文)的时候已经讲到了这个雾天退化模型,我们这里再来回顾一下。在计算机视觉领域,通常使用雾天图像退化模型来描述雾霾等恶劣天气条件对图像造成的影响,该模型是McCartney首先提出。该模型包括衰减模型和环境光模型两部分。模型表达式为:
其中,
公式(1)中的
由此可见,图像去雾过程就是根据
对于暗通道去雾算法来说,先从暗原色通道中选取最亮的0.1%比例的像素点,然后选取原输入图像中这些像素具有的最大灰度值作为全局大气光值
然后根据公式(2)可以得出:
首先可以确定的是
根据(4)和(5)推出:
因此初略估计透射率的计算公式:
最后为了保证图片的自然性,增加一个参数
好了,上面复习完了何凯明博士的暗通道去雾,我们一起来看看清华大学这篇论文。
3. 算法流程
![181b27f783362f430d6f63105c846c8a.png](https://i-blog.csdnimg.cn/blog_migrate/06260baa38a7ade15aed1fd6019119aa.jpeg)
实际上有了这个算法流程就可以写出代码了,不过为了加深理解可以看下面的一些推导。
4. 一些推导
我们知道去雾的步骤主要就是估计全局大气光值
4.1 估计透射率t(x)
从第二节的介绍我们知道
然后这篇论文使用了
我们取
所以公式2变换为
对公式(4)右边进行均值滤波:
其中
均值滤波后的结果可以反映
其中
为了防止去雾后图像出现整体画面偏暗,这里根据图像的均值来调整
其中
因此可以得到透射率的计算公式:
结合公式(1)推出:
4.2 估计全球大气光值
公式(5)中第一个等式左侧的表达式取值范围为
一般情况下又存在
(KaiMing He的暗通道先验理论)。这样就初步确定了全局大气光的范围,为了能快速获取全局大气光,文章直接取两者的平均值作为全局大气光值,即:
然后大气光值
5. 代码实现
下面是代码实现。
#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:fog1.jpg");
Mat dst = dehaze(src);
cv::imshow("origin", src);
cv::imshow("result", dst);
cv::imwrite("F:fogres.jpg", dst);
waitKey(0);
return 0;
}
6. 结果
![33d17059f1c3c14d314d062b96687b01.png](https://i-blog.csdnimg.cn/blog_migrate/aaa5a2914ac90a939029fd9a5875c5d7.jpeg)
![61c776238640ff2bb53b43da39642100.png](https://i-blog.csdnimg.cn/blog_migrate/bcf95a8a4d7b2d37ecaadaa0c6d1e6ca.jpeg)
![af023a62dfe638f8a1986cb4f461d3be.png](https://i-blog.csdnimg.cn/blog_migrate/e05057be95f9e6bd5ec32c5d23a62532.jpeg)
![8e0b52e3f115f0450c88af8cb0e09faf.png](https://i-blog.csdnimg.cn/blog_migrate/5dc9dc32bb50146e5e19e73dfce1e49b.jpeg)
![225272fecfbd6819ebe77a20fea9dad1.png](https://i-blog.csdnimg.cn/blog_migrate/eaf856ad0354e295237155ec131b5be9.jpeg)
![2423d5414f78eae2cd346775b5b6065c.png](https://i-blog.csdnimg.cn/blog_migrate/07a65174716c583e271d06cfd8417a03.jpeg)
![0a0b2eb52e6bcc54db7e7c1bf71bdc84.png](https://i-blog.csdnimg.cn/blog_migrate/f4a34bb3f89b2745609d86798d5067b5.jpeg)
![ba6a13ab0c90c65c9e141b794d07a706.png](https://i-blog.csdnimg.cn/blog_migrate/65a9773b40dc1a306364408322e2db3b.jpeg)
![41f8e6f2fc3a7ca8fa7a7a0e266914a5.png](https://i-blog.csdnimg.cn/blog_migrate/5cd511300b9665c63fc98d354c0fc36c.jpeg)
![0fa4ac0e78fb6b3fd4a418bf95f1234d.png](https://i-blog.csdnimg.cn/blog_migrate/04b49a2a03439da6e42dab06d0ea7b6d.jpeg)
7. 结论
算法里面有2个参数可以自己调节,滤波的半径和
8. 参考
- https://blog.csdn.net/u013684730/article/details/76640321
- https://www.cnblogs.com/Imageshop/p/3410279.html
欢迎关注GiantPandaCV, 在这里你将看到独家的深度学习分享,坚持原创,每天分享我们学习到的新鲜知识。( • ̀ω•́ )✧
有对文章相关的问题,或者想要加入交流群,欢迎添加BBuf微信:
https://u.wechat.com/MPWFDnmCPu6zgf5YUtdpT_U (二维码自动识别)