【图像处理】去雾算法

2023-11-11

真正了解了什么叫最简单的就是最美好的

真正的好文章不需要大堆公式堆积显得充实,而是最最平实的思想!

这篇文章的:原文PDFPPT。感兴趣的可以了解一下。

这篇文章的目的就是以最简单的思路将图像达到去雾效果。用Matlab编了一下,效果图特别好啊哈:



下面是摘录的:

CVPR的中文名是计算机视觉与模式识别会议,是计算机视觉领域最顶尖的国际 会议之一。09年的CVPR共收到约1450篇投稿,其中393篇文章被接收,接收率为26%。只有一篇文章被选为今年的最佳论文。这是CVPR创立25年 以来首次由中国人获得这个奖项。

2010年的结果也已经出来了,一共1724篇文章,CVPR2010 Paper Acceptance Rates: 78 papers were accepted for ORAL Presentation (4.5%).384 papers were accepted for POSTER Presentation (22.3%).

下面是作者的感想摘录,值得借鉴:

这篇论文研究的问题是图像的去雾技术,它可 以还原图像的颜色和能见度,同时也能利用雾的浓度来估计物体的距离,这些在计算机视觉上都有重要应用(例如三维重建,物体识别)。但是之前人们还没找到简 单有效的方法来达到这个目的。在这篇论文里,我们找到了一个非常简单的,甚至说令人惊讶统计规律,并提出了有效的去雾方法。

与之前的方法不同,我们把注意力放到了无雾图像的统计特征上。我们发 现,在无雾图像中,每一个局部区域都很有可能会有阴影,或者是纯颜色的东西,又或者是黑色的东西。因此,每一个局部区域都很有可能有至少一个颜色通道会有 很低的值。我们把这个统计规律叫做Dark Channel Prior。直观来说,Dark Channel Prior认为每一个局部区域都总有一些很暗的东西。这个规律很简单,但在我们研究的去雾问题上却是本质的基本规律。

由于雾总是灰白色的,因此一旦图像受到雾的影响,那么这些本来应该很暗 的东西就会变得灰白。不仅如此,根据物理上雾的形成公式,我们还能根据这些东西的灰白程度来判断雾的浓度。因此,我们提出的Dark Channel Prior能很有效地去除雾的影响,同时利用物的浓度来估算物体的距离。

大道之行在于简

我们这篇文章的三个审稿人都给出了最高的评分。他们认为我们的方法简单 而有效。其中一位评委说,Dark Channel Prior的想法听起来很不可思议,但我们却证明了其真实性。另一位评委认为很少有文章能够用如此简单的方法使实验结果获得如此大的提升。还有一位评委甚 至亲自实现了我们的方法并确认其可行。孙剑说阅读这样的评审结果是一件让人快乐的事情。而汤老师认为,这篇文章的成功在于三个方面。第一,方法非常简单; 第二,对于一个很困难的问题,给出了很好的结果;第三,发现了一个基本的自然规律并且应用在实际的问题中。在迈阿密的演讲结束后,观众也给予了很高的评 价。他们跟我说,这是这次CVPR上最有趣的一个演讲。

一位与会的研究员说,最好的idea,往往就是那些看起来很简单,但说 出来大家都会觉得怎么没有人想到过的idea。而我们的idea正好就符合了这一点。我们论文摘要的第一句话是这么说的,“我们提出了一个简单而有效的方 法”。或许,这就是对我们这次工作最好的概括——简单的,就是美的。

代码如下:(仅仅修改了原图地址,可运行)

Matlab

%=========================================================%
%调用规则:(有雾时调用,否则不调用)
%实际操作时,according to experiments:
%percent=under_50/total
%percent<0.1%,取w=0.6
%percent>0.1%&&percent<1%,取w=0.45
%percenet>1%&&percent<2%,取w=0.3
%else not use haze-free-adjust
%有雾:绘制出的直方图<50的部分<1%
%最后控制台还会输出原图中under_50像素点所占比例
%=========================================================%
close all
clear all
clc
blockSize=15;               %每个block为15个像素
w0=0.6;                    
t0=0.1;
% A=200;
I=imread('city.png');
%I=imread('C:\Users\Zrq\Desktop\同济.jpg');
h = figure;
%set(gcf,'outerposition',get(0,'screensize'));%获得SystemScreenSize 传递给当前图像句柄gcf的outerposition属性
subplot(321)%表示3(行数)*2(列数)的图像,1代表所画图形的序号
imshow(I);
title('Original Image');
subplot(323);
grayI=rgb2gray(I);
imshow(grayI,[]);
title('原图像灰度图')
subplot(324);
imhist(grayI,64);
%统计<50的像素所占的比例
%%%%%%%%%%%%%%%%%%%%%%
[COUNT x]=imhist(grayI);
under_50=0;
for i=0:50
    under_50=under_50+COUNT(x==i);
