《Single Image Haze Removal Using Dark Channel Prior》论文阅读及复现番外(使用导向滤波估计更加精细的透射率)
前言
之前写过这篇论文的复现,https://blog.csdn.net/just_sort/article/details/84110518 ,但是当时估算透射率的时候没有用softmating或者导向滤波,是用何博士的公式粗略的计算的,所幸,在了解了导向滤波后,我完成了使用导向滤波估算 更加精细的透射率的任务,也确实取得了更好的去雾效果,所以打算分享一下这个源码。我所有开源的论文实现均在github地址里:https://github.com/BBuf/-Image-processing-algorithm
算法原理
这些就不说了,可以查看之前的博客,直接公布代码吧。
代码
#include <opencv2/opencv.hpp>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace cv;
using namespace std;cv::Mat guidedFilter(cv::Mat I, cv::Mat p, int r, double eps)
{/*% GUIDEDFILTER O(1) time implementation of guided filter.%% - guidance image: I (should be a gray-scale/single channel image)% - filtering input image: p (should be a gray-scale/single channel image)% - local window radius: r% - regularization parameter: eps*/cv::Mat _I;I.convertTo(_I, CV_64FC1);I = _I;cv::Mat _p;p.convertTo(_p, CV_64FC1);p = _p;//[hei, wid] = size(I);int hei = I.rows;int wid = I.cols;//N = boxfilter(ones(hei, wid), r); % the size of each local patch; N=(2r+1)^2 except for boundary pixels.cv::Mat N;cv::boxFilter(cv::Mat::ones(hei, wid, I.type()), N, CV_64FC1, cv::Size(r, r));//mean_I = boxfilter(I, r) ./ N;cv::Mat mean_I;cv::boxFilter(I, mean_I, CV_64FC1, cv::Size(r, r));//mean_p = boxfilter(p, r) ./ N;cv::Mat mean_p;cv::boxFilter(p, mean_p, CV_64FC1, cv::Size(r, r));//mean_Ip = boxfilter(I.*p, r) ./ N;cv::Mat mean_Ip;cv::boxFilter(I.mul(p), mean_Ip, CV_64FC1, cv::Size(r, r));//cov_Ip = mean_Ip - mean_I .* mean_p; % this is the covariance of (I, p) in each local patch.cv::Mat cov_Ip = mean_Ip - mean_I.mul(mean_p);//mean_II = boxfilter(I.*I, r) ./ N;cv::Mat mean_II;cv::boxFilter(I.mul(I), mean_II, CV_64FC1, cv::Size(r, r));//var_I = mean_II - mean_I .* mean_I;cv::Mat var_I = mean_II - mean_I.mul(mean_I);//a = cov_Ip ./ (var_I + eps); % Eqn. (5) in the paper; cv::Mat a = cov_Ip / (var_I + eps);//b = mean_p - a .* mean_I; % Eqn. (6) in the paper;cv::Mat b = mean_p - a.mul(mean_I);//mean_a = boxfilter(a, r) ./ N;cv::Mat mean_a;cv::boxFilter(a, mean_a, CV_64FC1, cv::Size(r, r));mean_a = mean_a / N;//mean_b = boxfilter(b, r) ./ N;cv::Mat mean_b;cv::boxFilter(b, mean_b, CV_64FC1, cv::Size(r, r));mean_b = mean_b / N;//q = mean_a .* I + mean_b; % Eqn. (8) in the paper;cv::Mat q = mean_a.mul(I) + mean_b;return q;
}int rows, cols;
//获取最小值矩阵
int **getMinChannel(cv::Mat img) {rows = img.rows;cols = img.cols;if (img.channels() != 3) {fprintf(stderr, "Input Error!");exit(-1);}int **imgGray;imgGray = new int *[rows];for (int i = 0; i < rows; i++) {imgGray[i] = new int[cols];}for (int i = 0; i < rows; i++) {for (int j = 0; j < cols; j++) {int loacalMin = 255;for (int k = 0; k < 3; k++) {if (img.at<Vec3b>(i, j)[k] < loacalMin) {loacalMin = img.at<Vec3b>(i, j)[k];}}imgGray[i][j] = loacalMin;}}return imgGray;
}//求暗通道
int **getDarkChannel(int **img, int blockSize = 3) {if (blockSize % 2 == 0 || blockSize < 3) {fprintf(stderr, "blockSize is not odd or too small!");exit(-1);}//计算pool Sizeint poolSize = (blockSize - 1) / 2;int newHeight = rows + poolSize - 1;int newWidth = cols + poolSize - 1;int **imgMiddle;imgMiddle = new int *[newHeight];for (int i = 0; i < newHeight; i++) {imgMiddle[i] = new int[newWidth];}for (int i = 0; i < newHeight; i++) {for (int j = 0; j < newWidth; j++) {if (i < rows && j < cols) {imgMiddle[i][j] = img[i][j];}else {imgMiddle[i][j] = 255;}}}int **imgDark;imgDark = new int *[rows];for (int i = 0; i < rows; i++) {imgDark[i] = new int[cols];}int localMin = 255;for (int i = poolSize; i < newHeight - poolSize; i++) {for (int j = poolSize; j < newWidth - poolSize; j++) {for (int k = i - poolSize; k < i + poolSize + 1; k++) {for (int l = j - poolSize; l < j + poolSize + 1; l++) {if (imgMiddle[k][l] < localMin) {localMin = imgMiddle[k][l];}}}imgDark[i - poolSize][j - poolSize] = localMin;}}return imgDark;
}struct node {int x, y, val;node() {}node(int _x, int _y, int _val) :x(_x), y(_y), val(_val) {}bool operator<(const node &rhs) {return val > rhs.val;}
};//估算全局大气光值
int getGlobalAtmosphericLightValue(int **darkChannel, cv::Mat img, bool meanMode = false, float percent = 0.001) {int size = rows * cols;std::vector <node> nodes;for (int i = 0; i < rows; i++) {for (int j = 0; j < cols; j++) {node tmp;tmp.x = i, tmp.y = j, tmp.val = darkChannel[i][j];nodes.push_back(tmp);}}sort(nodes.begin(), nodes.end());int atmosphericLight = 0;if (int(percent*size) == 0) {for (int i = 0; i < 3; i++) {if (img.at<Vec3b>(nodes[0].x, nodes[0].y)[i] > atmosphericLight) {atmosphericLight = img.at<Vec3b>(nodes[0].x, nodes[0].y)[i];}}}//开启均值模式if (meanMode == true) {int sum = 0;for (int i = 0; i < int(percent*size); i++) {for (int j = 0; j < 3; j++) {sum = sum + img.at<Vec3b>(nodes[i].x, nodes[i].y)[j];}}}//获取暗通道在前0.1%的位置的像素点在原图像中的最高亮度值for (int i = 0; i < int(percent*size); i++) {for (int j = 0; j < 3; j++) {if (img.at<Vec3b>(nodes[i].x, nodes[i].y)[j] > atmosphericLight) {atmosphericLight = img.at<Vec3b>(nodes[i].x, nodes[i].y)[j];}}}return atmosphericLight;
}//恢复原图像
// Omega 去雾比例 参数
//t0 最小透射率值
cv::Mat getRecoverScene(cv::Mat img, float omega = 0.95, float t0 = 0.1, int blockSize = 15, bool meanModel = false, float percent = 0.001) {int** imgGray = getMinChannel(img);int **imgDark = getDarkChannel(imgGray, blockSize = blockSize);int atmosphericLight = getGlobalAtmosphericLightValue(imgDark, img, meanModel = meanModel, percent = percent);float **imgDark2, **transmission;imgDark2 = new float *[rows];for (int i = 0; i < rows; i++) {imgDark2[i] = new float[cols];}Mat B(rows, cols, CV_8UC1);for (int i = 0; i < rows; i++) {for (int j = 0; j < cols; j++) {B.at<uchar>(i, j) = img.at<Vec3b>(i, j)[0];}}Mat p(rows, cols, CV_64FC1);for (int i = 0; i < rows; i++) {for (int j = 0; j < cols; j++) {p.at<double>(i, j) = 1 - omega * imgDark[i][j] / atmosphericLight;}}Mat transmission_filter = guidedFilter(B, p, 80, 1e-3);imshow("transmission", transmission_filter);imwrite("F:\\res3.jpg", transmission_filter);waitKey(0);transmission = new float *[rows];for (int i = 0; i < rows; i++) {transmission[i] = new float[cols];}for (int i = 0; i < rows; i++) {for (int j = 0; j < cols; j++) {imgDark2[i][j] = float(imgDark[i][j]);//transmission[i][j] = 1 - omega * imgDark[i][j] / atmosphericLight;transmission[i][j] = transmission_filter.at<double>(i, j);if (transmission[i][j] < 0.1) {transmission[i][j] = 0.1;}}}cv::Mat dst(img.rows, img.cols, CV_8UC3);for (int channel = 0; channel < 3; channel++) {for (int i = 0; i < rows; i++) {for (int j = 0; j < cols; j++) {int temp = (img.at<Vec3b>(i, j)[channel] - atmosphericLight) / transmission[i][j] + atmosphericLight;if (temp > 255) {temp = 255;}if (temp < 0) {temp = 0;}dst.at<Vec3b>(i, j)[channel] = temp;}}}return dst;
}int main() {Mat src = imread("F:\\fog\\3.jpg");//cv::Mat src = cv::imread("/home/zxy/CLionProjects/Acmtest/3.jpg");rows = src.rows;cols = src.cols;cv::Mat dst = getRecoverScene(src);cv::imshow("origin", src);cv::imshow("result", dst);cv::imwrite("F:\\res2.jpg", dst);waitKey(0);
}
效果
结论
可以看到效果确实好一些,关于导向滤波可以看我的这篇博客:https://blog.csdn.net/just_sort/article/details/84324239
《Single Image Haze Removal Using Dark Channel Prior》论文阅读及复现番外(使用导向滤波估计更加精细的透射率)相关推荐
- 《Single Image Haze Removal Using Dark Channel Prior》一文中图像去雾算法的原理、实现、效果及其他。...
在图像去雾这个领域,几乎没有人不知道<Single Image Haze Removal Using Dark Channel Prior>这篇文章,该文是2009年CVPR最佳论文.作者 ...
- Single Image Haze Removal Using Dark Channel Prior 基于暗原色先验的单一图像去雾方法【翻译】
Single Image Haze Removal Using Dark Channel Prior Kaiming He, Jian Sun, Xiaoou Tang The Chinese Uni ...
- Single Image Haze Removal Using Dark Channel Prior
单幅图像基于暗通道先验的去雾 Single Image Haze Removal Using Dark Channel Prior Kaiming He, Jian Sun, and Xiaoou T ...
- 《Single Image Haze Removal Using Dark Channel Prior》一文中图像去雾算法的原理、实现、效果(速度可实时)...
最新的效果见 :http://video.sina.com.cn/v/b/124538950-1254492273.html 可处理视频的示例:视频去雾效果 在图像去雾这个领域,几乎没有人不知道< ...
- 《Single Image Haze Removal Using Dark Channel Prior》一文中图像去雾算法的原理、实现、效果及其他。 ...
在图像去雾这个领域,几乎没有人不知道<Single Image Haze Removal Using Dark Channel Prior>这篇文章,该文是2009年CVPR最佳论文.作者 ...
- A Fast Single Image Haze Removal Algorithm Using Color Attenuation Prior——基于颜色衰减先验单图片去雾算法原理...
本人最近在研究去雾方面的最新文献(2016年初),当然去雾方面的经典论文是何凯明博士的<Single Image Haze Removal Using Dark Channel Prior> ...
- Contrast in Haze Removal: Configurable Contrast Enhancement Model Based on Dark Channel Prior
吐槽吐槽!!!有史以来读的最费劲的一篇文章,各种长句!各种句式!各种缩写!各种实验中夹杂公式!!!各种各种!!!可是是IEEE的文章呢,读了那么多英文文章的如今读到我开始怀疑我的英文水平了,怀疑人生了 ...
- 读A Fast Single Image Haze Removal Algorithm Using Color Attenuation Prior
学习目标: A Fast Single Image Haze Removal Algorithm Using Color Attenuation Prior 个人体会: 基于模糊图像中像素的亮度和饱和 ...
- 【深度学习】何恺明经典之作—2009 CVPR Best Paper | Dark Channel Prior
本文介绍一下中国大陆第一篇计算机视觉顶会的best paper,也是何恺明第一次在计算机视觉领域大放异彩的一篇经典之作-Dark Channel Prior.另外本文在Dark Channel Pri ...
最新文章
- Tesla AutoPilot纯视觉方案解析
- 我国企业大数据的发展与应用总览
- 【数字信号处理】傅里叶变换性质 ( 傅里叶变换频移性质示例 )
- 人人都会设计模式:03-策略模式--Strategy
- Qt OpenGL 问题总结
- 数据结构中La表的数据合并到Lb表中
- linux grep跨行文本匹配,grep跨行匹配
- 易语言解析html实例,易语言总使用正则表达式实例解析
- linux 消息队列查看和删除
- 华硕主板如何用u盘启动计算机,华硕主板怎么设置u盘启动 华硕主板设置u盘启动方法【图文】...
- 运行Shell脚本的两种方法
- 游戏设计模式——观察者模式(Observer)
- Python绘制六种可视化图表详解
- 非管理系考PMP证书有用吗?
- 安卓非微信内置浏览器中的网页调起微信支付的方案研究
- 2019中国网络作家影响力榜乌贼排第一,烽火第二十,让人不解
- 渗透测试工具篇——sqlmap
- Android第三方开发包值高德地图SDK使用介绍
- JavaScript-ES7~ES8新特性使用教程
- 调用百度API,识别pdf图片
热门文章
- sklearn训练感知器用iris数据集
- 【笔记】计算机网络(一)
- 编写 Java 程序用于显示人的姓名和年龄。
- html5在线编辑器 h,前端最好用的HTML在线编辑器是哪一款
- 微信多点登录,消息漫游,假如让你来实现?
- 51单片机系列--1WrieDS18B20温度模块
- CVPR2019领域自适应/语义分割:Adapting Structural Information across Domains for Boosting Sema适应结构信息跨领域促进语义分割
- 基于python食品安全溯源管理系统django框架计算机毕业设计源码+系统+数据库+lw文档+调试部署
- maven配置aliyun镜像仓库settings.xml
- EPLAN P8部件库:包含低压电气控制系统设计常用品Pai型号