You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

870 lines
26 KiB
C++

/*
This source file contains dehazing construnctor, destructor, and
dehazing functions.
The detailed description of the algorithm is presented
in "http://mcl.korea.ac.kr/projects/dehazing". See also
J.-H. Kim, W.-D. Jang, Y. Park, D.-H. Lee, J.-Y. Sim, C.-S. Kim, "Temporally
coherent real-time video dehazing," in Proc. IEEE ICIP, 2012.
Last updated: 2013-02-06
Author: Jin-Hwan, Kim.
*/
#include "dehazing.h"
dehazing::dehazing(){}
/*
Constructor: dehazing constructor
Parameters:
nW - width of input image
nH - height of input image
bPrevFlag - boolean for temporal cohenrence of video dehazing
bPosFlag - boolean for postprocessing.
*/
dehazing::dehazing(int nW, int nH, bool bPrevFlag, bool bPosFlag)
{
m_nWid = nW;
m_nHei = nH;
// Flags for temporal coherence & post processing
m_bPreviousFlag = bPrevFlag;
m_bPostFlag = bPosFlag;
m_fLambda1 = 5.0f;
m_fLambda2 = 1.0f;
// Transmission estimation block size
m_nTBlockSize = 40;
// Guided filter block size, step size(sampling step), & LookUpTable parameter
m_nGBlockSize = 40;
m_nStepSize = 2;
m_fGSigma = 10.0f;
// to specify the region of atmospheric light estimation
m_nTopLeftX = 0;
m_nTopLeftY = 0;
m_nBottomRightX = m_nWid;
m_nBottomRightY = m_nHei;
m_pfSmallTransP = new float [320*240]; // previous trans. (video only)
m_pfSmallTrans = new float [320*240]; // init trans.
m_pfSmallTransR = new float [320*240]; // refined trans.
m_pnSmallYImg = new int [320*240];
m_pnSmallYImgP = new int [320*240];
m_pfSmallInteg = new float[320*240];
m_pfSmallDenom = new float[320*240];
m_pfSmallY = new float[320*240];
m_pfTransmission = new float [m_nWid*m_nHei];
m_pfTransmissionR = new float[m_nWid*m_nHei];
m_pfTransmissionP = new float[m_nWid*m_nHei];
m_pnYImg = new int [m_nWid*m_nHei];
m_pnYImgP = new int [m_nWid*m_nHei];
m_pfInteg = new float[m_nWid*m_nHei];
m_pfDenom = new float[m_nWid*m_nHei];
m_pfY = new float[m_nWid*m_nHei];
m_pfSmallPk_p = new float[m_nGBlockSize*m_nGBlockSize];
m_pfSmallNormPk = new float[m_nGBlockSize*m_nGBlockSize];
m_pfPk_p = new float[m_nGBlockSize*m_nGBlockSize];
m_pfNormPk = new float[m_nGBlockSize*m_nGBlockSize];
m_pfGuidedLUT = new float[m_nGBlockSize*m_nGBlockSize];
}
/*
Constructor: dehazing constructor using various options
Parameters:
nW - width of input image
nH - height of input image
nTBLockSize - block size for transmission estimation
bPrevFlag - boolean for temporal cohenrence of video dehazing
bPosFlag - boolean for postprocessing
fL1 - information loss cost parameter (regulating)
fL2 - temporal coherence paramter
nGBlock - guided filter block size
*/
dehazing::dehazing(int nW, int nH, int nTBlockSize, bool bPrevFlag, bool bPosFlag, float fL1, float fL2, int nGBlock)
{
m_nWid = nW;
m_nHei = nH;
// Flags for temporal coherence & post processing
m_bPreviousFlag = bPrevFlag;
m_bPostFlag = bPosFlag;
// parameters for each cost (loss cost, temporal coherence cost)
m_fLambda1 = fL1;
m_fLambda2 = fL2;
// block size for transmission estimation
m_nTBlockSize = nTBlockSize;
// Guided filter block size, step size(sampling step), & LookUpTable parameter
m_nGBlockSize = nGBlock;
m_nStepSize = 2;
m_fGSigma = 10.0f;
// to specify the region of atmospheric light estimation
m_nTopLeftX = 0;
m_nTopLeftY = 0;
m_nBottomRightX = m_nWid;
m_nBottomRightY = m_nHei;
m_pfSmallTransP = new float [320*240];
m_pfSmallTrans = new float [320*240];
m_pfSmallTransR = new float [320*240];
m_pnSmallYImg = new int [320*240];
m_pnSmallYImgP = new int [320*240];
m_pnSmallRImg = new int [320*240];
m_pnSmallRImgP = new int [320*240];
m_pnSmallGImg = new int [320*240];
m_pnSmallGImgP = new int [320*240];
m_pnSmallBImg = new int [320*240];
m_pnSmallBImgP = new int [320*240];
m_pfSmallInteg = new float[320*240];
m_pfSmallDenom = new float[320*240];
m_pfSmallY = new float[320*240];
m_pfTransmission = new float [m_nWid*m_nHei];
m_pfTransmissionR = new float[m_nWid*m_nHei];
m_pfTransmissionP = new float[m_nWid*m_nHei];
m_pnYImg = new int [m_nWid*m_nHei];
m_pnYImgP = new int [m_nWid*m_nHei];
m_pnRImg = new int [m_nWid*m_nHei];
m_pnGImg = new int [m_nWid*m_nHei];
m_pnBImg = new int [m_nWid*m_nHei];
m_pnRImgP = new int [m_nWid*m_nHei];
m_pnGImgP = new int [m_nWid*m_nHei];
m_pnBImgP = new int [m_nWid*m_nHei];
m_pfInteg = new float[m_nWid*m_nHei];
m_pfDenom = new float[m_nWid*m_nHei];
m_pfY = new float[m_nWid*m_nHei];
m_pfSmallPk_p = new float[m_nGBlockSize*m_nGBlockSize];
m_pfSmallNormPk = new float[m_nGBlockSize*m_nGBlockSize];
m_pfPk_p = new float[m_nGBlockSize*m_nGBlockSize];
m_pfNormPk = new float[m_nGBlockSize*m_nGBlockSize];
m_pfGuidedLUT = new float[m_nGBlockSize*m_nGBlockSize];
}
dehazing::~dehazing(void)
{
if(m_pfSmallTransP != NULL)
delete [] m_pfSmallTransP;
if(m_pfSmallTrans != NULL)
delete [] m_pfSmallTrans;
if(m_pfSmallTransR != NULL)
delete [] m_pfSmallTransR;
if(m_pnSmallYImg != NULL)
delete [] m_pnSmallYImg;
if(m_pfSmallY != NULL)
delete [] m_pfSmallY;
if(m_pnSmallYImgP != NULL)
delete [] m_pnSmallYImgP;
if(m_pnSmallRImg != NULL)
delete [] m_pnSmallRImg;
if(m_pnSmallRImgP != NULL)
delete [] m_pnSmallRImgP;
if(m_pnSmallGImg != NULL)
delete [] m_pnSmallGImg;
if(m_pnSmallGImgP != NULL)
delete [] m_pnSmallGImgP;
if(m_pnSmallBImg != NULL)
delete [] m_pnSmallBImg;
if(m_pnSmallBImgP != NULL)
delete [] m_pnSmallBImgP;
if(m_pfSmallInteg != NULL)
delete [] m_pfSmallInteg;
if(m_pfSmallDenom != NULL)
delete [] m_pfSmallDenom;
if(m_pfSmallNormPk != NULL)
delete [] m_pfSmallNormPk;
if(m_pfSmallPk_p != NULL)
delete [] m_pfSmallPk_p;
if(m_pnYImg != NULL)
delete [] m_pnYImg;
if(m_pnYImgP != NULL)
delete [] m_pnYImgP;
if(m_pnRImg != NULL)
delete [] m_pnRImg;
if(m_pnGImg != NULL)
delete [] m_pnGImg;
if(m_pnBImg != NULL)
delete [] m_pnBImg;
if(m_pnRImgP != NULL)
delete [] m_pnRImgP;
if(m_pnGImgP != NULL)
delete [] m_pnGImgP;
if(m_pnBImgP != NULL)
delete [] m_pnBImgP;
if(m_pfTransmission != NULL)
delete [] m_pfTransmission;
if(m_pfTransmissionR != NULL)
delete [] m_pfTransmissionR;
if(m_pfTransmissionP != NULL)
delete [] m_pfTransmissionP;
if(m_pfInteg != NULL)
delete [] m_pfInteg;
if(m_pfDenom != NULL)
delete [] m_pfDenom;
if(m_pfY != NULL)
delete [] m_pfY;
if(m_pfPk_p != NULL)
delete [] m_pfPk_p;
if(m_pfNormPk != NULL)
delete [] m_pfNormPk;
if(m_pfGuidedLUT != NULL)
delete [] m_pfGuidedLUT;
m_pfSmallTransP = NULL;
m_pfSmallTrans = NULL;
m_pfSmallTransR = NULL;
m_pnSmallYImg = NULL;
m_pnSmallYImgP = NULL;
m_pnSmallRImg = NULL;
m_pnSmallRImgP = NULL;
m_pnSmallGImg = NULL;
m_pnSmallGImgP = NULL;
m_pnSmallBImg = NULL;
m_pnSmallBImgP = NULL;
m_pfSmallInteg = NULL;
m_pfSmallDenom = NULL;
m_pfSmallY = NULL;
m_pfTransmission = NULL;
m_pfTransmissionR = NULL;
m_pfTransmissionP = NULL;
m_pnYImg = NULL;
m_pnYImgP = NULL;
m_pnRImg = NULL;
m_pnGImg = NULL;
m_pnBImg = NULL;
m_pnRImgP = NULL;
m_pnGImgP = NULL;
m_pnBImgP = NULL;
m_pfInteg = NULL;
m_pfDenom = NULL;
m_pfY = NULL;
m_pfSmallPk_p = NULL;
m_pfSmallNormPk = NULL;
m_pfPk_p = NULL;
m_pfNormPk = NULL;
m_pfGuidedLUT = NULL;
}
/*
Function: AirlightEstimation
Description: estimate the atmospheric light value in a hazy image.
it divides the hazy image into 4 sub-block and selects the optimal block,
which has minimum std-dev and maximum average value.
*Repeat* the dividing process until the size of sub-block is smaller than
pre-specified threshold value. Then, We select the most similar value to
the pure white.
IT IS A RECURSIVE FUNCTION.
Parameter:
imInput - input image (cv iplimage)
Return:
m_anAirlight: estimated atmospheric light value
*/
void dehazing::AirlightEstimation(IplImage* imInput)
{
int nMinDistance = 65536;
int nDistance;
int nX, nY;
Mat R, G, B;
int nMaxIndex;
double dpScore[3];
//double dpMean[3];
Mat dpMean[3];
//double dpStds[3];
Mat dpStds[3];
float afMean[4] = {0};
float afScore[4] = {0};
float nMaxScore = 0;
int nWid = imInput->width;
int nHei = imInput->height;
int nStep = imInput->widthStep;
// 4 sub-block
IplImage *iplUpperLeft = cvCreateImage(cvSize(nWid/2, nHei/2),IPL_DEPTH_8U, 3);
IplImage *iplUpperRight = cvCreateImage(cvSize(nWid/2, nHei/2),IPL_DEPTH_8U, 3);
IplImage *iplLowerLeft = cvCreateImage(cvSize(nWid/2, nHei/2),IPL_DEPTH_8U, 3);
IplImage *iplLowerRight = cvCreateImage(cvSize(nWid/2, nHei/2),IPL_DEPTH_8U, 3);
IplImage *iplR = cvCreateImage(cvSize(nWid/2, nHei/2),IPL_DEPTH_8U, 1);
IplImage *iplG = cvCreateImage(cvSize(nWid/2, nHei/2),IPL_DEPTH_8U, 1);
IplImage *iplB = cvCreateImage(cvSize(nWid/2, nHei/2),IPL_DEPTH_8U, 1);
// divide
cvSetImageROI(imInput, cvRect(0, 0, nWid/2, nHei/2));
cvCopy(imInput, iplUpperLeft);
cvSetImageROI(imInput, cvRect(nWid/2+nWid%2, 0, nWid, nHei/2));
cvCopy(imInput, iplUpperRight);
cvSetImageROI(imInput, cvRect(0, nHei/2+nHei%2, nWid/2, nHei));
cvCopy(imInput, iplLowerLeft);
cvSetImageROI(imInput, cvRect(nWid/2+nWid%2, nHei/2+nHei%2, nWid, nHei));
cvCopy(imInput, iplLowerRight);
// compare to threshold(200) --> bigger than threshold, divide the block
if(nHei*nWid > 200)
{
// compute the mean and std-dev in the sub-block
// upper left sub-block
//cvCvtPixToPlane(iplUpperLeft, iplR, iplG, iplB, 0);
cvSplit(iplUpperLeft, iplR, iplG, iplB, 0);
//cvMean_StdDev(iplR, dpMean, dpStds);
R=cv::cvarrToMat(iplR);
meanStdDev(R, dpMean[0], dpStds[0]);
//cvMean_StdDev(iplG, dpMean+1, dpStds+1);
//cvMean_StdDev(iplB, dpMean+2, dpStds+2);
G=cv::cvarrToMat(iplG);
B=cv::cvarrToMat(iplB);
meanStdDev(G, dpMean[1], dpStds[1]);
meanStdDev(B, dpMean[2], dpStds[2]);
// dpScore: mean - std-dev
dpScore[0] = dpMean[0].at<double>(0,0)-dpStds[0].at<double>(0,0);
dpScore[1] = dpMean[1].at<double>(0,0)-dpStds[1].at<double>(0,0);
dpScore[2] = dpMean[2].at<double>(0,0)-dpStds[2].at<double>(0,0);
afScore[0] = (float)(dpScore[0]+dpScore[1]+dpScore[2]);
nMaxScore = afScore[0];
nMaxIndex = 0;
// upper right sub-block
//cvCvtPixToPlane(iplUpperRight, iplR, iplG, iplB, 0);
cvSplit(iplUpperRight, iplR, iplG, iplB, 0);
// cvMean_StdDev(iplR, dpMean, dpStds);
// cvMean_StdDev(iplG, dpMean+1, dpStds+1);
// cvMean_StdDev(iplB, dpMean+2, dpStds+2);
R=cv::cvarrToMat(iplR);
G=cv::cvarrToMat(iplG);
B=cv::cvarrToMat(iplB);
meanStdDev(R, dpMean[0], dpStds[0]);
meanStdDev(G, dpMean[1], dpStds[1]);
meanStdDev(B, dpMean[2], dpStds[2]);
dpScore[0] = dpMean[0].at<double>(0,0)-dpStds[0].at<double>(0,0);
dpScore[1] = dpMean[1].at<double>(0,0)-dpStds[1].at<double>(0,0);
dpScore[2] = dpMean[2].at<double>(0,0)-dpStds[2].at<double>(0,0);
afScore[1] = (float)(dpScore[0]+dpScore[1]+dpScore[2]);
if(afScore[1] > nMaxScore)
{
nMaxScore = afScore[1];
nMaxIndex = 1;
}
// lower left sub-block
//cvCvtPixToPlane(iplLowerLeft, iplR, iplG, iplB, 0);
cvSplit(iplLowerLeft, iplR, iplG, iplB, 0);
// cvMean_StdDev(iplR, dpMean, dpStds);
// cvMean_StdDev(iplG, dpMean+1, dpStds+1);
// cvMean_StdDev(iplB, dpMean+2, dpStds+2);
R=cv::cvarrToMat(iplR);
G=cv::cvarrToMat(iplG);
B=cv::cvarrToMat(iplB);
meanStdDev(R, dpMean[0], dpStds[0]);
meanStdDev(G, dpMean[1], dpStds[1]);
meanStdDev(B, dpMean[2], dpStds[2]);
dpScore[0] = dpMean[0].at<double>(0,0)-dpStds[0].at<double>(0,0);
dpScore[1] = dpMean[1].at<double>(0,0)-dpStds[1].at<double>(0,0);
dpScore[2] = dpMean[2].at<double>(0,0)-dpStds[2].at<double>(0,0);
afScore[2] = (float)(dpScore[0]+dpScore[1]+dpScore[2]);
if(afScore[2] > nMaxScore)
{
nMaxScore = afScore[2];
nMaxIndex = 2;
}
// lower right sub-block
//cvCvtPixToPlane(iplLowerRight, iplR, iplG, iplB, 0);
cvSplit(iplLowerRight, iplR, iplG, iplB, 0);
// cvMean_StdDev(iplR, dpMean, dpStds);
// cvMean_StdDev(iplG, dpMean+1, dpStds+1);
// cvMean_StdDev(iplB, dpMean+2, dpStds+2);
R=cv::cvarrToMat(iplR);
G=cv::cvarrToMat(iplG);
B=cv::cvarrToMat(iplB);
meanStdDev(R, dpMean[0], dpStds[0]);
meanStdDev(G, dpMean[1], dpStds[1]);
meanStdDev(B, dpMean[2], dpStds[2]);
dpScore[0] = dpMean[0].at<double>(0,0)-dpStds[0].at<double>(0,0);
dpScore[1] = dpMean[1].at<double>(0,0)-dpStds[1].at<double>(0,0);
dpScore[2] = dpMean[2].at<double>(0,0)-dpStds[2].at<double>(0,0);
afScore[3] = (float)(dpScore[0]+dpScore[1]+dpScore[2]);
if(afScore[3] > nMaxScore)
{
nMaxScore = afScore[3];
nMaxIndex = 3;
}
// select the sub-block, which has maximum score
switch (nMaxIndex)
{
case 0:
AirlightEstimation(iplUpperLeft); break;
case 1:
AirlightEstimation(iplUpperRight); break;
case 2:
AirlightEstimation(iplLowerLeft); break;
case 3:
AirlightEstimation(iplLowerRight); break;
}
}
else
{
// select the atmospheric light value in the sub-block
for(nY=0; nY<nHei; nY++)
{
for(nX=0; nX<nWid; nX++)
{
// 255-r, 255-g, 255-b
nDistance = int(sqrt(float(255-(uchar)imInput->imageData[nY*nStep+nX*3])*float(255-(uchar)imInput->imageData[nY*nStep+nX*3])
+float(255-(uchar)imInput->imageData[nY*nStep+nX*3+1])*float(255-(uchar)imInput->imageData[nY*nStep+nX*3+1])
+float(255-(uchar)imInput->imageData[nY*nStep+nX*3+2])*float(255-(uchar)imInput->imageData[nY*nStep+nX*3+2])));
if(nMinDistance > nDistance)
{
nMinDistance = nDistance;
m_anAirlight[0] = (uchar)imInput->imageData[nY*nStep+nX*3];
m_anAirlight[1] = (uchar)imInput->imageData[nY*nStep+nX*3+1];
m_anAirlight[2] = (uchar)imInput->imageData[nY*nStep+nX*3+2];
}
}
}
}
cvReleaseImage(&iplUpperLeft);
cvReleaseImage(&iplUpperRight);
cvReleaseImage(&iplLowerLeft);
cvReleaseImage(&iplLowerRight);
cvReleaseImage(&iplR);
cvReleaseImage(&iplG);
cvReleaseImage(&iplB);
}
/*
Function: RestoreImage
Description: Dehazed the image using estimated transmission and atmospheric light.
Parameter:
imInput - Input hazy image.
Return:
imOutput - Dehazed image.
*/
void dehazing::RestoreImage(IplImage* imInput, IplImage* imOutput)
{
int nStep = imInput->widthStep;
int nX, nY;
float fA_R, fA_G, fA_B;
fA_B = (float)m_anAirlight[0];
fA_G = (float)m_anAirlight[1];
fA_R = (float)m_anAirlight[2];
// post processing flag
if(m_bPostFlag == true)
{
PostProcessing(imInput,imOutput);
}
else
{
#pragma omp parallel for
// (2) I' = (I - Airlight)/Transmission + Airlight
for(nY=0; nY<m_nHei; nY++)
{
for(nX=0; nX<m_nWid; nX++)
{
// (3) Gamma correction using LUT
imOutput->imageData[nY*nStep+nX*3] = (uchar)m_pucGammaLUT[(uchar)CLIP((((float)((uchar)imInput->imageData[nY*nStep+nX*3+0])-fA_B)/CLIP_Z(m_pfTransmissionR[nY*m_nWid+nX]) + fA_B))];
imOutput->imageData[nY*nStep+nX*3+1] = (uchar)m_pucGammaLUT[(uchar)CLIP((((float)((uchar)imInput->imageData[nY*nStep+nX*3+1])-fA_G)/CLIP_Z(m_pfTransmissionR[nY*m_nWid+nX]) + fA_G))];
imOutput->imageData[nY*nStep+nX*3+2] = (uchar)m_pucGammaLUT[(uchar)CLIP((((float)((uchar)imInput->imageData[nY*nStep+nX*3+2])-fA_R)/CLIP_Z(m_pfTransmissionR[nY*m_nWid+nX]) + fA_R))];
}
}
}
}
/*
Function: PostProcessing
Description: deblocking for blocking artifacts of mpeg video sequence.
Parameter:
imInput - Input hazy frame.
Return:
imOutput - Dehazed frame.
*/
void dehazing::PostProcessing(IplImage* imInput, IplImage* imOutput)
{
const int nStep = imInput->widthStep;
const int nNumStep= 10;
const int nDisPos= 20;
float nAD0, nAD1, nAD2;
int nS, nX, nY;
float fA_R, fA_G, fA_B;
fA_B = (float)m_anAirlight[0];
fA_G = (float)m_anAirlight[1];
fA_R = (float)m_anAirlight[2];
#pragma omp parallel for private(nAD0, nAD1, nAD2, nS)
for(nY=0; nY<m_nHei; nY++)
{
for(nX=0; nX<m_nWid; nX++)
{
// (1) I' = (I - Airlight)/Transmission + Airlight
imOutput->imageData[nY*nStep+nX*3] = (uchar)m_pucGammaLUT[(uchar)CLIP((((float)((uchar)imInput->imageData[nY*nStep+nX*3+0])-fA_B)/CLIP_Z(m_pfTransmissionR[nY*m_nWid+nX]) + fA_B))];
imOutput->imageData[nY*nStep+nX*3+1] = (uchar)m_pucGammaLUT[(uchar)CLIP((((float)((uchar)imInput->imageData[nY*nStep+nX*3+1])-fA_G)/CLIP_Z(m_pfTransmissionR[nY*m_nWid+nX]) + fA_G))];
imOutput->imageData[nY*nStep+nX*3+2] = (uchar)m_pucGammaLUT[(uchar)CLIP((((float)((uchar)imInput->imageData[nY*nStep+nX*3+2])-fA_R)/CLIP_Z(m_pfTransmissionR[nY*m_nWid+nX]) + fA_R))];
// if transmission is less than 0.4, we apply post processing because more dehazed block yields more artifacts
if( nX > nDisPos+nNumStep && m_pfTransmissionR[nY*m_nWid+nX-nDisPos] < 0.4 )
{
nAD0 = (float)((int)((uchar)imOutput->imageData[nY*nStep+(nX-nDisPos)*3]) - (int)((uchar)imOutput->imageData[nY*nStep+(nX-nDisPos-1)*3]));
nAD1 = (float)((int)((uchar)imOutput->imageData[nY*nStep+(nX-nDisPos)*3+1]) - (int)((uchar)imOutput->imageData[nY*nStep+(nX-nDisPos-1)*3+1]));
nAD2 = (float)((int)((uchar)imOutput->imageData[nY*nStep+(nX-nDisPos)*3+2]) - (int)((uchar)imOutput->imageData[nY*nStep+(nX-nDisPos-1)*3+2]));
if(max(max(abs(nAD0),abs(nAD1)),abs(nAD2)) < 20
&& abs((uchar)imOutput->imageData[nY*nStep+(nX-nDisPos-1)*3+0]-(uchar)imOutput->imageData[nY*nStep+(nX-nDisPos-1-nNumStep)*3+0])
+abs((uchar)imOutput->imageData[nY*nStep+(nX-nDisPos-1)*3+1]-(uchar)imOutput->imageData[nY*nStep+(nX-nDisPos-1-nNumStep)*3+1])
+abs((uchar)imOutput->imageData[nY*nStep+(nX-nDisPos-1)*3+2]-(uchar)imOutput->imageData[nY*nStep+(nX-nDisPos-1-nNumStep)*3+2])
+abs((uchar)imOutput->imageData[nY*nStep+(nX-nDisPos)*3+0]-(uchar)imOutput->imageData[nY*nStep+(nX-nDisPos-1+nNumStep)*3+0])
+abs((uchar)imOutput->imageData[nY*nStep+(nX-nDisPos)*3+1]-(uchar)imOutput->imageData[nY*nStep+(nX-nDisPos-1+nNumStep)*3+1])
+abs((uchar)imOutput->imageData[nY*nStep+(nX-nDisPos)*3+2]-(uchar)imOutput->imageData[nY*nStep+(nX-nDisPos-1+nNumStep)*3+2]) < 30 )
{
for( nS = 1 ; nS < nNumStep+1; nS++)
{
imOutput->imageData[nY*nStep+(nX-nDisPos-1+nS-nNumStep)*3+0]=(uchar)CLIP((float)((uchar)imOutput->imageData[nY*nStep+(nX-nDisPos-1+nS-nNumStep)*3+0])+(float)nS*nAD0/(float)nNumStep);
imOutput->imageData[nY*nStep+(nX-nDisPos-1+nS-nNumStep)*3+1]=(uchar)CLIP((float)((uchar)imOutput->imageData[nY*nStep+(nX-nDisPos-1+nS-nNumStep)*3+1])+(float)nS*nAD1/(float)nNumStep);
imOutput->imageData[nY*nStep+(nX-nDisPos-1+nS-nNumStep)*3+2]=(uchar)CLIP((float)((uchar)imOutput->imageData[nY*nStep+(nX-nDisPos-1+nS-nNumStep)*3+2])+(float)nS*nAD2/(float)nNumStep);
}
}
}
}
}
}
/*
Function: HazeRemoval
Description: haze removal process
Parameter:
imInput - input image
nFrame - frame number
Return:
imOutput - output image
*/
void dehazing::HazeRemoval(IplImage* imInput, IplImage* imOutput, int nFrame)
{
if(nFrame == 0)
{
IplImage* imAir;
// initializing
MakeExpLUT();
GuideLUTMaker();
GammaLUTMaker(0.7f);
// specify the ROI region of atmospheric light estimation(optional)
cvSetImageROI(imInput, cvRect(m_nTopLeftX, m_nTopLeftY, m_nBottomRightX-m_nTopLeftX, m_nBottomRightY-m_nTopLeftY));
imAir = cvCreateImage(cvSize(m_nBottomRightX-m_nTopLeftX, m_nBottomRightY-m_nTopLeftY),IPL_DEPTH_8U, 3);
cvCopy(imInput, imAir);
AirlightEstimation(imAir);
// Y value of atmosperic light
m_nAirlight = (((int)(uchar)m_anAirlight[0]*25 + (int)(uchar)m_anAirlight[1]*129 + (int)(uchar)m_anAirlight[2]*66 +128) >>8) + 16;
cvReleaseImage(&imAir);
cvResetImageROI(imInput);
}
IplImageToInt(imInput);
// down sampling to fast estimation
DownsampleImage();
// trnasmission estimation
TransmissionEstimation(m_pnSmallYImg,m_pfSmallTrans, m_pnSmallYImgP, m_pfSmallTransP, nFrame, 320, 240);
// store a data for temporal coherent processing
memcpy(m_pfSmallTransP, m_pfSmallTrans, 320*240);
memcpy(m_pnSmallYImgP, m_pnSmallYImg, 320*240);
UpsampleTransmission();
/*
IplImage *test = cvCreateImage(cvSize(320, 240),IPL_DEPTH_8U, 1);
for(int nK = 0; nK < 320*240; nK++)
test->imageData[nK] = (uchar)(m_pnSmallYImg[nK]);
cvNamedWindow("tests");
cvShowImage("tests", test);
cvWaitKey(-1);
*/
FastGuidedFilter();
// (9) 영상 복원 수행
RestoreImage(imInput, imOutput);
}
/*
Function: ImageHazeRemoval
Description: haze removal process for a single image
Parameter:
imInput - input image
Return:
imOutput - output image
*/
void dehazing::ImageHazeRemoval(IplImage* imInput, IplImage* imOutput)
{
IplImage* imAir;
IplImage* imSmallInput;
// look up table creation
MakeExpLUT();
GuideLUTMaker();
GammaLUTMaker(0.7f);
// specify the ROI region of atmospheric light estimation(optional)
cvSetImageROI(imInput, cvRect(m_nTopLeftX, m_nTopLeftY, m_nBottomRightX-m_nTopLeftX, m_nBottomRightY-m_nTopLeftY));
imAir = cvCreateImage(cvSize(m_nBottomRightX-m_nTopLeftX, m_nBottomRightY-m_nTopLeftY),IPL_DEPTH_8U, 3);
imSmallInput = cvCreateImage(cvSize(320, 240), IPL_DEPTH_8U, 3);
cvCopy(imInput, imAir);
AirlightEstimation(imAir);
cvReleaseImage(&imAir);
cvResetImageROI(imInput);
// iplimage to int
IplImageToIntColor(imInput);
TransmissionEstimationColor(m_pnRImg, m_pnGImg, m_pnBImg, m_pfTransmission, m_pnRImg, m_pnGImg, m_pnBImg, m_pfTransmission, 0, m_nWid, m_nHei);
GuidedFilter(m_nWid, m_nHei, 0.001);
//GuidedFilterShiftableWindow(0.001);
/*
IplImage *test = cvCreateImage(cvSize(m_nWid, m_nHei),IPL_DEPTH_8U, 1);
for(int nK = 0; nK < m_nWid*m_nHei; nK++)
test->imageData[nK] = (uchar)(m_pfTransmissionR[nK]*255);
cvNamedWindow("tests");
cvShowImage("tests", test);
cvWaitKey(-1);
*/
// Restore image
RestoreImage(imInput, imOutput);
cvReleaseImage(&imSmallInput);
}
/*
Function:GetAirlight
Return: air light value
*/
int* dehazing::GetAirlight()
{
// (1) airlight값 주소 리턴
return m_anAirlight;
}
/*
Function:GetYImg
Return: get y image array
*/
int* dehazing::GetYImg()
{
// (1) Y영상 주소 리턴
return m_pnYImg;
}
/*
Function:GetTransmission
Return: get refined transmission array
*/
float* dehazing::GetTransmission()
{
// (1) 전달량 주소 리턴
return m_pfTransmissionR;
}
/*
Function:LambdaSetting
chnage labmda values
Parameter:
fLambdaLoss - new weight coefficient for loss cost
fLambdaTemp - new weight coefficient for temp cost
*/
void dehazing::LambdaSetting(float fLambdaLoss, float fLambdaTemp)
{
// (1) 람다값을 재정의 할 때 사용하는 함수
m_fLambda1 = fLambdaLoss;
if(fLambdaTemp>0)
m_fLambda2 = fLambdaTemp;
else
m_bPreviousFlag = false;
}
/*
Function:PreviousFlag
change boolean value
Parameter
bPrevFlag - flag
*/
void dehazing::PreviousFlag(bool bPrevFlag)
{
// (1) 이전 데이터 사용 유무 결정
m_bPreviousFlag = bPrevFlag;
}
/*
Function:TransBlockSize
change the block size of transmission estimation
Parameter:
nBlockSize - new block size
*/
void dehazing::TransBlockSize(int nBlockSize)
{
// (1) 전달량 계산의 블록 크기 결정
m_nTBlockSize = nBlockSize;
}
/*
Function:FilterBlockSize
change the block size of guided filter
Parameter:
nBlockSize - new block size
*/
void dehazing::FilterBlockSize(int nBlockSize)
{
// (1) 전달량 계산의 블록 크기 결정
m_nGBlockSize = nBlockSize;
}
/*
Function:SetFilterStepSize
change the step size of guided filter
Parameter:
nStepSize - new step size
*/
void dehazing::SetFilterStepSize(int nStepSize)
{
// (1) guided filter의 step size 수정
m_nStepSize = nStepSize;
}
/*
Function: AirlightSearchRange
Description: Specify searching range (block shape) by user
Parameter:
pointTopLeft - the top left point of searching block
pointBottomRight - the bottom right point of searching block.
Return:
m_nTopLeftX - integer x point
m_nTopLeftY - integer y point
m_nBottomRightX - integer x point
m_nBottomRightY - integer y point.
*/
void dehazing::AirlightSerachRange(POINT pointTopLeft, POINT pointBottomRight)
{
m_nTopLeftX = pointTopLeft.x;
m_nTopLeftY = pointTopLeft.y;
m_nBottomRightX = pointBottomRight.x;
m_nBottomRightY = pointBottomRight.y;
}
/*
Function: FilterSigma
Description: change the gaussian sigma value
Parameter:
nSigma
*/
void dehazing::FilterSigma(float nSigma)
{
m_fGSigma = nSigma;
}
/*
Function: Decision
Description: Decision function for re-estimation of atmospheric light
in this file, we just implement the decision function and don't
apply the decision algorithm in the dehazing function.
Parameter:
imSrc1 - first frame
imSrc2 - second frame
nThreshold - threshold value
Return:
boolean value
*/
bool dehazing::Decision(IplImage* imSrc1, IplImage* imSrc2, int nThreshold)
{
int nX, nY;
int nStep;
int nMAD;
nMAD = 0;
nStep = imSrc1->widthStep;
if(imSrc2->widthStep != nStep)
{
cout << "Size of src1 and src2 is not the same" << endl;
exit(1);
}
for(nY=0; nY<m_nHei; nY++)
{
for(nX=0; nX<m_nWid; nX++)
{
nMAD += abs((int)imSrc1->imageData[nY*nStep+nX*3+2]-(int)imSrc2->imageData[nY*nStep+nX*3+2]);
nMAD += abs((int)imSrc1->imageData[nY*nStep+nX*3+1]-(int)imSrc2->imageData[nY*nStep+nX*3+1]);
nMAD += abs((int)imSrc1->imageData[nY*nStep+nX*3+0]-(int)imSrc2->imageData[nY*nStep+nX*3+0]);
}
}
nMAD /= (m_nWid*m_nHei);
if(nMAD > nThreshold)
return true;
else
return false;
}