end
under_50
total=size(I,1)*size(I,2)*size(I,3);
percent=under_50/total
%%%%%%%%%%%%%%%%%%%%%%
if(percent>0.02)
    error('This image need not Haze-Free-Proprocessing.');
else if(percent<0.001)
        w=0.6;
    else if (percent>0.01)
            w=0.3;
        else
            w=0.45;
        end
    end
end
 
[h,w,s]=size(I);
min_I=zeros(h,w);
 
for i=1:h                 
    for j=1:w
        dark_I(i,j)=min(I(i,j,:));%取每个点的像素为RGB分量中最低的那个通道的值
    end
end
 
Max_dark_channel=double(max(max(dark_I)))
dark_channel=double(dark_I);
t=1-w0*(dark_channel/Max_dark_channel);
 
T=uint8(t*255);
 
t=max(t,t0);
 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
I1=double(I);
J(:,:,1) = uint8((I1(:,:,1) - (1-t)*Max_dark_channel)./t);
 
J(:,:,2) = uint8((I1(:,:,2) - (1-t)*Max_dark_channel)./t);
 
J(:,:,3) =uint8((I1(:,:,3) - (1-t)*Max_dark_channel)./t);
subplot(322)
imshow(J);
imwrite(J,'tj2.jpg');
title('Haze-Free Image:');
 
subplot(325);
grayJ=rgb2gray(J);
imshow(grayJ,[]);
title('去雾后灰度图')
 
subplot(326);
imhist(grayJ,64);

结果:


原图:


去雾:



OpenCV(未运行)

//Hazefree helper
char tbarname1[] = "调节block";
//定义两个滑动条,用于调节参数
char tbarname2[] = "调节w";
//w是为了保留一部分的雾
int block=5;
int w1=80;
double w;
IplImage *dst=NULL;
 
