《Single Image Haze Removal Using Dark Channel Prior》论文阅读及复现番外(使用导向滤波估计更加精细的透射率)

Single Image Haze RemovalUsing Dark Channel Prior 摘要 本文提出了一种简单而有效的图像先验方法——暗通道先验,用于去除单幅输入图像中的雾霾。暗通道先验是室外无雾图像的一种统计。它基于一个关键的观察结果——户外无雾图像中的大多数局部块包含一些像素,这些像素在至少一个颜色通道中的强度非常低。将该先验与薄雾成像模型一起使用,我们可以直接估计薄雾的厚度并恢复高质量的无薄雾图像。在各种模糊图像上的结果证明了所提出的先验的能力。此外,还可以获得高质量的深度图作为除雾的副产品。 一引言 本文提出了一种新的先验——暗通道先验,用于单幅图像去雾。暗通道先验是基于室外无 阅读详情

前言

之前写过这篇论文的复现,https://blog.youkuaiyun.com/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 Size
	int 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.youkuaiyun.com/just_sort/article/details/84324239

Single Image Haze Removal Using Dark Channel Prior(基于暗原色先验原理的单一图像去雾技术),附源代码与PPT 何凯明先生09年CVPR会议最佳论文,Single Image Haze Removal Using Dark Channel Prior,中英文都有,并且有何恺明在CVPR会议上演讲时的ppt——基于暗通道先验的单幅图像去雾技术,并且有何凯明公开的源码guided-filter-code。 立即下载

相关推荐

Single Image Haze Removal Using Dark Channel Prior 翻译

何恺明博士的经典论文,极简单的方式对图像去雾做了重大提升。 本文为原论文的翻译。

Single Image Haze Removal Using Dark Channel Prior

单幅图像基于暗通道先验的去雾 Kaiming He, Jian Sun, and Xiaoou Tang, Fellow, IEEE 摘要:在本篇论文中,我们提出了一种简单但是有效的图像先验条件——暗通道先验去从一幅输入图像中去雾。暗通道先验是一种对于大量户外有雾图像的统计结果,它最重要的一个观察结果是户外无雾图像的绝大部分区域包含某些像素的亮度值至少在某一个通道上是非常低的。结合这个先验条件与雾天图像模型,我们可以直接估计雾的厚度并且回复一幅高质量的无雾图像。基于各种各样的有雾图像的实验去雾结果证明了所提

风信子的博客 7606

Single Image Haze Removal Using Dark Channel Prior 图像去雾 原文及翻译 何凯明

Single Image Haze Removal Using Dark Channel Prior 图像去雾 原文及翻译 何凯明

何凯明:Single Image Haze Removal Using Dark Channel Prior

参考:在本文中,我们提出了一种简单但有效的图像先验-暗通道先验,用它可以从单个输入图像中去除雾。暗通道先验从无雾室外图像进行的统计所得。这是基于一个关键的观察:没有雾的室外图像中,大多数局部块包含一些像素,它们至少有一个颜色通道值非常低。使用此先验和雾成像模型,我们可以直接估计雾的厚度,并恢复成高质量的无雾的图像。对各种室外雾霾图像的结果证明了,我们提出的这个先验的威力。此外,去雾的同时还可以获得高质量深度图。

mytzs123的博客 4940

深度学习与神经网络有什么区别

人工神经网络(ArtificialNeuralNetwork,即ANN)是从信息处理角度对人脑神经元网络进行抽象,是20世纪80年代以来人工智能领域兴起的研究热点,其本质是一种运算模型,由大量的节点(或称神经元)之间相互联接构成,在模式识别、智能机器人、自动控制、生物、医学、经济等领域已成功地解决了许多现代计算机难以解决的实际问题,表现出了良好的智能特性。...

super67269的博客 8486

STM32F4_LCD显示汉字

LCD显示汉字和显示图片、数字、字符的原理是一样的,都是将汉字、图片、数字以及字符转换点阵,进而通过函数扫描点阵在LCD上显示;

light_2025的博客 1万+

Single Image Haze Removal Using Dark Channel Prior(暗通道先验)

基于暗通道先验的去雾算法原理以及实现

AI小花猫的博客 2866

agent-browser OpenClaw 的最佳搭档

