基于偏振差分成像的图像去雾算法
Polarization-based vision through haze
Yoav Y.Schechner,Srinivasa G.Narasimhan,and Shree K.Nayar
Columbia University
1,介绍
这篇文章在分析图像形成的过程中,将偏振对大气散射的影响考虑在内,然后设计从图像中去雾的算法。这个方法可以通过旋转偏振片到不同的角度或者两张偏振图像来实现。这个方法效果很好,不需要依赖天气情况的变化。
2,基本原理
把从光源到分布粒子的光线和从分布粒子到相机的光线构成的平面作为标准平面。将一束光线分成两个偏振分量,平行的量和垂直的量。光线和此平面平行的偏振量为,光线和此平面垂直的偏振量为,可以定义偏振度为:
其中A定义为:
根据大气散射模型,直接传输定义为:
其中表示无雾图像,t(z)可以表达为:
从而没有经过偏振片的含雾图像可以表达为:
当旋转偏振片时,是随偏振角度变化的函数,其函数曲线如下:
由上图可见,当偏振角度为90度时,为“最坏的状态”。当偏振角度为0度时,为“最好的状态”。其表达式如下:
其中和通过反解上式可得:
3,去雾过程
首先,应该求得大气光值和其对应的偏振度p。由于得到的0度和90度偏振图像中含有白色区域,不能直接选取图像中0.1%最亮的点的平均值作为大气光值。本文的做法如下,将90度偏振图像与0度偏振图像相减,得到的图像取其最亮的0.1%的点,在分别在0度和90度的偏振图像中找到作差得到的图像的最亮的0.1%的点的位置,取这些点的平均值,分别得到0度和90度偏振图像的大气光值。
现在定义每一个像素点的大气光为:
无偏振图像为:
传输函数为:
由以上各式,得到去雾图像为:
4,结果分析
依据上述的理论过程,利用MATLAB/C++实现的结果如下:
可以很明显的看到,通过上述理论过程去雾,在景物部分的效果很好,而在天空区域出现了很严重的噪声。为了解决这个问题,文章引入了一个参数,然后实现如下替换:,就可以解决天空区域噪声很大的问题。去噪的结果如下:
5,结论
通过以上的两个结果进行比较发现:不引入参数时天空区域出现严重的噪声现象;引入参数后,景物部分又出现了去雾效果不好的结果。总之,应适当调整引入的参数的大小,才能达到更好的去雾效果。
附录:
本文的C++代码如下:
#include <iostream> #include <stdlib.h> #include <time.h> #include <cmath> #include <algorithm> #include <opencv2\opencv.hpp>using namespace cv; using namespace std;typedef struct Pixel {int x, y;float data; }Pixel;bool structCmp(const Pixel &a, const Pixel &b) {return a.data > b.data;//descending降序 }Mat getAdd(Mat& parimg, Mat& perimg); Mat getSubstract(Mat& parimg, Mat& perimg); Mat getA(Mat& parimg, Mat& perimg, float *array); Mat recover(Mat& total, Mat& a, float *array);int main() {string loc1 = "E:\\polarization\\firstopencv\\0degree.tiff";string loc2 = "E:\\polarization\\firstopencv\\90degree.tiff";string name = "forest";clock_t start, finish;double duration;cout << "A defog program" << endl<< "----------------" << endl;Mat src1 = imread(loc1);Mat src2 = imread(loc2);Mat parimage = Mat(src1.size(), CV_16UC3);Mat perimage = Mat(src2.size(), CV_16UC3);src1.convertTo(parimage, CV_16UC3, 255.0 );src2.convertTo(perimage, CV_16UC3, 255.0 );imshow("0degree", parimage);imshow("90degree", perimage);cout << "input hazy image" << endl;int rows = parimage.rows;int cols = parimage.cols;Mat newparimage; Mat newperimage;parimage.convertTo(newparimage, CV_32FC3, 1.0/65535.0, 0);perimage.convertTo(newperimage, CV_32FC3, 1.0/65535.0, 0);Mat totalimage(rows, cols, CV_32FC3);Mat diffimage(rows, cols, CV_32FC3);Mat A(rows, cols, CV_32FC3);Mat recoverimg(rows, cols, CV_32FC3);totalimage = getAdd(newparimage,newperimage);diffimage = getSubstract(newparimage, newperimage);int nr = rows;int nl = cols;start = clock();//estimate Airlight//开一个结构体数组存暗通道,再sort,取最大0.1%,利用结构体内存储的原始坐标在原图中取点cout << "estimating airlight." << endl;vector<Mat> planes;split(diffimage, planes);Mat rchannel = planes[2];int pixelTot = rows * cols * 0.001;float *Apar = new float[3]; float *Aper = new float[3];Pixel *toppixels, *allpixels;toppixels = new Pixel[pixelTot];allpixels = new Pixel[rows * cols];for (unsigned int r = 0; r < rows; r++) {const uchar *data = rchannel.ptr<uchar>(r);for (unsigned int c = 0; c < cols; c++) {allpixels[r*cols + c].data = *data;allpixels[r*cols + c].x = r;allpixels[r*cols + c].y = c;}}std::sort(allpixels, allpixels + rows * cols, structCmp);memcpy(toppixels, allpixels, pixelTot * sizeof(Pixel));float tmp_par_A[3]; float tmp_per_A[3];float A_par_r, A_par_g, A_par_b, avg1, maximum1 = 0;int idx1, idy1, max_x1, max_y1;for (int i = 0; i < pixelTot; i++) {float A_par_sum_r = 0, A_par_sum_g = 0, A_par_sum_b = 0;idx1 = allpixels[i].x; idy1 = allpixels[i].y;const uchar *pardata = newparimage.ptr<uchar>(idx1);pardata += 3 * idy1;A_par_b = *pardata++;A_par_g = *pardata++;A_par_r = *pardata++;A_par_sum_b += A_par_b;A_par_sum_g += A_par_g;A_par_sum_r += A_par_r;tmp_par_A[0] = A_par_sum_b / pixelTot;tmp_par_A[1] = A_par_sum_g / pixelTot;tmp_par_A[2] = A_par_sum_r / pixelTot;}float A_per_r, A_per_g, A_per_b, avg2, maximum2 = 0;int idx2, idy2, max_x2, max_y2;for (int i = 0; i < pixelTot; i++){float A_per_sum_r = 0, A_per_sum_g = 0, A_per_sum_b = 0;idx2 = allpixels[i].x; idy2 = allpixels[i].y;const uchar *perdata = newperimage.ptr<uchar>(idx2);perdata += 3 * idy2;A_per_b = *perdata++;A_per_g = *perdata++;A_per_r = *perdata++;A_per_sum_b += A_per_b;A_per_sum_g += A_per_g;A_per_sum_r += A_per_r;tmp_per_A[0] = A_per_sum_b / pixelTot;tmp_per_A[1] = A_per_sum_g / pixelTot;tmp_per_A[2] = A_per_sum_r / pixelTot;}delete[] toppixels;delete[] allpixels;float P[3]; float Ainf[3];for (int i = 0; i < 3; i++){P[i] = (tmp_per_A[i] - tmp_par_A[i]) / (tmp_per_A[i] + tmp_par_A[i]);Ainf[i] = tmp_per_A[i] + tmp_par_A[i];}A = getA(newparimage, newperimage, P);cout << "start recovering." << endl;recoverimg = recover(totalimage, A, Ainf);cout << "recovering finished." << endl;finish = clock();duration = (double)(finish - start);cout << "defog used " << duration << "ms time;" << endl;imshow("result", recoverimg);waitKey(0);imwrite(name + "_refined.png", recoverimg);destroyAllWindows();parimage.release();perimage.release();recoverimg.release();return 0; }Mat getAdd(Mat& parimg, Mat& perimg) {int nr = parimg.rows; int nl = perimg.cols;Mat addimg = Mat::zeros(nr, nl, CV_32FC3);for (unsigned int r = 0; r < nr; r++){const float* parPtr = parimg.ptr<float>(r);const float* perPtr = perimg.ptr<float>(r);float* addPtr = addimg.ptr<float>(r);for (unsigned int c = 0; c < nl; c++){for (int i = 0; i < 3; i++){*addPtr++ = *parPtr++ + *perPtr++;}}}return addimg; }Mat getSubstract(Mat& parimg, Mat& perimg) {int nr = parimg.rows; int nl = perimg.cols;Mat subimg = Mat::zeros(nr, nl, CV_32FC3);for (unsigned int r = 0; r < nr; r++){const float* parPtr = parimg.ptr<float>(r);const float* perPtr = perimg.ptr<float>(r);float* subPtr = subimg.ptr<float>(r);for (unsigned int c = 0; c < nl; c++){for (int i = 0; i < 3; i++){*subPtr++ = *perPtr++ - *parPtr++;}}}return subimg; }Mat getA(Mat& parimg, Mat& perimg, float *array) {int nr = parimg.rows; int nl = perimg.cols;Mat A= Mat::zeros(nr, nl, CV_32FC3);for (unsigned int r = 0; r < nr; r++){const float* parPtr = parimg.ptr<float>(r);const float* perPtr = perimg.ptr<float>(r);float* APtr = A.ptr<float>(r);for (unsigned int c = 0; c < nl; c++){for (int i = 0; i < 3; i++){*APtr++ = (*perPtr++ - *parPtr++) / *array;}}}return A; }Mat recover(Mat& total,Mat& a,float *array) {int nr = total.rows;int nl=total.cols;Mat recoverimage = Mat::zeros(nr, nl, CV_32FC3);for (unsigned int r = 0; r < nr; r++){const float* totalPtr = total.ptr<float>(r);const float* aPtr = a.ptr<float>(r);float* recoverPtr = recoverimage.ptr<float>(r);for (unsigned int c = 0; c < nl; c++){for (int i=0;i<3;i++){*recoverPtr = (*totalPtr - *aPtr) /(1-(*aPtr / *array));recoverPtr++;totalPtr++;aPtr++;}}}return recoverimage; }
0度偏振图像为:
90度偏振图像为:
转载于:https://www.cnblogs.com/rust/p/10396378.html
基于偏振差分成像的图像去雾算法相关推荐
- 【论文阅读】改进的基于均值滤波的单幅图像去雾算法研究
改进的基于均值滤波的单幅图像去雾算法研究 吴延海,张婧,陈康 西安科技大学 学报, 2016 本文是在<基于单幅图像的快速去雾>基础上进行改进.主要改进有以下几点: 对<基于单幅图像 ...
- matlab求图像暗通道图像,基于暗通道先验条件图像去雾算法
基于暗通道先验条件图像去雾算法 香港大学何凯明博士于2009发表了一篇论文<Single Image Haze Removal Using Dark Channel Prior>.在文章中 ...
- 【计算机视觉课程设计】基于暗通道先验单幅图像去雾算法的实现(MATLAB)
声明:原创内容,创作不易,欢迎点赞收藏~ 摘 要 随着信息化时代的到来,计算机视觉得以迅速发展,在社会生活中的各个领域发挥了重要作用.然而,近年来大气污染逐渐加重,雾霾天气出现的频率越来越高,导 ...
- 基于MATLAB改进暗通道先验的图像去雾算法
基于MATLAB改进暗通道先验的图像去雾算法 摘要:暗通道先验去雾算法求得的的透射率比较精细,去雾效果优于大多数去雾算法.然而在暗通道求取过程中,最小值滤波的处理会使得暗色向外扩张,导致透射率扩张变大 ...
- 综述:视频和图像去雾算法以及相关的图像恢复和增强研究
综述:视频和图像去雾算法以及相关的图像恢复和增强研究 翻译自IEEE的一篇文章<Review of Video and Image Defogging Algorithms and Relate ...
- 单幅图像去雾算法研究综述
来源 <计算机工程与应用>北大核心期刊,CSCD数据库. 影响因子:2.348 简介 图像去雾算法是以满足特定场景需求,突出图片细节并增强图片质量为目的的图像分析与处理方法.在雾霾天气下, ...
- 避免图像去雾算法中让天空部分出现过增强的一种简易方法
FROM:http://www.chawenti.com/articles/25193.html 在经典的几种去雾算法中,包括何凯明的暗通道去雾.Tarel的基于中值滤波的去雾以及一些基于其他边缘保留 ...
- 基于暗通道优先的单幅图像去雾算法(Matlab)
基于暗通道优先的单幅图像去雾算法(Matlab) 每一幅图像的RGB三个颜色通道中,总有一个通道的灰度值很低,几乎趋向于0.基于这个几乎可以视作是定理的先验知识,作者提出暗通道先验的去雾算法. 首 ...
- 基于暗通道先验的单幅图像去雾算法小结
在开始之前,先看一组去雾的效果图. 1. 关于去雾的意义及算法 去雾在视频监控.航拍.遥感.自动/辅助驾驶等需要在室外复杂.恶劣天气下运行的视觉系统,都可能需要运用到这一技术. 目前去雾算法主要有两个 ...
最新文章
- 转:软件设计漫谈之三:30分钟掌握面向对象类的设计原则
- python2.7.13环境搭建
- Netmeeting的四个端口
- java RSA加密解密--转载
- 洛谷P1352 没有上司的舞会(树形DP水题)
- Delphi对话框初始地址InitialDir
- 计算机中复合模板在哪,冷冲模CAD系统中装配模板的设计与复合算法研究-计算机软件专业论文.docx...
- c 子类对象 访问父类对象受保护成员_面向对象三大特征: 继承
- pop3协议auth指令总结
- 动态规划—代码查重实验
- vue中的@click.native.prevent,点击事件加上native.prevent究竟有什么用呢?
- NCA:九岁的已经发起了 DDoS 攻击
- Qt多线程之QtConcurrent
- iOS 9 spotlight搜索 3DTouch
- python 绘图 坐标轴范围 颜色 保存
- Word太大怎么进行压缩?实用Word压缩工具
- 如何解决 Windows 实例出现身份验证错误
- 谷歌应用商店现木马程序、百万WiFi路由器面临漏洞风险|12月6日全球网络安全热点
- OpenCV—python 自动色彩均衡(ACE)
- win10下解决谷歌浏览器点击安装包无反应
热门文章
- [oeasy]python0127_中文系统_gbk_BIG5_南极星_内码转化
- Python中几个非常有趣的模块
- Vue实战项,基于Element-UI 电商管理系统源代码,含项目部署指南
- 关于Unity实现游戏录制功能的思考
- 电脑怎么快捷复制粘贴发送?
- 波动方程有限差分法c语言,一维波动方程有限差分法.doc
- C# 文字转语音遇到的坑(System.Speech)
- mybatis处理map参数取值
- 这个细到把头发丝都抠出来的算法,效果太赞了
- unity实现网络对战游戏