IplImage *quw(IplImage *src,int block,double w)
{
	//图像分别有三个颜色通道
	IplImage *dst1=NULL;
	IplImage *dst2=NULL;
	IplImage *dst3=NULL;
	IplImage *imgroi1;
	//dst1的ROI
	IplImage *imgroi2;
	//dst2的ROI
	IplImage *imgroi3;
	//dst3的ROI
	IplImage *roidark;
	//dark channel的ROI
	IplImage *dark_channel=NULL;
	//暗原色先验的指针
	IplImage *toushelv=NULL;
	//透射率
 
	//去雾算法运算后的三个通道
	IplImage *j1=NULL;
	IplImage *j2=NULL;
	IplImage *j3=NULL;
	//去雾后的图像,三通道合并成
	IplImage *dst=NULL;
	//源图像ROI位置以及大小
	CvRect ROI_rect;
 
	//分离的三个通道
	dst1=cvCreateImage(cvSize(src->width,src->height),IPL_DEPTH_8U,1);
	dst2=cvCreateImage(cvSize(src->width,src->height),IPL_DEPTH_8U,1);
	dst3=cvCreateImage(cvSize(src->width,src->height),IPL_DEPTH_8U,1);
 
	//为各个ROI分配内存
	imgroi1=cvCreateImage(cvSize(block,block),IPL_DEPTH_8U,1);
	imgroi2=cvCreateImage(cvSize(block,block),IPL_DEPTH_8U,1);
	imgroi3=cvCreateImage(cvSize(block,block),IPL_DEPTH_8U,1);
	roidark=cvCreateImage(cvSize(block,block),IPL_DEPTH_8U,1);
 
	//为j1 j2 j3分配大小
	j1=cvCreateImage(cvSize(src->width,src->height),IPL_DEPTH_8U,1);
	j2=cvCreateImage(cvSize(src->width,src->height),IPL_DEPTH_8U,1);
	j3=cvCreateImage(cvSize(src->width,src->height),IPL_DEPTH_8U,1);
 
	//为暗原色先验指针分配大小
	dark_channel=cvCreateImage(cvSize(src->width,src->height),IPL_DEPTH_8U,1);
	//为透射率指针分配大小
	toushelv=cvCreateImage(cvSize(src->width,src->height),IPL_DEPTH_8U,1);
	//dst分配大小
	dst=cvCreateImage(cvSize(src->width,src->height),IPL_DEPTH_8U,3);
	//将原彩色图像分离成三通道
	cvSplit(src,dst1,dst2,dst3,NULL);
	//求暗原色
	ROI_rect.width=block;
	ROI_rect.height=block;
	ROI_rect.x=0;
	ROI_rect.y=0;
 
 
	int i;
	int j;
	double min1=0;
	double max1=0;
	double min2=0;
	double max2=0;
	double min3=0;
	double max3=0;
	double min=0;
	CvScalar value;
	for(i=0;i<src->width/block;i++)
	{        for(j=0;j<src->height/block;j++)
	{
		//分别计算三个通道内ROI的最小值
		cvSetImageROI(dst1,ROI_rect);
		cvCopy(dst1,imgroi1,NULL);
		cvMinMaxLoc(imgroi1,&min1,&max1,NULL,NULL);
		cvSetImageROI(dst2,ROI_rect);
		cvCopy(dst2,imgroi2,NULL);
		cvMinMaxLoc(imgroi2,&min2,&max2,NULL,NULL);
		cvSetImageROI(dst3,ROI_rect);
		cvCopy(dst3,imgroi3,NULL);
		cvMinMaxLoc(imgroi3,&min3,&max3,NULL,NULL);
		//求三个通道内最小值的最小值
		if(min1<min2)
			min=min1;
		else
			min=min2;
		if(min>min3)
			min=min3;//min为这个ROI中暗原色
		value=cvScalar(min,min,min,min);//min放在value中
		//min赋予dark_channel中相应的ROI
		cvSetImageROI(dark_channel,ROI_rect);
		cvSet(roidark,value,NULL);
		cvCopy(roidark,dark_channel,NULL);
		//释放各个ROI
		cvResetImageROI(dst1);
		cvResetImageROI(dst2);
		cvResetImageROI(dst3);
		cvResetImageROI(dark_channel);
		//转入下一个ROI
		ROI_rect.x=block*i;
		ROI_rect.y=block*j;
	}
	}
	//保存暗原色先验的图像
	cvSaveImage("f:/dark_channel_prior.jpg",dark_channel);
	//利用得到的暗原色先验dark_channel_prior.jpg求大气光强
	double min_dark;
	double max_dark;
	CvPoint min_loc;
	CvPoint max_loc;//max_loc是暗原色先验最亮一小块的原坐标
	cvMinMaxLoc(dark_channel,&min_dark,&max_dark,&min_loc,&max_loc,NULL);
//	cout<<max_loc.x<<" "<<max_loc.y<<endl;
	ROI_rect.x=max_loc.x;
	ROI_rect.y=max_loc.y;
	double A_dst1;//定义大气光成分的估计值
	double dst1_min;
	double A_dst2;
	double dst2_min;
	double A_dst3;
	double dst3_min;
	cvSetImageROI(dst1,ROI_rect);
	//按照论文方法求大气光强估计值
	cvCopy(dst1,imgroi1,NULL);
	cvMinMaxLoc(imgroi1,&dst1_min,&A_dst1,NULL,NULL);
	cvSetImageROI(dst2,ROI_rect);
	cvCopy(dst2,imgroi2,NULL);
	cvMinMaxLoc(imgroi2,&dst2_min,&A_dst2,NULL,NULL);
	cvSetImageROI(dst3,ROI_rect);
	cvCopy(dst3,imgroi3,NULL);
	cvMinMaxLoc(imgroi3,&dst3_min,&A_dst3,NULL,NULL);
//	cout<<A_dst1<<" "<<A_dst2<<" "<<A_dst3<<endl;//这三值为大气光强度估计值
	//求透射率
	int k;
	int l;
	CvScalar m;
	CvScalar n;//暗原色先验各元素值
 
	for(k=0;k<src->height;k++)
	{
		for(l=0;l<src->width;l++)
		{
			m=cvGet2D(dark_channel,k,l);
			n=cvScalar(255-w*m.val[0]);
			//w目的是保留一部分的雾,使图像看起来真实些
			cvSet2D(toushelv,k,l,n);
		}
	}
	cvSaveImage("f:/toushelv.jpg",toushelv);
 
	//求无雾图像
	int p,q;
	double tx;
	double jj1,jj2,jj3;
	CvScalar ix,jx;
	for(p=0;p<src->height;p++)
	{
		for(q=0;q<src->width;q++)
		{
			tx=cvGetReal2D(toushelv,p,q);
			tx=tx/255;
			if(tx<0.1)
				tx=0.1;
			ix=cvGet2D(src,p,q);
			jj1=(ix.val[0]-A_dst1)/tx+A_dst1;//根据雾产生模型运算,还原出无雾图像
			jj2=(ix.val[1]-A_dst2)/tx+A_dst2;
			jj3=(ix.val[2]-A_dst3)/tx+A_dst3;
			jx=cvScalar(jj1,jj2,jj3,0.0);
			cvSet2D(dst,p,q,jx);
		}
	}
	cvSaveImage("f:/removed_haze.jpg",dst);
 
	//释放指针
	cvReleaseImage(&dst1);
	cvReleaseImage(&dst2);
	cvReleaseImage(&dst3);
	cvReleaseImage(&imgroi1);
	cvReleaseImage(&imgroi2);
	cvReleaseImage(&imgroi3);
	cvReleaseImage(&roidark);
	cvReleaseImage(&dark_channel);
	cvReleaseImage(&toushelv);
	cvReleaseImage(&j1);
	cvReleaseImage(&j2);
	cvReleaseImage(&j3);
	return dst;
}
 