agent-browser 是专为 AI Agent 设计的浏览器自动化工具,目前被公认为 OpenClaw 的最佳配套方案。这份技术文档完整记录了其架构、协议、性能调优与常见问题处理,非常适合想让OpenClaw 真正“上手”互联网的开发者与老用户。

liu_zhiyi的博客 1779

Single Image Haze Removal Using Dark Channel Prior使用暗通道先验去除单个图像的雾霾

室外场景图像通常收到大气中浑浊介质(颗粒和水滴)的影响。雾、霾和烟就是由于大气的吸收和散射而产生的这种现象。摄像机从场景点接收到的辐照度沿视线衰减。入射光与空气光混合,空气光是被大气粒子反射到视线中的环境光,退化的图像失去对比度和色彩保真度。由于散射的数量取决于场景点到相机的距离,因此退化是空间变化的。本文发现,在大多数不覆盖天空的局部区域中,一些像素(或暗像素)通常在至少一个颜色(RGB)通道中具有非常低的强度。在模糊图像中,该通道中这些暗像素的强度主要是由空气光贡献的。

qq_43267011的博客 1219

从流量到凭证:实战解析SMB协议中的NTLMv2/v1哈希提取与破解

本文详细解析了SMB协议中NTLMv2/v1哈希的提取与破解实战技巧。从流量捕获、哈希格式处理到Hashcat高效破解,提供了一套完整的操作指南。文章特别强调了NTLMv2和NTLMv1哈希的区别及处理要点,并分享了防护建议与检测方法,帮助安全人员提升渗透测试效率。

weixin_30642561的博客 116

企业信息化系统的组成模块-核心业务系统

通过标准化的数据流形成完整的业务闭环,CRM生成的销售订单驱动ERP的生产和采购,ERP将生产计划传递给MES执行,MES报工数据返回ERP进行成本核算,ERP再将交付信息同步给CRM供客户查询。生产管理确保高效交付,缩短订单周期。某贸易公司实施ERP供应链模块后,库存周转率从每年4次提升到8次,库存资金占用从2000万降到1200万,释放800万现金流,同时缺货率从15%降到5%。│ │库存 │ │ MRP │ │ ERP │ │ 云ERP/ │ │。

weiyvyy的博客 694

何凯明:Single Image Haze Removal Using Dark Channel Prior[CVPR 2009]

在图像去雾领域,几乎没有人不知道《Single Image Haze Removal Using Dark Channel Prior》这篇文章,该文是2009年CVPR最佳论文。作者何凯明博士,2007年清华大学毕业,2011年香港中文大学博士毕业。 soft matting过程比较复杂,并且执行速度非常慢,论文的推理步骤特别清晰,讲解很到位。其另外一篇文章《Guided I...

女王の专属领地 3919

点云数据处理:体素滤波算法

体素滤波是一种简单而有效的点云数据处理方法,可用于去除离群点和平滑点云表面。体素滤波是一种常用的点云数据处理算法,用于去除离群点并平滑点云表面。在本文中,我们将介绍CloudCompare和PCL(Point Cloud Library)中的体素滤波算法,并提供相应的源代码示例。PCL是一个专门用于点云处理的开源库,提供了一系列高效的点云处理算法和工具。然后,我们创建了一个。方法执行体素滤波,并将滤波后的点云保存为"filtered_cloud.ply"文件。方法来执行体素滤波,指定体素大小为0.01。

ZyqfCss的博客 388

单张图像去雾技术解析:Single Image Haze Removal Using Dark Channel Prior

单张图像去雾技术解析:Single Image Haze Removal Using Dark Channel Prior 去发现同类优质开源项目:https://gitcode.com/ 项目核心功能/场景:利用暗通道先验进行单张图像去雾,提升图像清晰度。 项目介绍 在现代图像处理领域,图像去雾技术一直是研究的热点。Single Image Haze Removal Using Dark Cha...

gitblog_06775的博客 538

【agent实战教程】OpenClaw多个agent一文通

一个合格的独立agent,必须具备6个完全独立的专属组件独立组件路径规则核心要求不独立的严重后果唯一agentId配置文件中全局唯一,不能重复,建议用英文+数字,不要有特殊字符agent配置冲突,消息派单错误,会话串线独立工作区(workspace)建议每个agent一个独立文件夹,不要共用人设、记忆、规则混在一起,agent人设崩塌,对话串线独立状态目录(agentDir)固定系统自动生成,绝对禁止多个agent复用同一个agentDir。

