标签:出现 mat 自适应 固定 otto lte 超出 float 遇到
我使用了导向图滤波来计算折射率t,而在opencv中,要使用它需要在一开始就采用编译安装增加contrib模块。
何凯明博士提出了“暗通道”的说法,他发现色彩明亮没有雾的图像其暗通道几乎“全是黑的”
而有雾的图像由于雾提高了图像的颜色,其暗通道就“不全是黑的”
而公式推导及计算网上很多博客都有写,我主要说一下我遇到的一些问题
一开始尝试了许多代码,但都一致地会出现色斑及图像失真问题,后来查询了许多资料发现是t的计算问题,由于对t设置了阈值min_t,而在实际计算中如果t大于min_t,那么此点的t就设置为min_t,就会导致图像中部分像素点使用一样的t值,出现较多的色斑色偏
我发现A与min_t并不能采用一个固定的值,对于不同的图片,如果想要效果较好,那么就得对A与min_t进行微调
以下是实现代码:
// // Created by swenw on 2019/10/30. // Copyright © 2019 swenw. All rights reserved. // #include <opencv2/opencv.hpp> #include <opencv2/ximgproc/edge_filter.hpp> using namespace cv; using namespace std; const float kernRatio=0.01; //自适应核比例 const float w=0.95; //w系数 用来调节 const float min_t =0.5; //最小透射率 void minFilter(Mat src, Mat &dst, int ksize); int main(int argc, char *argv[]) { Mat src = imread("/Users/swenw/Documents/数字媒体技术/Image/3.png"); imshow("src",src); //最小RGB Mat minRgb = Mat::zeros(src.rows,src.cols,CV_8UC1); for(int i=0;i<src.rows;i++){ for(int j=0;j<src.cols;j++) { uchar g_minvalue =255; for(int c=0;c<3;c++) { if(g_minvalue>src.at<Vec3b>(i,j)[c]) g_minvalue=src.at<Vec3b>(i,j)[c]; } minRgb.at<uchar>(i,j)=g_minvalue; } } //对RGB进行最小值滤波,获得暗通道 Mat darkChannel; int ksize=max(3,max((int)(src.cols*kernRatio),(int)(src.rows*kernRatio))); minFilter(minRgb, darkChannel, ksize); //求大气A,A为含雾图像的像素的最大值 double A; Point maxLoc; minMaxLoc(darkChannel, 0, 0, 0, &maxLoc); A=max(src.at<Vec3b>(maxLoc.y,maxLoc.x)[0], max(src.at<Vec3b>(maxLoc.y,maxLoc.x)[1], src.at<Vec3b>(maxLoc.y,maxLoc.x)[2])); //求透射率t=1-w*(darkChannel/A) //当I非常接近于A时,t会非常的小,t<mint_t,于是会出现比较多的色斑色偏 //对t进行修正, Mat trans=Mat::zeros(src.rows,src.cols,CV_32FC1); uchar pix[3]; for(int i=0; i<src.rows; i++){ const uchar* inData = darkChannel.ptr<uchar>(i); const uchar* srcData = src.ptr<uchar>(i); float* outData = trans.ptr<float>(i); for(int j=0; j<src.cols; j++){ pix[0]=*srcData++; pix[1]=*srcData++; pix[2]=*srcData++; uchar t=fabs((pix[0]+pix[1]+pix[2])/3.0-A); if(t<min_t) //当像素接近于大气光强时,加一个增幅量,使其不总比min_t小 *outData++=1-w*(*inData++/A)+(min_t-t)/min_t; else *outData++=1-w*(*inData++/A); } } Mat t = Mat::zeros(src.rows,src.cols,CV_32FC1); //导向图滤波 ximgproc::guidedFilter(src, trans, t, 0.25, 0.001); imshow("t", t); //J=(I-A)/max(t,min_t)+A Mat deFog=Mat::zeros(src.rows,src.cols,CV_8UC3); for(int i=0;i<src.rows;i++){ for(int j=0;j<src.cols;j++){ for(int k=0;k<src.channels();k++){ deFog.at<Vec3b>(i,j)[k]=saturate_cast<uchar>((src.at<Vec3b>(i,j)[k]-A)/max(t.at<float>(i,j), min_t)+A); } } } imshow("defog",deFog); while(char(waitKey(1))!=‘q‘){} } void minFilter(const Mat src,Mat &dst,int ksize) { if(src.channels()!=1) return; if(src.depth()>8) return; int r=(ksize-1)/2; //核半径 dst=Mat::zeros(src.rows,src.cols,CV_8UC1); for(int i=0; i<src.rows; i++){ for(int j=0; j<src.cols; j++) { //初始化滤波核的上下左右边界 int top=i-r; int bottom=i+r; int left=j-r; int right=j+r; //检查滤波核是否超出边界 if(i-r<0) top=0; if(i+r>src.rows) bottom=src.rows; if(j-r<0) left=0; if(j+r>src.cols) right=src.cols; //求取模板下的最小值 Mat ImROI=src(Range(top,bottom),Range(left,right)); double min; minMaxLoc(ImROI, &min, 0, 0, 0); dst.at<uchar>(i,j)=min; } } }
由于最小值滤波带来的影响,会在图像的边缘出现透明的边框问题,而导向图滤波就是为了消除这一问题,但让我疑惑的是我的导向图滤波并没有达到很好的效果(如上图,透明边框很明显)
而使透明边框缩小一点的方法就是尽量的减小最小值滤波的滤波核,如改为3*3,而不是采用自适应滤波核,此时的效果会好一点
我的数媒老师说在测试的时候尽量不要找有水或有天的图片,因为会对最终效果带来影响,我也发现如果不改进t的计算,这类图片的色偏和色差是最大的
关于何凯明博士的方法计算后,得到的图片颜色会“偏暗”……
标签:出现 mat 自适应 固定 otto lte 超出 float 遇到
原文地址:https://www.cnblogs.com/swenw/p/12245013.html