IplImage *source;
void on_trackbar1(int h)
{
	dst=quw(source,block,w);
	cvShowImage("目的图像",dst);
	//      cvWaitKey(0);
}
void on_trackbar2(int h)
{
	w=(double)w1/100;
	dst=quw(source,block,w);
	cvShowImage("目的图像",dst);
	//      cvWaitKey(0);
}
 
void CCVMFCView::OnImageHazefree()
{
	imageClone(workImg,&source);
	//cvNamedWindow("有雾图像",CV_WINDOW_AUTOSIZE);
	cvFlip(source);
	//cvShowImage("有雾图像",source);
	cvNamedWindow("目的图像",CV_WINDOW_AUTOSIZE);
	cvShowImage("目的图像",source);
	cvCreateTrackbar(tbarname1, "目的图像", &block, 15, on_trackbar1);
	cvCreateTrackbar(tbarname2, "目的图像", &w1, 100, on_trackbar2);
	cvWaitKey(0);
	
	cvReleaseImage(&source);
 
	cvDestroyWindow("目的图像");
	cvDestroyWindow("有雾图像");
	cvFlip(dst);
	m_dibFlag=imageReplace(dst,&workImg);
	Invalidate();
}


文章是香港中文的汤教授么?谁有文章原文麻烦发我一份,没找到,想学习一下。

twinklezheng@163.com


转载来源 点击打开链接

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【图像处理】去雾算法 的相关文章

  • ACL访问控制列表原理及实例

    目录 一 ACL概述 1 ACL访问控制列表作用 2 ACL访问控制列表工作原理 3 ACL访问控制列表处理过程原则 二 ACL访问控制列表类型 1 标准访问控制列表 2 扩展访问控制列表 三 配置实例 1 要求 用标准访问控制列表 vla