海兰 649

基于深度学习的三维重建算法——详解与实现

随着深度学习技术的迅猛发展,基于深度学习的三维重建算法在最近几年取得了显著的进展。而基于深度学习的三维重建算法通过利用深度神经网络,能够从大规模数据中学习到更准确、鲁棒的三维结构表示。本文综述了基于深度学习的三维重建算法,并给出了相应的源代码。随着深度学习技术的不断发展,我们相信基于深度学习的三维重建算法将会在未来得到更广泛的应用。实验结果表明,基于深度学习的三维重建算法在准确性和鲁棒性方面取得了显著的提升。以上是关于基于深度学习的三维重建算法的详细介绍与实现,希望对您有所帮助。

CyberGenius的博客 1227

暗通道先验——Single Image Haze Removal Using Dark Channel Prior

大气散射模型 暗通道先验 大气光值A的估计 图像复原 from PIL import Image import cv2; import math; import numpy as np; import os def DarkChannel(im,sz): b,g,r = cv2.split(im)#通道拆分 dc = cv2.min(cv2.min(r,g),b);#取...

cherry1307的博客 2250

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

暗通道先验去雾Single Image Haze Removal Using Dark Channel Prior

MATLAB代码

W_extend的博客 586

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

暗原色先验单一输入图像去雾

何恺明,孙剑,汤晓鸥 香港中文大学 微软亚洲研究院 摘要:在这篇论文当中,我们提出了一种简单但是有效的图像先验规律——暗原色先验(dark channel prior)来为单一输入图像去雾。暗原色先验来自对户外无雾图像数据库的统计规律,它基于经观察得到的这么一个关键事实——绝大多数的户外无雾图像的每个局部区域都存在某些至少一个颜色通道的强度值很低的像素。利用这个先验建立的去雾模型,我们可直接估算

shirelyme的专栏 5881

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

基于照明光分离的用于航海监督的单帧图像去雾

基于照明光分离的用于航海监督的单帧图像去雾 Single Image Defogging Based on Illumination Decomposition for Visual Maritime Surveillance 文献引文信息: Hu, H. M., et al. (2019). “Single Image Defogging Based on Illumination Decomposition for Visual Maritime Surveillance.” IEEE Trans I.

小山山的博客 1405

图像去雾技术详解:Single Image Haze Removal Using Dark Channel Prior 原文及翻译

图像去雾技术详解:Single Image Haze Removal Using Dark Channel Prior 原文及翻译 去发现同类优质开源项目:https://gitcode.com/ 此仓库提供了《Single Image Haze Removal Using Dark Channel Prior》的中英文对照原文,由何凯明先生撰写。该文章详细介绍了利用暗通道先验进行单张图像去雾的方...

gitblog_06756的博客 347

《Single Image Haze Removal Using Dark Channel Prior》阅读笔记

《Single Image Haze Removal Using Dark Channel Prior》 前言 这篇文章是何大神于09发表在cvpr上的传统图像处理方向的文章,直到现在其效果任然不输于深度网络。 论文连接:https://ieeexplore.ieee.org/document/5567108/ 代码连接: Abstract 在本文中,我们提出了一个简单但有效的图像先验暗通道,以去除单一输入图像的雾霾。暗通道先验是一种无雾霾户外图像的统计数据。它是基于一个关键的观察—— 在无雾的户外图像中的

NiZjiTouA的博客 1036

OpenCV图像处理专栏十二 |《基于二维伽马函数的光照不均匀图像自适应校正算法》

欢迎STAR我的论文复现工程: https://github.com/BBuf/-Image-processing-algorithm 算法原理 论文使用了Retinex的多尺度高斯滤波求取光照分量,然后使用了二维Gamma函数针对原图的HSV空间的V分量进行亮度改变,得到结果。原理还是蛮简单的,因为是中文论文,且作者介绍得很清楚,我就不细说了,可以自己看论文,论文地址: https://wenk...

I good vegetable a! 8840
上一篇: 【AI PC端算法优化】五,常量阶最大值最小值滤波算法
下一篇: OpenCV图像处理专栏十 | 利用中值滤波进行去雾
just_sort
博客等级 码龄11年 2356粉丝 1667原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值