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.

1288 lines
38 KiB
C++

/*
The original guided filter is just converted version of He et al.'s matlab code
The detailed description of the code and the algorithm is presented
in "http://research.microsoft.com/en-us/um/people/kahe/eccv10/index.html"
The fast guided filter is approximated filter to reduce the computational
complexity of filtering. We only apply the filter to sampled points. The
similar works are presented in the paper, J.-Y. Kim, L.-S. Kim, S.-H. Hwang,
"An advanced contrast enhancement using partially overlapped subblock
histogram equalization," IEEE Trans. Circuits and Syst. Video Technol.
11 (4) (2001) 475-484. Also, at each window, the gussian weight is applied.
The guided filter with shiftable window is the enhanced algorithm of original
guided image filtering by shifting the filter window.
Last updated: 2013-02-06
Author: Jin-Hwan, Kim.
*/
#include "dehazing.h"
/*
Function: CalcAcoeff
Description: calculate the coefficent "a" of guided filter (intrinsic function for guide filtering)
Parameters:
pfSigma - Sigma + eps * eye(3) --> see the paper and original matlab code
pfCov - Cov of image
nIdx - location of image(index).
Return:
pfA1, pfA2, pfA3 - coefficient of "a" at each color channel
*/
void dehazing::CalcAcoeff(float* pfSigma, float* pfCov, float* pfA1, float* pfA2, float* pfA3, int nIdx)
{
float fDet;
float fOneOverDeterminant;
float pfInvSig[9];
int nIdx9 = nIdx*9;
// a_k = (sum_i(I_i*p_i-mu_k*p_k)/(abs(omega)*(sigma_k^2+epsilon))
fDet = ( (pfSigma[nIdx9]*(pfSigma[nIdx9+4] * pfSigma[nIdx9+8] - pfSigma[nIdx9+5] * pfSigma[nIdx9+7]))
- ( pfSigma[nIdx9+1]*(pfSigma[nIdx9+3] * pfSigma[nIdx9+8] - pfSigma[nIdx9+5] * pfSigma[nIdx9+6]))
+ ( pfSigma[nIdx9+2]*(pfSigma[nIdx9+3] * pfSigma[nIdx9+7] - pfSigma[nIdx9+4] * pfSigma[nIdx9+6])) );
fOneOverDeterminant = 1.0f/fDet;
pfInvSig [0] = (( pfSigma[nIdx9+4]*pfSigma[nIdx9+8] ) - (pfSigma[nIdx9+5]*pfSigma[nIdx9+7]))*fOneOverDeterminant;
pfInvSig [1] = -(( pfSigma[nIdx9+1]*pfSigma[nIdx9+8] ) - (pfSigma[nIdx9+2]*pfSigma[nIdx9+7]))*fOneOverDeterminant;
pfInvSig [2] = (( pfSigma[nIdx9+1]*pfSigma[nIdx9+5] ) - (pfSigma[nIdx9+2]*pfSigma[nIdx9+4]))*fOneOverDeterminant;
pfInvSig [3] = -(( pfSigma[nIdx9+3]*pfSigma[nIdx9+8] ) - (pfSigma[nIdx9+5]*pfSigma[nIdx9+6]))*fOneOverDeterminant;
pfInvSig [4] = (( pfSigma[nIdx9]*pfSigma[nIdx9+8] ) - (pfSigma[nIdx9+2]*pfSigma[nIdx9+6]))*fOneOverDeterminant;
pfInvSig [5] = -(( pfSigma[nIdx9]*pfSigma[nIdx9+5] ) - (pfSigma[nIdx9+2]*pfSigma[nIdx9+3]))*fOneOverDeterminant;
pfInvSig [6] = (( pfSigma[nIdx9+3]*pfSigma[nIdx9+7] ) - (pfSigma[nIdx9+4]*pfSigma[nIdx9+6]))*fOneOverDeterminant;
pfInvSig [7] = -(( pfSigma[nIdx9]*pfSigma[nIdx9+7] ) - (pfSigma[nIdx9+1]*pfSigma[nIdx9+6]))*fOneOverDeterminant;
pfInvSig [8] = (( pfSigma[nIdx9]*pfSigma[nIdx9+4] ) - (pfSigma[nIdx9+1]*pfSigma[nIdx9+3]))*fOneOverDeterminant;
int nIdx3 = nIdx*3;
pfA1[nIdx] = pfCov[nIdx3]*pfInvSig[0]+pfCov[nIdx3+1]*pfInvSig[3]+pfCov[nIdx3+2]*pfInvSig[6];
pfA2[nIdx] = pfCov[nIdx3]*pfInvSig[1]+pfCov[nIdx3+1]*pfInvSig[4]+pfCov[nIdx3+2]*pfInvSig[7];
pfA3[nIdx] = pfCov[nIdx3]*pfInvSig[2]+pfCov[nIdx3+1]*pfInvSig[5]+pfCov[nIdx3+2]*pfInvSig[8];
}
/*
Function: BoxFilter
Description: cummulative function for calculating the integral image (It may apply other arraies.)
Parameters:
pfInArray - input array
nR - radius of filter window
nWid - width of array
nHei - height of array
Return:
fOutArray - output array (integrated array)
*/
void dehazing::BoxFilter(float* pfInArray, int nR, int nWid, int nHei, float*& fOutArray)
{
float* pfArrayCum = new float[nWid*nHei];
//cumulative sum over Y axis
for ( int nX = 0; nX < nWid; nX++ )
pfArrayCum[nX] = pfInArray[nX];
for ( int nIdx = nWid; nIdx <nWid*nHei; nIdx++ )
pfArrayCum[nIdx] = pfArrayCum[nIdx-nWid] + pfInArray[nIdx];
//difference over Y axis
for ( int nIdx = 0; nIdx < nWid*(nR+1); nIdx++)
fOutArray[nIdx] = pfArrayCum[nIdx+nR*nWid];
for ( int nIdx = (nR+1)*nWid; nIdx < (nHei-nR)*nWid; nIdx++ )
fOutArray[nIdx] = pfArrayCum[nIdx+nR*nWid] - pfArrayCum[nIdx-nR*nWid-nWid];
for ( int nY = nHei-nR; nY < nHei; nY++ )
for ( int nX = 0; nX < nWid; nX++ )
fOutArray[nY*nWid+nX] = pfArrayCum[(nHei-1)*nWid+nX] - pfArrayCum[(nY-nR-1)*nWid+nX];
//cumulative sum over X axis
for ( int nIdx = 0; nIdx < nHei*nWid; nIdx += nWid )
pfArrayCum[nIdx] = fOutArray[nIdx];
for ( int nY = 0; nY < nHei*nWid; nY+=nWid )
for ( int nX = 1; nX < nWid; nX++ )
pfArrayCum[nY+nX] = pfArrayCum[nY+nX-1]+fOutArray[nY+nX];
//difference over Y axis
for ( int nY = 0; nY < nHei*nWid; nY+=nWid )
for ( int nX = 0; nX < nR+1; nX++ )
fOutArray[nY+nX] = pfArrayCum[nY+nX+nR];
for ( int nY = 0; nY < nHei*nWid; nY+=nWid )
for ( int nX = nR+1; nX < nWid-nR; nX++ )
fOutArray[nY+nX] = pfArrayCum[nY+nX+nR] - pfArrayCum[nY+nX-nR-1];
for ( int nY = 0; nY < nHei*nWid; nY+=nWid )
for ( int nX = nWid-nR; nX < nWid; nX++ )
fOutArray[nY+nX] = pfArrayCum[nY+nWid-1] - pfArrayCum[nY+nX-nR-1];
delete []pfArrayCum;
}
/*
Function: BoxFilter (for 3D array)
Description: cummulative function for calculating the integral image (It may apply other arraies.)
Parameters:
pfInArray1 - input array D1
pfInArray2 - input array D2
pfInArray3 - input array D3
nR - radius of filter window
nWid - width of array
nHei - height of array
Return:
fOutArray1 - output array D1(integrated array)
fOutArray1 - output array D2(integrated array)
fOutArray1 - output array D3(integrated array)
*/
void dehazing::BoxFilter(float* pfInArray1, float* pfInArray2, float* pfInArray3, int nR, int nWid, int nHei, float*& pfOutArray1, float*& pfOutArray2, float*& pfOutArray3)
{
float* pfArrayCum1 = new float[nWid*nHei];
float* pfArrayCum2 = new float[nWid*nHei];
float* pfArrayCum3 = new float[nWid*nHei];
//cumulative sum over Y axis
for ( int nX = 0; nX < nWid; nX++ )
{
pfArrayCum1[nX] = pfInArray1[nX];
pfArrayCum2[nX] = pfInArray2[nX];
pfArrayCum3[nX] = pfInArray3[nX];
}
for ( int nIdx = nWid; nIdx < nHei*nWid; nIdx++ )
{
pfArrayCum1[nIdx] = pfArrayCum1[nIdx-nWid]+pfInArray1[nIdx];
pfArrayCum2[nIdx] = pfArrayCum2[nIdx-nWid]+pfInArray2[nIdx];
pfArrayCum3[nIdx] = pfArrayCum3[nIdx-nWid]+pfInArray3[nIdx];
}
//difference over Y axis
for ( int nIdx = 0; nIdx < (nR+1)*nWid; nIdx++ )
{
pfOutArray1[nIdx] = pfArrayCum1[nIdx+nR*nWid];
pfOutArray2[nIdx] = pfArrayCum2[nIdx+nR*nWid];
pfOutArray3[nIdx] = pfArrayCum3[nIdx+nR*nWid];
}
for ( int nIdx = (nR+1)*nWid; nIdx < (nHei-nR)*nWid; nIdx++ )
{
pfOutArray1[nIdx] = pfArrayCum1[nIdx+nR*nWid] - pfArrayCum1[nIdx-(nR+1)*nWid];
pfOutArray2[nIdx] = pfArrayCum2[nIdx+nR*nWid] - pfArrayCum2[nIdx-(nR+1)*nWid];
pfOutArray3[nIdx] = pfArrayCum3[nIdx+nR*nWid] - pfArrayCum3[nIdx-(nR+1)*nWid];
}
for ( int nY = nHei-nR; nY < nHei; nY++ )
{
for ( int nX = 0; nX < nWid; nX++ )
{
pfOutArray1[nY*nWid+nX] = pfArrayCum1[(nHei-1)*nWid+nX] - pfArrayCum1[(nY-nR-1)*nWid+nX];
pfOutArray2[nY*nWid+nX] = pfArrayCum2[(nHei-1)*nWid+nX] - pfArrayCum2[(nY-nR-1)*nWid+nX];
pfOutArray3[nY*nWid+nX] = pfArrayCum3[(nHei-1)*nWid+nX] - pfArrayCum3[(nY-nR-1)*nWid+nX];
}
}
//cumulative sum over X axis
for ( int nY = 0; nY < nHei*nWid; nY+=nWid )
{
pfArrayCum1[nY] = pfOutArray1[nY];
pfArrayCum2[nY] = pfOutArray2[nY];
pfArrayCum3[nY] = pfOutArray3[nY];
}
for ( int nY = 0; nY < nHei*nWid; nY+=nWid )
{
for ( int nX = 1; nX < nWid; nX++ )
{
pfArrayCum1[nY+nX] = pfArrayCum1[nY+nX-1]+pfOutArray1[nY+nX];
pfArrayCum2[nY+nX] = pfArrayCum2[nY+nX-1]+pfOutArray2[nY+nX];
pfArrayCum3[nY+nX] = pfArrayCum3[nY+nX-1]+pfOutArray3[nY+nX];
}
}
//difference over Y axis
for ( int nY = 0; nY < nHei*nWid; nY+=nWid )
{
for ( int nX = 0; nX < nR+1; nX++ )
{
pfOutArray1[nY+nX] = pfArrayCum1[nY+nX+nR];
pfOutArray2[nY+nX] = pfArrayCum2[nY+nX+nR];
pfOutArray3[nY+nX] = pfArrayCum3[nY+nX+nR];
}
}
for ( int nY = 0; nY < nHei*nWid; nY+=nWid )
{
for ( int nX = nR+1; nX < nWid-nR; nX++ )
{
pfOutArray1[nY+nX] = pfArrayCum1[nY+nX+nR] - pfArrayCum1[nY+nX-nR-1];
pfOutArray2[nY+nX] = pfArrayCum2[nY+nX+nR] - pfArrayCum2[nY+nX-nR-1];
pfOutArray3[nY+nX] = pfArrayCum3[nY+nX+nR] - pfArrayCum3[nY+nX-nR-1];
}
}
for ( int nY = 0; nY < nHei*nWid; nY+=nWid )
{
for ( int nX = nWid-nR; nX < nWid; nX++ )
{
pfOutArray1[nY+nX] = pfArrayCum1[nY+nWid-1] - pfArrayCum1[nY+nX-nR-1];
pfOutArray2[nY+nX] = pfArrayCum2[nY+nWid-1] - pfArrayCum2[nY+nX-nR-1];
pfOutArray3[nY+nX] = pfArrayCum3[nY+nWid-1] - pfArrayCum3[nY+nX-nR-1];
}
}
delete []pfArrayCum1;
delete []pfArrayCum2;
delete []pfArrayCum3;
}
/*
Function: GuidedFilterY
Description: the original guided filter for gray image. This function is used for image dehazing.
The video dehazing algorithm uses appoximated filter for fast refinement.
Parameter:
nW - width of array
nH - height of array
fEps - epsilon
(member variable)
m_pfTransmission - initial transmission (block_based)
m_pnYImg - guidance image (Y image)
Return:
m_pfTransmissionR - filtered transmission
*/
void dehazing::GuidedFilterY(int nW, int nH, float fEps)
{
float* pfImageY = new float[nW*nH];
float* pfInitN = new float[nW*nH];
float* pfInitMeanIp = new float[nW*nH];
float* pfMeanP = new float[nW*nH];
float* pfA = new float[nW*nH];
float* pfB = new float[nW*nH];
float* pfOutA = new float[nW*nH];
float* pfOutB = new float[nW*nH];
float* pfN = new float[nW*nH];
float* pfMeanI = new float[nW*nH];
float* pfMeanIp = new float[nW*nH];
float* pfInitvarI = new float[nW*nH];
float* pfvarI = new float[nW*nH];
float* pfCovIp = new float[nW*nH];
int nIdx;
// Converting to floating point array
for(nIdx = 0 ; nIdx < nW*nH ; nIdx++ )
{
pfImageY[nIdx] = (float)m_pnYImg[nIdx];
}
//////////////////////////////////////////////////////////////////////////
// Make an integral image
for (nIdx = 0; nIdx < nW*nH; nIdx++ )
{
pfInitN[nIdx] = 1.0f;
pfInitMeanIp[nIdx] = pfImageY[nIdx]*m_pfTransmission[nIdx];
}
BoxFilter(pfInitN, m_nGBlockSize, nW, nH, pfN);
BoxFilter(m_pfTransmission, m_nGBlockSize, nW, nH, pfMeanP);
BoxFilter(pfImageY, m_nGBlockSize, nW, nH, pfMeanI);
BoxFilter(pfInitMeanIp, m_nGBlockSize, nW, nH, pfMeanIp);
// Variance of (I, pfTrans) in each local patch
for (nIdx = 0; nIdx < nW*nH; nIdx++ )
{
pfInitvarI[nIdx] = pfImageY[nIdx]*pfImageY[nIdx];
}
BoxFilter(pfInitvarI, m_nGBlockSize, nW, nH, pfvarI);
for (nIdx = 0; nIdx < nW*nH; nIdx++ )
{
pfMeanI[nIdx] = pfMeanI[nIdx]/pfN[nIdx];
pfMeanP[nIdx] = pfMeanP[nIdx]/pfN[nIdx];
pfMeanIp[nIdx] = pfMeanIp[nIdx]/pfN[nIdx];
pfCovIp[nIdx] = pfMeanIp[nIdx] - pfMeanI[nIdx] * pfMeanP[nIdx];
pfvarI[nIdx] = pfvarI[nIdx]/pfN[nIdx] - pfMeanI[nIdx]*pfMeanI[nIdx];
}
// Calculate coefficient a and coefficient b
for(int nIdx =0; nIdx<nW*nH; nIdx++)
{
// coefficient a
pfA[nIdx] = (pfCovIp[nIdx])/(pfvarI[nIdx]+fEps);
// coefficient b
pfB[nIdx] = pfMeanP[nIdx] - pfA[nIdx]*pfMeanI[nIdx];
}
// Transmission refinement at each pixel
BoxFilter(pfA,m_nGBlockSize,nW,nH,pfOutA);
BoxFilter(pfB,m_nGBlockSize,nW,nH,pfOutB);
for ( int nIdx = 0; nIdx < nW*nH; nIdx++ )
{
m_pfTransmissionR[nIdx] = ( pfOutA[nIdx]*pfImageY[nIdx] + pfOutB[nIdx] ) / pfN[nIdx];
}
delete []pfInitN;
delete []pfInitMeanIp;
delete []pfMeanP;
delete []pfN;
delete []pfMeanI;
delete []pfMeanIp;
delete []pfCovIp;
delete []pfInitvarI;
delete []pfvarI;
delete []pfA;
delete []pfB;
delete []pfOutA;
delete []pfOutB;
//////////////////////////////////////////////////////////////////////////
delete []pfImageY;
}
/*
Function: GuidedFilter
Description: the original guided filter for rgb color image. This function is used for image dehazing.
The video dehazing algorithm uses appoximated filter for fast refinement.
Parameter:
nW - width of array
nH - height of array
fEps - epsilon
(member variable)
m_pfTransmission - initial transmission (block_based)
m_pnYImg - guidance image (Y image)
Return:
m_pfTransmissionR - filtered transmission
*/
void dehazing::GuidedFilter(int nW, int nH, float fEps)
{
float* pfImageR = new float[nW*nH];
float* pfImageG = new float[nW*nH];
float* pfImageB = new float[nW*nH];
float* pfInitN = new float[nW*nH];
float* pfInitMeanIpR = new float[nW*nH];
float* pfInitMeanIpG = new float[nW*nH];
float* pfInitMeanIpB = new float[nW*nH];
float* pfMeanP = new float[nW*nH];
float* pfN = new float[nW*nH];
float* pfMeanIr = new float[nW*nH];
float* pfMeanIg = new float[nW*nH];
float* pfMeanIb = new float[nW*nH];
float* pfMeanIpR = new float[nW*nH];
float* pfMeanIpG = new float[nW*nH];
float* pfMeanIpB = new float[nW*nH];
float* pfCovIpR = new float[nW*nH];
float* pfCovIpG = new float[nW*nH];
float* pfCovIpB = new float[nW*nH];
float* pfCovEntire = new float[nW*nH*3];
float* pfInitVarIrr = new float[nW*nH];
float* pfInitVarIrg = new float[nW*nH];
float* pfInitVarIrb = new float[nW*nH];
float* pfInitVarIgg = new float[nW*nH];
float* pfInitVarIgb = new float[nW*nH];
float* pfInitVarIbb = new float[nW*nH];
float* pfVarIrr = new float[nW*nH];
float* pfVarIrg = new float[nW*nH];
float* pfVarIrb = new float[nW*nH];
float* pfVarIgg = new float[nW*nH];
float* pfVarIgb = new float[nW*nH];
float* pfVarIbb = new float[nW*nH];
float* pfA1 = new float[nW*nH];
float* pfA2 = new float[nW*nH];
float* pfA3 = new float[nW*nH];
float* pfOutA1 = new float[nW*nH];
float* pfOutA2 = new float[nW*nH];
float* pfOutA3 = new float[nW*nH];
float* pfSigmaEntire = new float[nW*nH*9];
float* pfB = new float[nW*nH];
float* pfOutB = new float[nW*nH];
int nIdx;
// Converting to float point
for(nIdx = 0 ; nIdx < nW*nH ; nIdx++ )
{
pfImageR[nIdx] = (float)m_pnRImg[nIdx];
pfImageG[nIdx] = (float)m_pnGImg[nIdx];
pfImageB[nIdx] = (float)m_pnBImg[nIdx];
}
//////////////////////////////////////////////////////////////////////////
// Make an integral image
for (nIdx = 0; nIdx < nW*nH; nIdx++ )
{
pfInitN[nIdx] = (float)1;
pfInitMeanIpR[nIdx] = pfImageR[nIdx]*m_pfTransmission[nIdx];
pfInitMeanIpG[nIdx] = pfImageG[nIdx]*m_pfTransmission[nIdx];
pfInitMeanIpB[nIdx] = pfImageB[nIdx]*m_pfTransmission[nIdx];
}
BoxFilter(pfInitN, m_nGBlockSize, nW, nH, pfN);
BoxFilter(m_pfTransmission, m_nGBlockSize, nW, nH, pfMeanP);
BoxFilter(pfImageR, pfImageG, pfImageB, m_nGBlockSize, nW, nH, pfMeanIr, pfMeanIg, pfMeanIb);
BoxFilter(pfInitMeanIpR, pfInitMeanIpG, pfInitMeanIpB, m_nGBlockSize, nW, nH, pfMeanIpR, pfMeanIpG, pfMeanIpB);
//Covariance of (I, pfTrans) in each local patch
for (nIdx = 0; nIdx < nW*nH; nIdx++ )
{
pfMeanIr[nIdx] = pfMeanIr[nIdx]/pfN[nIdx];
pfMeanIg[nIdx] = pfMeanIg[nIdx]/pfN[nIdx];
pfMeanIb[nIdx] = pfMeanIb[nIdx]/pfN[nIdx];
pfMeanP[nIdx] = pfMeanP[nIdx]/pfN[nIdx];
pfMeanIpR[nIdx] = pfMeanIpR[nIdx]/pfN[nIdx];
pfMeanIpG[nIdx] = pfMeanIpG[nIdx]/pfN[nIdx];
pfMeanIpB[nIdx] = pfMeanIpB[nIdx]/pfN[nIdx];
pfCovIpR[nIdx] = pfMeanIpR[nIdx] - pfMeanIr[nIdx]*pfMeanP[nIdx];
pfCovIpG[nIdx] = pfMeanIpG[nIdx] - pfMeanIg[nIdx]*pfMeanP[nIdx];
pfCovIpB[nIdx] = pfMeanIpB[nIdx] - pfMeanIb[nIdx]*pfMeanP[nIdx];
pfCovEntire[nIdx*3] = pfCovIpR[nIdx];
pfCovEntire[nIdx*3+1] = pfCovIpG[nIdx];
pfCovEntire[nIdx*3+2] = pfCovIpB[nIdx];
pfInitVarIrr[nIdx] = pfImageR[nIdx]*pfImageR[nIdx];
pfInitVarIrg[nIdx] = pfImageR[nIdx]*pfImageG[nIdx];
pfInitVarIrb[nIdx] = pfImageR[nIdx]*pfImageB[nIdx];
pfInitVarIgg[nIdx] = pfImageG[nIdx]*pfImageG[nIdx];
pfInitVarIgb[nIdx] = pfImageG[nIdx]*pfImageB[nIdx];
pfInitVarIbb[nIdx] = pfImageB[nIdx]*pfImageB[nIdx];
}
// Variance of I in each local patch: the matrix Sigma.
// rr, rg, rb
// pfSigma rg, gg, gb
// rb, gb, bb
BoxFilter(pfInitVarIrr, pfInitVarIrg, pfInitVarIrb, m_nGBlockSize, nW, nH, pfVarIrr, pfVarIrg, pfVarIrb);
BoxFilter(pfInitVarIgg, pfInitVarIgb, pfInitVarIbb, m_nGBlockSize, nW, nH, pfVarIgg, pfVarIgb, pfVarIbb);
for (nIdx = 0; nIdx < nW*nH; nIdx++ )
{
pfVarIrr[nIdx] = pfVarIrr[nIdx]/pfN[nIdx] - pfMeanIr[nIdx]*pfMeanIr[nIdx];
pfVarIrg[nIdx] = pfVarIrg[nIdx]/pfN[nIdx] - pfMeanIr[nIdx]*pfMeanIg[nIdx];
pfVarIrb[nIdx] = pfVarIrb[nIdx]/pfN[nIdx] - pfMeanIr[nIdx]*pfMeanIb[nIdx];
pfVarIgg[nIdx] = pfVarIgg[nIdx]/pfN[nIdx] - pfMeanIg[nIdx]*pfMeanIg[nIdx];
pfVarIgb[nIdx] = pfVarIgb[nIdx]/pfN[nIdx] - pfMeanIg[nIdx]*pfMeanIb[nIdx];
pfVarIbb[nIdx] = pfVarIbb[nIdx]/pfN[nIdx] - pfMeanIb[nIdx]*pfMeanIb[nIdx];
pfSigmaEntire[nIdx*9+0] = pfVarIrr[nIdx]+fEps*2.0f;
pfSigmaEntire[nIdx*9+1] = pfVarIrg[nIdx];
pfSigmaEntire[nIdx*9+2] = pfVarIrb[nIdx];
pfSigmaEntire[nIdx*9+3] = pfVarIrg[nIdx];
pfSigmaEntire[nIdx*9+4] = pfVarIgg[nIdx]+fEps*2.0f;
pfSigmaEntire[nIdx*9+5] = pfVarIgb[nIdx];
pfSigmaEntire[nIdx*9+6] = pfVarIrb[nIdx];
pfSigmaEntire[nIdx*9+7] = pfVarIgb[nIdx];
pfSigmaEntire[nIdx*9+8] = pfVarIbb[nIdx]+fEps*2.0f;
}
// Coefficient a와 coefficient b계산
// Coefficienta
for(nIdx =0; nIdx<nW*nH; nIdx++)
{
CalcAcoeff(pfSigmaEntire, pfCovEntire, pfA1, pfA2, pfA3, nIdx);
}
// Coefficient b
for (nIdx = 0; nIdx < nW*nH; nIdx++ )
{
pfB[nIdx] = pfMeanP[nIdx] - pfA1[nIdx]*pfMeanIr[nIdx] - pfA2[nIdx]*pfMeanIg[nIdx] - pfA3[nIdx]*pfMeanIb[nIdx];
}
// Transmission refinement at each pixel
BoxFilter(pfA1,pfA2,pfA3,m_nGBlockSize,nW,nH,pfOutA1,pfOutA2,pfOutA3);
BoxFilter(pfB,m_nGBlockSize,nW,nH,pfOutB);
for (nIdx = 0; nIdx < nW*nH; nIdx++ )
{
m_pfTransmissionR[nIdx] = ( pfOutA1[nIdx]*pfImageR[nIdx] + pfOutA2[nIdx]*pfImageG[nIdx] + pfOutA3[nIdx]*pfImageB[nIdx] + pfOutB[nIdx] ) / pfN[nIdx];
}
delete []pfInitN;
delete []pfInitMeanIpR;
delete []pfInitMeanIpG;
delete []pfInitMeanIpB;
delete []pfMeanP;
delete []pfN;
delete []pfMeanIr;
delete []pfMeanIg;
delete []pfMeanIb;
delete []pfMeanIpR;
delete []pfMeanIpG;
delete []pfMeanIpB;
delete []pfCovIpR;
delete []pfCovIpG;
delete []pfCovIpB;
delete []pfCovEntire;
delete []pfInitVarIrr;
delete []pfInitVarIrg;
delete []pfInitVarIrb;
delete []pfInitVarIgg;
delete []pfInitVarIgb;
delete []pfInitVarIbb;
delete []pfVarIrr;
delete []pfVarIrg;
delete []pfVarIrb;
delete []pfVarIgg;
delete []pfVarIgb;
delete []pfVarIbb;
delete []pfA1;
delete []pfA2;
delete []pfA3;
delete []pfOutA1;
delete []pfOutA2;
delete []pfOutA3;
delete []pfSigmaEntire;
delete []pfB;
delete []pfOutB;
//////////////////////////////////////////////////////////////////////////
delete []pfImageR;
delete []pfImageG;
delete []pfImageB;
}
/*
Function: FastGuidedFilter (downsampled image)
Description: Transmission refinement based on guided fitlering, but we approximate the filtering
using partial window. In addtion, we analyze the guided filter using projection method.
SSE (SIMD) is applied.
* Limitation - In this code, we do not consider the border line of filtering, hence we will update the code.
The user may regulate the window size that the image size divides into the window size.
Parameters:
nW - width of down-sampled image
nH - height of down-sampled image
(hidden)
m_pnSmallYImg - down-sampled image
m_pnSmallTrans - down-sampled initial transmission
Return:
m_pfSmallTransR - down-sampled refined transmission
*/
void dehazing::FastGuidedFilterS()
{
int nW = 320;
int nH = 240;
int nStep = m_nStepSize;
int nWstep = m_nGBlockSize/nStep; // Step size of x-axis
int nHstep = m_nGBlockSize/nStep; // Step size of y-axis
int nYb, nXb, nYa, nXa;
int nIdxA, nIdxB, nI;
float fDenom, fNormV1, fMeanI;
float fAk, fBk;
// SIMD is applied
__m128 sseMean, sseY, ssePk_p, sseDenom, sseInteg, sseNormPk,
sseAk, sseBk, sseP, sseNormV1, sseGauss, sseBkV1, sseQ;
// Initialization
for ( nYb = 0 ; nYb < nH; nYb++ )
{
for ( nXb = 0; nXb < nW; nXb++ )
{
m_pfSmallY[nYb*nW+nXb]=(float)m_pnSmallYImg[nYb*nW+nXb];
m_pfSmallInteg[nYb*nW+nXb]=0;
m_pfSmallDenom[nYb*nW+nXb]=0;
}
}
// Transmission refinement is applied to sampling pixels
for ( nYa = 0 ; nYa < (nH-m_nGBlockSize)/nHstep+1 ; nYa++ )
{
for ( nXa = 0 ; nXa < (nW-m_nGBlockSize)/nWstep+1 ; nXa++ )
{
nIdxA=nYa*nHstep*nW+nXa*nWstep;
// vector normalize -> fNormV1
fNormV1 = 1.0f/m_nGBlockSize;
fMeanI = 0.0f;
// fNormV1 --> create perpendicular vector(m_pfSmallPk_p)
// m_pfSmallPk_p == m_pfSmallY - fMeanI;
sseMean = _mm_setzero_ps();
sseY = _mm_setzero_ps();
// Mean value
for ( nYb = 0 ; nYb < m_nGBlockSize; nYb++ )
{
for ( nXb = 0; nXb < m_nGBlockSize; nXb+=4 )
{
sseY = _mm_loadu_ps((m_pfSmallY+(nIdxA+nYb*nW+nXb)));
sseMean = _mm_add_ps( sseMean, sseY );
}
}
for ( nI = 0 ; nI < 4; nI++ )
{
fMeanI += *((float*)(&sseMean)+nI);
}
fMeanI = fMeanI/(m_nGBlockSize*m_nGBlockSize);
sseMean = _mm_set1_ps(fMeanI);
sseY = _mm_setzero_ps();
ssePk_p;
// m_pfSmallY - fMeanI
for ( nYb = 0 ; nYb < m_nGBlockSize; nYb++ )
{
for ( nXb = 0; nXb < m_nGBlockSize; nXb+=4 )
{
sseY = _mm_loadu_ps(m_pfSmallY+(nIdxA+nYb*nW+nXb));
ssePk_p = _mm_sub_ps( sseY, sseMean );
for ( nI = 0 ; nI < 4; nI++)
{
m_pfSmallPk_p[nYb*m_nGBlockSize+nXb+nI] = *((float*)(&ssePk_p)+nI);
}
}
}
// p vector normalize -> m_pfSmallNormPk
// m_pfSmallPk_p^2
fDenom=0.0f;
sseDenom =_mm_setzero_ps();
for ( nIdxB = 0 ; nIdxB < m_nGBlockSize*m_nGBlockSize; nIdxB+=4 )
{
ssePk_p = _mm_loadu_ps(m_pfSmallPk_p+nIdxB);
sseDenom = _mm_add_ps( sseDenom, _mm_mul_ps( ssePk_p, ssePk_p ));
}
for ( nI = 0 ; nI < 4; nI++ )
{
fDenom += *((float*)(&sseDenom)+nI);
}
sseDenom = _mm_set1_ps(sqrt(fDenom));
sseNormPk;
fAk = 0.0f;
fBk = 0.0f;
sseAk = _mm_setzero_ps();
sseBk = _mm_setzero_ps();
sseP;
// a = q'norm_p
// b = q'norm_v1
// Exception handling (denominator == 0)
if(fDenom == 0)
{
// a = 0;
fAk = 0;
sseNormV1 = _mm_set1_ps(fNormV1);
for ( nYb = 0 ; nYb < m_nGBlockSize; nYb++ )
{
for ( nXb = 0; nXb < m_nGBlockSize; nXb+=4 )
{
sseP = _mm_loadu_ps(m_pfSmallTrans+(nIdxA+nYb*nW+nXb));
sseBk = _mm_add_ps( _mm_mul_ps( sseP , sseNormV1 ), sseBk );
}
}
// b = q'norm_v1
for ( nI = 0 ; nI < 4; nI++ )
fBk += *((float*)(&sseBk)+nI);
}
else
{
// m_pfSmallNormPk
for ( nIdxB = 0 ; nIdxB < m_nGBlockSize*m_nGBlockSize; nIdxB+=4 )
{
ssePk_p = _mm_loadu_ps(m_pfSmallPk_p+nIdxB);
sseNormPk = _mm_div_ps(ssePk_p, sseDenom);
for ( nI = 0 ; nI < 4; nI++ )
{
m_pfSmallNormPk[nIdxB+nI] = *((float*)(&sseNormPk)+nI);
}
}
// a = q'norm_p
// b = q'norm_v1
sseNormV1 = _mm_set1_ps(fNormV1);
for ( nYb = 0 ; nYb < m_nGBlockSize; nYb++ )
{
for ( nXb = 0; nXb < m_nGBlockSize; nXb+=4 )
{
sseP = _mm_loadu_ps(m_pfSmallTrans+(nIdxA+nYb*nW+nXb));
sseNormPk = _mm_loadu_ps(m_pfSmallNormPk+(nYb*m_nGBlockSize+nXb));
sseAk = _mm_add_ps( _mm_mul_ps( sseP , sseNormPk ), sseAk );
sseBk = _mm_add_ps( _mm_mul_ps( sseP , sseNormV1 ), sseBk );
}
}
for ( nI = 0 ; nI < 4; nI++ )
{
fAk += *((float*)(&sseAk)+nI);
fBk += *((float*)(&sseBk)+nI);
}
}
sseGauss;
sseInteg;
sseBkV1 = _mm_set1_ps(fBk*fNormV1);
sseAk = _mm_set1_ps(fAk);
// Gaussian weighting
// Weighted_denom
for ( nYb = 0 ; nYb < m_nGBlockSize; nYb++ )
{
for ( nXb = 0; nXb < m_nGBlockSize; nXb+=4 )
{
sseNormPk = _mm_loadu_ps(m_pfSmallNormPk+(nYb*m_nGBlockSize+nXb));
sseGauss = _mm_loadu_ps(m_pfGuidedLUT+(nYb*m_nGBlockSize+nXb));
sseInteg = _mm_mul_ps(_mm_add_ps( _mm_mul_ps(sseNormPk, sseAk), sseBkV1 ), sseGauss);
// m_pfSmallInteg
// m_pfSmallDenom
for ( nI = 0 ; nI < 4; nI++ )
{
m_pfSmallInteg[nIdxA+nYb*nW+nXb+nI] += *((float*)(&sseInteg)+nI);
m_pfSmallDenom[nIdxA+nYb*nW+nXb+nI] += *((float*)(&sseGauss)+nI);
}
}
}
}
}
// m_pfSmallTransR = m_pfSmallInteg / m_pfSmallDenom
for( nIdxA = 0 ; nIdxA < nW*nH; nIdxA+=4 )
{
sseInteg = _mm_loadu_ps(m_pfSmallInteg+nIdxA);
sseDenom = _mm_loadu_ps(m_pfSmallDenom+nIdxA);
sseQ = _mm_div_ps(sseInteg, sseDenom);
for( nI = 0; nI < 4; nI++)
m_pfSmallTransR[nIdxA+nI] = *((float*)(&sseQ)+nI);
}
}
/*
Function: FastGuidedFilter (original sized image)
Description: Transmission refinement based on guided fitlering, but we approximate the filtering
using partial window. In addtion, we analyze the guided filter using projection method.
SSE (SIMD) is applied.
* Limitation - In this code, we do not consider the border line of filtering, hence we will update the code.
The user may regulate the window size that the image size divides into the window size.
Parameters:
nW - width of down-sampled image
nH - height of down-sampled image
(hidden)
m_pnYImg - down-sampled image
m_pnTransmission - down-sampled initial transmission
Return:
m_pfTransmissionR - down-sampled refined transmission
*/
void dehazing::FastGuidedFilter()
{
int nStep = m_nStepSize; // step size
int nEPBlockSizeL = m_nGBlockSize;
int nHeiL = m_nHei;
int nWidL = m_nWid;
float* pfYL = m_pfY;
float* pfIntegL = m_pfInteg;
float* pfDenomL = m_pfDenom;
int* pnYImgL = m_pnYImg;
float* pfPk_pL = m_pfPk_p;
float* pfNormPkL = m_pfNormPk;
float* pfGuidedLUTL = m_pfGuidedLUT;
float* pfTransmissionL = m_pfTransmission;
int nWstep = nEPBlockSizeL/nStep;
int nHstep = nEPBlockSizeL/nStep;
float fDenom, fNormV1, fMeanI;
float fAk = 0.0f; // fAk : a in "a*I+b", fBk : b in "a*I+b"
float fBk = 0.0f;
int nIdxA, nYa, nXa, nYb, nXb, nI, nIdxB; // indexing
// SIMD is applied
__m128 sseMean, sseY, ssePk_p, sseDenom, sseInteg, sseNormPk,
sseAk, sseBk, sseP, sseNormV1, sseGauss, sseBkV1, sseQ;
// Initialization
for ( nYb = 0 ; nYb < nHeiL; nYb++ )
{
for ( nXb = 0; nXb < nWidL; nXb++ )
{
pfYL[nYb*nWidL+nXb]=(float)pnYImgL[nYb*nWidL+nXb];
pfIntegL[nYb*nWidL+nXb]=0;
pfDenomL[nYb*nWidL+nXb]=0;
}
}
// sampling points
for ( nYa = 0 ; nYa < (nHeiL-nEPBlockSizeL)/nHstep+1 ; nYa++ )
{
for ( nXa = 0 ; nXa < (nWidL-nEPBlockSizeL)/nWstep+1 ; nXa++ )
{
nIdxA=nYa*nHstep*nWidL+nXa*nWstep;
// 1 vector normalize -> fNormV1
fNormV1 = 1.0f/nEPBlockSizeL;
fMeanI = 0.0f;
// Create p vector(m_pfSmallPk_p) which is perpendicular to fNormV1
// p vector == m_pfSmallY - fMeanI
sseMean = _mm_setzero_ps();
sseY = _mm_setzero_ps();
// Mean value
for ( nYb = 0 ; nYb < nEPBlockSizeL; nYb++ )
{
for ( nXb = 0; nXb < nEPBlockSizeL; nXb+=4 )
{
sseY = _mm_loadu_ps((pfYL+(nIdxA+nYb*nWidL+nXb)));
sseMean = _mm_add_ps( sseMean, sseY );
}
}
for ( nI = 0 ; nI < 4; nI++ )
{
fMeanI += *((float*)(&sseMean)+nI);
}
fMeanI = fMeanI/(nEPBlockSizeL*nEPBlockSizeL);
sseMean = _mm_set1_ps(fMeanI);
sseY = _mm_setzero_ps();
// m_pfSmallY - fMeanI
for ( nYb = 0 ; nYb < nEPBlockSizeL; nYb++ )
{
for ( nXb = 0; nXb < nEPBlockSizeL; nXb+=4 )
{
sseY = _mm_loadu_ps(pfYL+(nIdxA+nYb*nWidL+nXb));
ssePk_p = _mm_sub_ps( sseY, sseMean );
for ( nI = 0 ; nI < 4; nI++)
{
pfPk_pL[nYb*nEPBlockSizeL+nXb+nI] = *((float*)(&ssePk_p)+nI);
}
}
}
// p vector normalize -> m_pfSmallNormPk
// m_pfSmallPk_p^2
fDenom=0.0f;
sseDenom =_mm_setzero_ps();
for ( nIdxB = 0 ; nIdxB < nEPBlockSizeL*nEPBlockSizeL; nIdxB+=4 )
{
ssePk_p = _mm_loadu_ps(pfPk_pL+nIdxB);
sseDenom = _mm_add_ps( sseDenom, _mm_mul_ps( ssePk_p, ssePk_p ));
}
for ( nI = 0 ; nI < 4; nI++ )
{
fDenom += *((float*)(&sseDenom)+nI);
}
sseDenom = _mm_set1_ps(sqrt(fDenom));
sseAk = _mm_setzero_ps();
sseBk = _mm_setzero_ps();
// a = q'norm_p
// b = q'norm_v1
// Exception handling (denominator == 0)
// a = 0;
fAk = 0.0f;
fBk = 0.0f;
if(fDenom == 0)
{
sseNormV1 = _mm_set1_ps(fNormV1);
for ( nYb = 0 ; nYb < nEPBlockSizeL; nYb++ )
{
for ( nXb = 0; nXb < nEPBlockSizeL; nXb+=4 )
{
sseP = _mm_loadu_ps(pfTransmissionL+(nIdxA+nYb*nWidL+nXb));
sseBk = _mm_add_ps( _mm_mul_ps( sseP , sseNormV1 ), sseBk );
}
}
// b = q'norm_v1
for ( nI = 0 ; nI < 4; nI++ )
fBk += *((float*)(&sseBk)+nI);
}
else
{
// m_pfSmallNormPk
for ( nIdxB = 0 ; nIdxB < nEPBlockSizeL*nEPBlockSizeL; nIdxB+=4 )
{
ssePk_p = _mm_loadu_ps(pfPk_pL+nIdxB);
sseNormPk = _mm_div_ps(ssePk_p, sseDenom);
for ( int nI = 0 ; nI < 4; nI++ )
{
pfNormPkL[nIdxB+nI] = *((float*)(&sseNormPk)+nI);
}
}
sseNormV1 = _mm_set1_ps(fNormV1);
// a = q'norm_p
// b = q'norm_v1
for ( nYb = 0 ; nYb < nEPBlockSizeL; nYb++ )
{
for ( nXb = 0; nXb < nEPBlockSizeL; nXb+=4 )
{
sseP = _mm_loadu_ps(pfTransmissionL+(nIdxA+nYb*nWidL+nXb));
sseNormPk = _mm_loadu_ps(pfNormPkL+(nYb*nEPBlockSizeL+nXb));
sseAk = _mm_add_ps( _mm_mul_ps( sseP , sseNormPk ), sseAk );
sseBk = _mm_add_ps( _mm_mul_ps( sseP , sseNormV1 ), sseBk );
}
}
for ( nI = 0 ; nI < 4; nI++ )
{
fAk += *((float*)(&sseAk)+nI);
fBk += *((float*)(&sseBk)+nI);
}
}
sseBkV1 = _mm_set1_ps(fBk*fNormV1);
sseAk = _mm_set1_ps(fAk);
// Gaussian weighting
// Weighted_denom
for ( nYb = 0 ; nYb < nEPBlockSizeL; nYb++ )
{
for ( nXb = 0; nXb < nEPBlockSizeL; nXb+=4 )
{
sseNormPk = _mm_loadu_ps(pfNormPkL+(nYb*nEPBlockSizeL+nXb));
sseGauss = _mm_loadu_ps(pfGuidedLUTL+(nYb*nEPBlockSizeL+nXb));
sseInteg = _mm_mul_ps(_mm_add_ps( _mm_mul_ps(sseNormPk, sseAk), sseBkV1 ), sseGauss);
// m_pfSmallInteg
// m_pfSmallDenom
for ( nI = 0 ; nI < 4; nI++ )
{
pfIntegL[nIdxA+nYb*nWidL+nXb+nI] += *((float*)(&sseInteg)+nI);
pfDenomL[nIdxA+nYb*nWidL+nXb+nI] += *((float*)(&sseGauss)+nI);
}
}
}
}
}
// m_pfSmallTransR = m_pfSmallInteg / m_pfSmallDenom
for( int nIdx = 0 ; nIdx < nWidL*nHeiL; nIdx+=4 )
{
sseInteg = _mm_loadu_ps(pfIntegL+nIdx);
sseDenom = _mm_loadu_ps(pfDenomL+nIdx);
sseQ = _mm_div_ps(sseInteg, sseDenom);
for( int nI = 0; nI < 4; nI++)
m_pfTransmissionR[nIdx+nI] = *((float*)(&sseQ)+nI);
}
}
/*
Function: GuidedFilterShiftableWindow
Description: It is a modified guided filter to reduce blur artifacts of original
one. The algorithm shift the window which has the minimum error.
The other scheme is the same with original one.
Parameters:
fEps - the epsilon (the same with original guided filter).
Return:
m_pfSmallTransR - refined transmission.
*/
void dehazing::GuidedFilterShiftableWindow(float fEps)
{
int nY, nX;
int nH, nW;
int nYmin, nXmin, nYmax, nXmax;
int nYminOpt, nXminOpt, nYmaxOpt, nXmaxOpt;
float fMeanI, fMeanR, fMeanG, fMeanB;
float fActualBlock;
float fMeant;
float ftrans;
float fa1, fa2, fa3, fb;
float fCovRp, fCovGp, fCovBp;
float afSigma[9], afInv[9];
float fVRR, fVRG, fVRB, fVGB, fVBB, fVGG;
float fMRt, fMGt, fMBt;
float fR, fG, fB;
float fDet;
int x1, x2, y1, y2;
int nItersX, nItersY;
float fVariance, fOptVariance;
float *pfImageY = new float[m_nWid*m_nHei];
float *pfSqImageY = new float[m_nWid*m_nHei];
float *pfSumTrans = new float[m_nWid*m_nHei];
float *pfIntImageY = new float[m_nWid*m_nHei];
float *pfSqIntImageY= new float[m_nWid*m_nHei];
float *pfintN = new float[m_nWid*m_nHei];
float *pfones = new float[m_nWid*m_nHei];
float *pfWeight = new float[m_nWid*m_nHei];
float *pfWeiSum = new float[m_nWid*m_nHei];
float *pfVarImage = new float[m_nWid*m_nHei];
int *pnN = new int [m_nWid*m_nHei];
int *pnVarN = new int [m_nWid*m_nHei];
int nMax = 0;
float fMaxvar=0;
float grey;
bool bIterationFlag;
float fMB, fMG, fMR, fMBS, fMGS, fMRS;
int nSizes = 31;
int nNewX, nNewY, nOptNewX, nOptNewY;
float inverseweight;
bIterationFlag = true;
// initialize
for(nX=0; nX<m_nWid*m_nHei; nX++)
{
pfSumTrans[nX] = 0;
pfintN[nX] = 0;
pfones[nX] = 1.0f;
pnVarN[nX] = 0;
pfWeiSum[nX] = 0;
pfImageY[nX] = (float)m_pnYImg[nX];
pfSqImageY[nX] = (float)m_pnYImg[nX]*(float)m_pnYImg[nX];
}
BoxFilter(pfImageY, 15, m_nWid, m_nHei, pfIntImageY);
BoxFilter(pfSqImageY, 15, m_nWid, m_nHei, pfSqIntImageY);
BoxFilter(pfones, 15, m_nWid, m_nHei, pfintN);
for(nY=0; nY<m_nHei; nY++)
{
for(nX=0; nX<m_nWid; nX++)
{
pfVarImage[nX+nY*m_nWid] = pfSqIntImageY[nX+nY*m_nWid]/pfintN[nX+nY*m_nWid] - pfIntImageY[nX+nY*m_nWid]/pfintN[nX+nY*m_nWid]*pfIntImageY[nX+nY*m_nWid]/pfintN[nX+nY*m_nWid];
}
}
int totalsum = 0;
iterative:
for(nY=0; nY<m_nHei; nY++)
{
for(nX=0; nX<m_nWid; nX++)
{
//find minimum
fOptVariance = 99999999999999;
for(nItersY=-nSizes/2; nItersY<nSizes/2+1; nItersY+=2)
{
for(nItersX=-nSizes/2; nItersX<nSizes/2+1; nItersX+=2)
{
nYmin = max(0, (nY+nItersY) - nSizes/2);
nYmax = min(m_nHei, (nY+nItersY) + nSizes/2+1);
nXmin = max(0, (nX+nItersX) - nSizes/2);
nXmax = min(m_nWid, (nX+nItersX) + (nSizes)/2+1);
nNewX = min(max(nX+nItersX, 0), m_nWid-1);
nNewY = min(max(nY+nItersY, 0), m_nHei-1);
inverseweight = 1;//exp(-((float)(nItersX*nItersX)+(float)(nItersY*nItersY))/70.0f);
if(fOptVariance > pfVarImage[nNewX+nNewY*m_nWid]*inverseweight)
{
fOptVariance = pfVarImage[nNewX+nNewY*m_nWid]*inverseweight;
nYminOpt = nYmin;
nXminOpt = nXmin;
nYmaxOpt = nYmax;
nXmaxOpt = nXmax;
nOptNewX = nNewX;
nOptNewY = nNewY;
}
}
}
fActualBlock = (float)(nYmaxOpt-nYminOpt)*(nXmaxOpt-nXminOpt);
if(bIterationFlag)
{
pnVarN[nOptNewX+nOptNewY*m_nWid]++;
totalsum++;
}
fVRR=0; fVRG=0; fVRB=0; fVGB=0; fVBB=0; fVGG=0;
fMeanR=0; fMeanG=0; fMeanB=0; fMeant=0;
fMRt=0; fMGt=0; fMBt=0;
// guided filtering at optimal block
for(nH=nYminOpt; nH<nYmaxOpt; nH++)
{
for(nW=nXminOpt; nW<nXmaxOpt; nW++)
{
fB = ((float)(m_pnBImg[nW+m_nWid*nH]))/255.0f;
fG = ((float)(m_pnGImg[nW+m_nWid*nH]))/255.0f;
fR = ((float)(m_pnRImg[nW+m_nWid*nH]))/255.0f;
fMeanB += fB;
fMeanG += fG;
fMeanR += fR;
ftrans = CLIP_TRS(m_pfTransmission[nW+m_nWid*nH]);
fMeant += ftrans;
fMBt += fB*ftrans;
fMGt += fG*ftrans;
fMRt += fR*ftrans;
fVRR += fR*fR;
fVRG += fR*fG;
fVRB += fR*fB;
fVGG += fG*fG;
fVGB += fG*fB;
fVBB += fB*fB;
}
}
fMeanB /= fActualBlock;
fMeanG /= fActualBlock;
fMeanR /= fActualBlock;
fMeant /= fActualBlock;
fMRt /= fActualBlock;
fMGt /= fActualBlock;
fMBt /= fActualBlock;
fCovRp = fMRt - fMeanR*fMeant;
fCovGp = fMGt - fMeanG*fMeant;
fCovBp = fMBt - fMeanB*fMeant;
afSigma[0] = fVRR/fActualBlock - fMeanR*fMeanR + fEps*2.0f;
afSigma[1] = fVRG/fActualBlock - fMeanR*fMeanG;
afSigma[2] = fVRB/fActualBlock - fMeanR*fMeanB;
afSigma[3] = fVRG/fActualBlock - fMeanR*fMeanG;
afSigma[4] = fVGG/fActualBlock - fMeanG*fMeanG + fEps*2.0f;
afSigma[5] = fVGB/fActualBlock - fMeanG*fMeanB;
afSigma[6] = fVRB/fActualBlock - fMeanR*fMeanB;
afSigma[7] = fVGB/fActualBlock - fMeanG*fMeanB;
afSigma[8] = fVBB/fActualBlock - fMeanB*fMeanB + fEps*2.0f;
//3x3 inverse
fDet = 1.0f/( (afSigma[0]*(afSigma[4] * afSigma[8] - afSigma[5] * afSigma[7]))
- ( afSigma[1]*(afSigma[3] * afSigma[8] - afSigma[5] * afSigma[6]))
+ ( afSigma[2]*(afSigma[3] * afSigma[7] - afSigma[4] * afSigma[6])) );
for(nH=0; nH<3; nH++)
{
for(nW=0; nW<3; nW++)
{
x1 = nH == 0? 1: 0;
x2 = nH == 2? 1: 2;
y1 = nW == 0? 1: 0;
y2 = nW == 2? 1: 2;
afInv[nH*3+nW] = (( afSigma[y1*3+x1] * afSigma[y2*3+x2] )
- ( afSigma[y1*3+x2] * afSigma[y2*3+x1] )) * fDet;
if(1==((nW+nH)%2))
afInv[nH*3+nW] = - afInv[nH*3+nW];
}
}
//
fa1 = fCovRp*afInv[0] + fCovGp*afInv[3] + fCovBp*afInv[6];
fa2 = fCovRp*afInv[1] + fCovGp*afInv[4] + fCovBp*afInv[7];
fa3 = fCovRp*afInv[2] + fCovGp*afInv[5] + fCovBp*afInv[8];
fb = fMeant - fa1*fMeanR - fa2*fMeanG - fa3*fMeanB;
if(bIterationFlag)
{
for(nH=nYminOpt; nH<nYmaxOpt; nH++)
{
for(nW=nXminOpt; nW<nXmaxOpt; nW++)
{
pnN[nH*m_nWid+nW]++;
}
}
}
else
{
for(nH=nYminOpt; nH<nYmaxOpt; nH++)
{
for(nW=nXminOpt; nW<nXmaxOpt; nW++)
{
pfSumTrans[nH*m_nWid+nW] = pfSumTrans[nH*m_nWid+nW] +
(fa1*(float)(m_pnRImg[nW+m_nWid*nH])/255.0f
+ fa2*(float)(m_pnGImg[nW+m_nWid*nH])/255.0f
+ fa3*(float)(m_pnBImg[nW+m_nWid*nH])/255.0f + fb)*pfWeight[nOptNewY*m_nWid+nOptNewX];
//pnN[nH*nWid+nW]++;
pfWeiSum[nH*m_nWid+nW] += pfWeight[nOptNewY*m_nWid+nOptNewX];
}
}
}
}
}
nMax = 0;
float fmax=0;
for(nY=0; nY<m_nHei; nY++)
{
for(nX=0; nX<m_nWid; nX++)
{
if(bIterationFlag)
{
if(nMax < pnVarN[nY*m_nWid+nX])
nMax = pnVarN[nY*m_nWid+nX];
pfWeight[nX+nY*m_nWid] = (float)pnVarN[nX+nY*m_nWid]/(float)pnN[nX+nY*m_nWid];
}
else
{
m_pfTransmissionR[nY*m_nWid+nX] = pfSumTrans[nY*m_nWid+nX]/pfWeiSum[nY*m_nWid+nX];
}
}
}
if(bIterationFlag)
{
bIterationFlag = false;
goto iterative;
}
delete [] pfImageY;
delete [] pfSqImageY;
delete [] pfSumTrans;
delete [] pfIntImageY;
delete [] pfSqIntImageY;
delete [] pfintN;
delete [] pfones;
delete [] pfWeight;
delete [] pfWeiSum;
delete [] pfVarImage;
delete [] pnN;
delete [] pnVarN;
}