|
|
|
|
#include "stdafx.h"
|
|
|
|
|
#include "DarkChannelDehaze.h"
|
|
|
|
|
|
|
|
|
|
DarkChannelDehaze::DarkChannelDehaze(void):block(7),w(0.9)
|
|
|
|
|
{
|
|
|
|
|
ROI_rect.x = 0;
|
|
|
|
|
ROI_rect.y = 0;
|
|
|
|
|
double min_channel1 = 0;
|
|
|
|
|
double min_channel2 = 0;
|
|
|
|
|
double min_channel3 = 0;
|
|
|
|
|
double max_channel1 = 0;
|
|
|
|
|
double max_channel2 = 0;
|
|
|
|
|
double max_channel3 = 0;
|
|
|
|
|
double min = 0;
|
|
|
|
|
|
|
|
|
|
double A_final = 10;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DarkChannelDehaze::~DarkChannelDehaze(void)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DarkChannelDehaze::doDehaze( const Mat& src, Mat& dst )
|
|
|
|
|
{
|
|
|
|
|
dcc.setTo(cv::Scalar::all(0));
|
|
|
|
|
cv::split(src, dsts);
|
|
|
|
|
ROI_rect.width = block;
|
|
|
|
|
ROI_rect.height = block;
|
|
|
|
|
|
|
|
|
|
Mat Vm, Vop,Vnorm;
|
|
|
|
|
uchar pixel;
|
|
|
|
|
cv::Scalar e2x,ex2;
|
|
|
|
|
cv::Rect meanRect;
|
|
|
|
|
meanRect.width = 5;
|
|
|
|
|
meanRect.height = 5;
|
|
|
|
|
Vm.create(src.size(), CV_8UC1);
|
|
|
|
|
Vm.setTo(cv::Scalar::all(0));
|
|
|
|
|
for(int i = 0;i<src.rows;i++)
|
|
|
|
|
{
|
|
|
|
|
for(int j = 0;j<src.cols;j++)
|
|
|
|
|
{
|
|
|
|
|
pixel = min(dsts[1].at<uchar>(i,j),dsts[0].at<uchar>(i,j));
|
|
|
|
|
pixel = min(pixel,dsts[2].at<uchar>(i,j));
|
|
|
|
|
Vm.at<uchar>(i,j) = pixel;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Vnorm = Vm.clone();
|
|
|
|
|
Sobel(Vm,Vop,-1,1,1,3,1,0,BORDER_DEFAULT);
|
|
|
|
|
Mat element = getStructuringElement(MORPH_RECT,Size(15, 15));
|
|
|
|
|
morphologyEx(Vm,Vnorm,MORPH_OPEN,element);
|
|
|
|
|
normalize(Vop, Vop, 255,0,NORM_MINMAX);
|
|
|
|
|
|
|
|
|
|
for(int row = 0;row<src.rows;row++)
|
|
|
|
|
{
|
|
|
|
|
for(int col = 0;col<src.cols;col++)
|
|
|
|
|
{
|
|
|
|
|
dcc.at<uchar>(row,col) = (Vm.at<uchar>(row,col)*Vop.at<uchar>(row,col)+Vnorm.at<uchar>(row,col)*(255-Vop.at<uchar>(row,col)))/255;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Adcc = dcc.clone();
|
|
|
|
|
|
|
|
|
|
cv::Point minloc, maxloc;
|
|
|
|
|
cv::minMaxLoc(Adcc, &min_dark, &max_dark, &minloc, &maxloc);
|
|
|
|
|
ROI_rect.x = maxloc.x;
|
|
|
|
|
ROI_rect.y = maxloc.y;
|
|
|
|
|
ROI_rect.width = block;
|
|
|
|
|
ROI_rect.height = block;
|
|
|
|
|
ROI_rect = ROI_rect&(cv::Rect(0, 0, src.cols, src.rows));
|
|
|
|
|
|
|
|
|
|
imgroi1 = dsts[0](ROI_rect).clone();
|
|
|
|
|
|
|
|
|
|
cv::minMaxLoc(imgroi1, &dst1_min, &A_dst1, NULL, NULL);
|
|
|
|
|
|
|
|
|
|
imgroi2 = dsts[1](ROI_rect).clone();
|
|
|
|
|
|
|
|
|
|
cv::minMaxLoc(imgroi2, &dst2_min, &A_dst2, NULL, NULL);
|
|
|
|
|
|
|
|
|
|
imgroi3 = dsts[2](ROI_rect).clone();
|
|
|
|
|
|
|
|
|
|
cv::minMaxLoc(imgroi3, &dst3_min, &A_dst3, NULL, NULL);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ((src.cols<=100)&&(src.rows<=100))
|
|
|
|
|
{
|
|
|
|
|
double td = 20;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
td = 120;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(A_dst1 > A_dst2)
|
|
|
|
|
Amax = A_dst1;
|
|
|
|
|
else
|
|
|
|
|
Amax = A_dst2;
|
|
|
|
|
if(Amax > A_dst3)
|
|
|
|
|
Amax = A_dst3;
|
|
|
|
|
A1 = abs(Amax - A_final);
|
|
|
|
|
|
|
|
|
|
if (A1 >= td)
|
|
|
|
|
|
|
|
|
|
A_final = Amax;
|
|
|
|
|
|
|
|
|
|
#pragma omp parallel for
|
|
|
|
|
for (int row = 0; row < src.rows; row++)
|
|
|
|
|
{
|
|
|
|
|
for (int col = 0; col < src.cols; col++)
|
|
|
|
|
{
|
|
|
|
|
toushelv.at<uchar>(row, col) = static_cast<uchar>((1.0 - w * dcc.at<uchar>(row, col)/A_final) * 255.0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
int gfresize = 4;
|
|
|
|
|
cv::resize(toushelv, dstpinghua,cv::Size(src.cols/gfresize, src.rows/gfresize));
|
|
|
|
|
cv::resize(src, Ihalf, cv::Size(src.cols/gfresize, src.rows/gfresize));
|
|
|
|
|
|
|
|
|
|
pinghua = guidedFilter(Ihalf, dstpinghua, 7, 0.01);
|
|
|
|
|
|
|
|
|
|
double sumtxd = 0;
|
|
|
|
|
for (int row = 0; row < dst.rows; row++)
|
|
|
|
|
{
|
|
|
|
|
for (int col = 0; col < dst.cols; col++)
|
|
|
|
|
{
|
|
|
|
|
sumtxd = sumtxd + pinghua.at<double>(row/gfresize, col/gfresize);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
double avetxd = sumtxd/(dst.rows * dst.cols);
|
|
|
|
|
double adjust = 1.5 * avetxd * A_final;
|
|
|
|
|
|
|
|
|
|
//<2F><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>ͼ<EFBFBD><CDBC>
|
|
|
|
|
#pragma omp parallel for
|
|
|
|
|
for (int row = 0; row < dst.rows; row++)
|
|
|
|
|
{
|
|
|
|
|
for (int col = 0; col < dst.cols; col++)
|
|
|
|
|
{
|
|
|
|
|
double txd;
|
|
|
|
|
txd = pinghua.at<double>(row/gfresize, col/gfresize);//
|
|
|
|
|
txd = txd/255.0;
|
|
|
|
|
if(txd < 0.1)
|
|
|
|
|
txd = 0.1;
|
|
|
|
|
const cv::Vec3b& ixv = src.at<cv::Vec3b>(row, col);
|
|
|
|
|
|
|
|
|
|
double v1 = (((double)(ixv.val[0]) - A_final)/txd + A_final);
|
|
|
|
|
double v2 = (((double)(ixv.val[1]) - A_final)/txd + A_final);
|
|
|
|
|
double v3 = (((double)(ixv.val[2]) - A_final)/txd + A_final);
|
|
|
|
|
v1 = (v1 * (255 + adjust))/(v1 + adjust);
|
|
|
|
|
v2 = (v2 * (255 + adjust))/(v2 + adjust);
|
|
|
|
|
v3 = (v3 * (255 + adjust))/(v3 + adjust);
|
|
|
|
|
v1 = v1<1.0?1.0:v1>254.0?254:v1;
|
|
|
|
|
v2 = v2<1.0?1.0:v2>254.0?254:v2;
|
|
|
|
|
v3 = v3<1.0?1.0:v3>254.0?254:v3;
|
|
|
|
|
cv::Vec3d val(v1, v2, v3);
|
|
|
|
|
dst.at<cv::Vec3b>(row, col) = val;//cv::Vec3b(txd*255,txd*255,txd*255);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cv::Mat DarkChannelDehaze::calDev(Mat src, Rect meanRect)
|
|
|
|
|
{
|
|
|
|
|
int sum_value,sum_value2;
|
|
|
|
|
double e1,e2;
|
|
|
|
|
Mat Vop;
|
|
|
|
|
|
|
|
|
|
#pragma omp parallel for
|
|
|
|
|
for(int ii = 0;ii<src.rows-meanRect.width;ii++)
|
|
|
|
|
{
|
|
|
|
|
for(int jj = 0;jj<src.cols-meanRect.height;jj++)
|
|
|
|
|
{
|
|
|
|
|
meanRect.x = jj;
|
|
|
|
|
meanRect.y = ii;
|
|
|
|
|
sum_value = 0;
|
|
|
|
|
sum_value2 = 0;
|
|
|
|
|
e1 = 0.0;
|
|
|
|
|
e2 = 0.0;
|
|
|
|
|
for (int i = 0;i<meanRect.width;i++)
|
|
|
|
|
{
|
|
|
|
|
for (int j = 0;j<meanRect.height;j++)
|
|
|
|
|
{
|
|
|
|
|
sum_value += src(meanRect).at<uchar>(i,j);
|
|
|
|
|
sum_value2 += src(meanRect).at<uchar>(i,j)*src(meanRect).at<uchar>(i,j);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
e1 = sum_value/(meanRect.width*meanRect.height);
|
|
|
|
|
e2 = sum_value2/(meanRect.width*meanRect.height);
|
|
|
|
|
Vop.create(src.size(), CV_32FC1);
|
|
|
|
|
Vop.setTo(cv::Scalar::all(0.0));
|
|
|
|
|
|
|
|
|
|
Vop.at<float>(ii,jj) = static_cast<float>(e2 - e1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
normalize(Vop,Vop,255.0,0.0,NORM_MINMAX);
|
|
|
|
|
return Vop;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DarkChannelDehaze::calcDarkChannel( const Mat& src, Mat& dark )
|
|
|
|
|
{
|
|
|
|
|
std::vector<Mat> rgbs;
|
|
|
|
|
cv::split(src, rgbs);
|
|
|
|
|
|
|
|
|
|
int totalrow = ((src.rows)/block);
|
|
|
|
|
totalrow += ((src.rows) % block == 0 ? 0 : 1);
|
|
|
|
|
int totalcol = ((src.cols) / block);
|
|
|
|
|
totalcol += ((src.cols) % block == 0)?0:1;
|
|
|
|
|
Mat block_dark = Mat(totalrow, totalcol, CV_8UC1);
|
|
|
|
|
block_dark.setTo(cv::Scalar::all(0));
|
|
|
|
|
cv::Rect imgRect(0, 0, src.cols, src.rows);
|
|
|
|
|
|
|
|
|
|
#pragma omp parallel for
|
|
|
|
|
for (int row = 0; row < totalrow; row++)
|
|
|
|
|
{
|
|
|
|
|
for (int col = 0;col < totalcol;col++)
|
|
|
|
|
{
|
|
|
|
|
cv::Rect block_rect(col*block, row*block, block, block);
|
|
|
|
|
block_rect = block_rect&imgRect;
|
|
|
|
|
cv::Vec3d mins, maxs;
|
|
|
|
|
for (size_t i = 0;i < rgbs.size();i++)
|
|
|
|
|
{
|
|
|
|
|
cv::minMaxLoc(rgbs[i](block_rect), mins.val + i, maxs.val + i, NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uchar min = 0;
|
|
|
|
|
if(mins.val[0] < mins.val[1])
|
|
|
|
|
{
|
|
|
|
|
min = static_cast<uchar>(mins.val[0]);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
min = static_cast<uchar>(mins.val[1]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(min > mins.val[2])
|
|
|
|
|
{
|
|
|
|
|
min = static_cast<uchar>(mins.val[2]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
block_dark.at<uchar>(row,col) = min;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dark.create(src.size(), CV_8UC1);
|
|
|
|
|
dark.setTo(cv::Scalar::all(0));
|
|
|
|
|
|
|
|
|
|
#pragma omp parallel for
|
|
|
|
|
for (int row = 0; row < dark.rows; row++)
|
|
|
|
|
{
|
|
|
|
|
for (int col = 0; col < dark.cols; col++)
|
|
|
|
|
{
|
|
|
|
|
int rrow = row/block;
|
|
|
|
|
int rcol = col/block;
|
|
|
|
|
dark.at<uchar>(row, col) = block_dark.at<uchar>(rrow, rcol);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DarkChannelDehaze::Init(int width, int height)
|
|
|
|
|
{
|
|
|
|
|
dcc.create(height, width, CV_8UC1);
|
|
|
|
|
toushelv.create(height, width, CV_8UC1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cv::Mat DarkChannelDehaze::guidedFilter( cv::Mat I, cv::Mat ip, int rid, double eps )
|
|
|
|
|
{
|
|
|
|
|
cv::Mat _I;
|
|
|
|
|
cv::Mat _ip;
|
|
|
|
|
cvtColor(I, _I, CV_BGR2GRAY);
|
|
|
|
|
_I.convertTo(I, CV_64FC1);
|
|
|
|
|
ip.convertTo(_ip, CV_64FC1);
|
|
|
|
|
ip = _ip;
|
|
|
|
|
|
|
|
|
|
int hei = I.rows;
|
|
|
|
|
int wid = I.cols;
|
|
|
|
|
|
|
|
|
|
cv::Mat N;
|
|
|
|
|
cv::boxFilter(cv::Mat::ones(hei, wid, I.type()), N, CV_64FC1, cv::Size(rid, rid));
|
|
|
|
|
|
|
|
|
|
cv::Mat mean_I;
|
|
|
|
|
cv::boxFilter(I, mean_I, CV_64FC1, cv::Size(rid, rid));
|
|
|
|
|
|
|
|
|
|
cv::Mat mean_p;
|
|
|
|
|
cv::boxFilter(ip, mean_p, CV_64FC1, cv::Size(rid, rid));
|
|
|
|
|
|
|
|
|
|
cv::Mat mean_Ip;
|
|
|
|
|
cv::boxFilter(I.mul(ip), mean_Ip, CV_64FC1, cv::Size(rid, rid));
|
|
|
|
|
|
|
|
|
|
cv::Mat cov_Ip = mean_Ip - mean_I.mul(mean_p);
|
|
|
|
|
|
|
|
|
|
cv::Mat mean_II;
|
|
|
|
|
cv::boxFilter(I.mul(I), mean_II, CV_64FC1, cv::Size(rid, rid));
|
|
|
|
|
|
|
|
|
|
cv::Mat var_I = mean_II - mean_I.mul(mean_I);
|
|
|
|
|
cv::Mat amask = cov_Ip/(var_I + eps);
|
|
|
|
|
|
|
|
|
|
cv::Mat bmask = mean_p - amask.mul(mean_I);
|
|
|
|
|
|
|
|
|
|
cv::Mat mean_a;
|
|
|
|
|
cv::boxFilter(amask, mean_a, CV_64FC1, cv::Size(rid, rid));
|
|
|
|
|
mean_a = mean_a/N;
|
|
|
|
|
|
|
|
|
|
cv::Mat mean_b;
|
|
|
|
|
cv::boxFilter(bmask, mean_b, CV_64FC1, cv::Size(rid, rid));
|
|
|
|
|
mean_a = mean_a/N;
|
|
|
|
|
|
|
|
|
|
cv::Mat pinghua = mean_a.mul(I) + mean_b;
|
|
|
|
|
|
|
|
|
|
return pinghua;
|
|
|
|
|
}
|