随机推荐

  • qt modules public internal 私有头文件 private

    qt对源码进行了分层 把数据成员都单独拉到一个 p h的头文件中 形成internal部分的接口类Qt之二进制兼容 qt p h 文件的用途是什么 qt不建议用户使用internal部分的接口类 因为不同平台和不用版本的qt interna
  • sort函数的时间、空间复杂度

    sort函数进行排序的时间复杂度为n log2n 原理 不是简单的快排 STL的sort 算法 数据量大时采用Quick Sort 分段递归排序 一旦分段后的数据量小于某个门槛 为避免Quick Sort的递归调用带来过大的额外负荷 就改用
  • Grade for Android(从 Gradle 和 AS 开始)

    http www open open com lib view open1451536597026 html 正如大家所见 这是本英文书 而由于国内的gradle翻译资料不全 所以特次开辟专栏 翻译gradle for android这本书
  • 基于JWT的springboot权限验证技术实现

    JWT简介 Json Web Token JWT JSON网络令牌 是为了在网络应用环境间传递声明而制定的一种基于JSON的开放标准 RFC 7519 JWT是一个轻便的安全跨平台传输格式 定义了一个紧凑的自包含的方式用于通信双方之间以 J
  • 通过Navicat创建ER图技巧笔记

    1 通过已有数据库逆向创建模型时 切忌一次生成所有表ER图 建议先将所有表添加到模型 然后依次从上至下添加到图表 2 单张图表可以通过图表模式进行重命名 在左侧图表窗口最上方 右键当前图表 gt 重命名 gt 修改 3 单张图表不宜过大 4
  • 解决vscode jupyter启动kernel错误的方案Failed to connect to Jupyter notebook.

    最近在vscode里面运行 ipynb文件的时候经常性地会出现报错情况 报错的图片内容如下 Failed to connect to Jupyter notebook 经过网上一番查阅方法之后 终于将配件搭建好了 解决方法为输入如下命令 p
  • 【Unity 学习笔记】动画系统(续)和事件

    在上一篇笔记中 我们使用Unity的动画系统实现了移动和跳跃的动画 在这一篇笔记中我们将使用Unity事件的方式来实现受伤和死亡的动画 首先创建一个受伤动画 由于素材中没有现成的受伤动画 我们只能手动创建一个简陋的闪烁动画 主要现实在角色受
  • java变量的类别和作用范围

    1 类别及作用范围 类变量 在类中用static修饰的字段 存储位置 方法区 生命周期 随着JVM的消亡而消失 生命周期最长 局部变量 在方法中存在的 或者形参 存储位置 栈帧中 生命周期 随着方法的调用而存在 生命周期最短 实例变量 在类
  • GCC编译器-<嵌入式Linux应用程序开发标准教程>-华清远见

    3 3 gcc编译器 GNU CC 简称为gcc 是GNU项目中符合ANSI C标准的编译系统 能够编译用C C 和Object C等 语言编写的程序 gcc不仅功能强大 而且可以编译如C C Object C Java Fortran P
  • LA@特征值和特征向量的性质

    文章目录 方阵特征值和特征向量的性质 特征值之和 特征值之积 推论 特征值判定方阵的可逆性 证明 小结 导出性质 可逆矩阵的特征值性质 转置矩阵和特征值 矩阵多项式的特征值 不同特征值的特征向量线性无关定理 推论 推广 特征向量线性组合 特
  • [python爬虫] 爬取图片无法打开或已损坏的简单探讨

    本文主要针对python使用urlretrieve或urlopen下载百度 搜狗 googto 谷歌镜像 等图片时 出现 无法打开图片或已损坏 的问题 作者对它进行简单的探讨 同时 作者将进一步帮你巩固selenium自动化操作和urlli
  • 【C语言】数据结构-----字符串匹配之KMP算法

    目录 算法简介 匹配原理 第一次匹配 第二次匹配 第三次匹配 第四次匹配 可能失配位置 next数组求解 next数组的由来 next数组的用法 next数组代码的实现 KMP算法的实现 示例 完整的代码 KMP算法与BF算法相比较 算法简
  • python处理ECG二进制文件(.dat文件)和.db文件

    python处理ECG二进制文件 dat文件 和 db文件 最近拿到了一批ECG原数据文件 包括 dat和 db文件 需要自己解析 记录一下解析结果 1 dat 文件是病人的心电数据 以二进制形式读取和解析 数据文件的说明 数据文件记录的是
  • FLASH擦除问题

    我们最近用mm32f3277的flash mm32f3277的flash有512K的空间 128个扇区 每个扇区有四页 每页有1K 图一 mm32f3277的flash 我们写入flash用的是片内FLASH存储器 片内FLASH存储器的地
  • java多线程异步处理批量数据

    前段时间需要一个批量请求别人接口的模块 由于别人接口反应速度慢导致批量请求耗费时间太多 于是在网上多发查询找到一个批量异步接口切能返回数据 多线程配置类 import org springframework aop interceptor
  • error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏

    一 问题描述 打开用VS2010打开vs 2008创建的解决方案 重新生成解决方案时 报如下错误 error LNK1123 转换到 COFF 期间失败 文件无效或损坏 二 原因分析 输入文件必须具有通用对象文件格式 COFF 如果输入文件
  • Maven 子项目

    使用maven搭建的子项目 其中包含web子项目和其他依赖子项目 在使用tomcat构建war的时候 会构建该web相对应的war maven关联的其他子项目会以jar包的形式关联到lib中 从而 使得web项目中可以引用其他包的类以及配置
  • 【C++】友元

    目录 友元的定义 全局函数做友元 类做友元 成员函数做友元 友元的定义 友元定义在类外面的一种函数或者类 友元不是成员函数 但是友元可以对某个类里面私有成员进行访问 要想友元获得访问某个类私有成员的权限 我们需要利用关键字friend并且在
  • eclipse web 项目中配置jetty-maven-plugin 版本 9.4.2.v20170220

    在web项目的pom xml文件中添加jetty maven plugin插件配置 如下
  • 【图像处理】去雾算法

    真正了解了什么叫最简单的就是最美好的 真正的好文章不需要大堆公式堆积显得充实 而是最最平实的思想 这篇文章的 原文PDF PPT 感兴趣的可以了解一下 这篇文章的目的就是以最简单的思路将图像达到去雾效果 用Matlab编了一下 效果图特别好