日记
最近做的项目需要用到去雾,尝试了很多去雾算法,包括使用暗通道去雾之后,用自动色阶优化,gamma校正,超分辨率重建等手段进一步处理图像,也没有达到想要的效果。看完“Optimized contrast enhancement for real-time image and video dehazing”这篇论文,看论文贴图比较酷炫,复现一波试试效果。作者的源码说句实话,放置的比较乱,并年代久远作者使用的opencv2.0里面有些函数不能用了,我自己补充一些功能函数,处理速度可能会比较慢,也可能影响到去雾效果。各位大神刷帖子时,看到有什么优化的地方请指出,从python转到c++两个多月,码程序属实难受啊。另外,各位有什么更好的传统去雾手段希望可以分享给我。
论文就不介绍了,网上介绍论文很多。
论文及原作者的代码下载地址:http://mcl.korea.ac.kr/projects/dehazing/#userconsent#
实现环境
ubuntu20.4, clion(c++), opencv3.4.1
CmakeLists
cmake_minimum_required(VERSION 3.16)
project(remade_voide)
set(CMAKE_CXX_STANDARD 14)
set(Opencv_DIR /home/amax/opencv-3.4.1)
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
file(GLOB_RECURSE DEHAZE_HEAD_FILES ./HazeRemoval/*.h)
file(GLOB_RECURSE DEHAZE_SRC_FILES ./HazeRemoval/*.cpp)
#打印调试信息
MESSAGE(STATUS "Project: ${PROJECT_NAME}")
MESSAGE(STATUS "OpenCV library status:")
MESSAGE(STATUS " version: ${OpenCV_VERSION}")
MESSAGE(STATUS " libraries: ${OpenCV_LIBS}")
MESSAGE(STATUS " include path: ${OpenCV_INCLUDE_DIRS}")
include_directories(${PROJECT_SOURCE_DIR} /HazeRemoval)
add_executable(ImageHazeRemoval ImageHazeRemoval.cpp ${DEHAZE_HEAD_FILES} ${DEHAZE_SRC_FILES})
target_link_libraries(ImageHazeRemoval ${OpenCV_LIBS})
功能函数代码dehazeing.cpp/.h
dehazeing.h
#include <omp.h>
#include <math.h>
#include <iostream>
#include <highgui.h>
#include <emmintrin.h>
#include <opencv2/opencv.hpp>
#ifndef OPENCV_TEST_DEHAZEING_H
#define OPENCV_TEST_DEHAZEING_H
#define CLIP(x) ((x)<(0)?0:((x)>(255)?(255):(x)))
#define CLIP_Z(x) ((x)<(0)?0:((x)>(1.0f)?(1.0f):(x)))
using namespace std;
using namespace cv;
class dehazeing {
public:
dehazeing();
dehazeing(int nWidth, int nHeight, int nTBlockSize, bool bPrevFlag, bool bPostFlag, float fL1, float fL2, int nGBlock);
~dehazeing();
void ImageHazeRemoval(Mat imInput, Mat &imOutput);
private:
//Original size
float m_pfExpLUT[256];
uchar m_pucGammaLUT[256]; //for gamma correction
float* m_pfGuidedLUT; //Guided filter
float m_fGSigma; //Guided filter
int m_nGBlockSize; // Block size for guided filter
int m_nTBlockSize; // Block size for transmission estimation
int m_anAirlight[3]; // atmospheric light value
bool m_bPreviousFlag;
float m_fLambda1; //Loss cost
float m_fLambda2; //Temporal cost
float* m_pfTransmission;
float* m_pfTransmissionR;
bool m_bPostFlag;
bool m_bPostFLag;
int m_nWid;
int m_nHei;
int m_nStepSize;
int m_fGsigma;
int* m_pnRImg;
int* m_pnGImg;
int* m_pnBImg;
//Airlight search range
int m_nTopLeftX;
int m_nTopLeftY;
int m_nBottomRightX;
int m_nBottomRightY;
// dehazing
void AirlightEstimation(Mat imInput);
void RestoreImage(Mat imInput, Mat &imOutput);
void PostProcessing(IplImage imInput, IplImage imOutput);
void piexAverage(Mat imInput, double &std, double &mean);
// TransmissionRefinement
void TransmissionEstimationColor(int *pnImageR, int *pnImageG, int *pnImageB, float *pfTransmission,
int *pnImageRP, int *pnImageGP, int *pnImageBP, float *pfTransmissionP,int nFrame, int nWid, int nHei);
float NFTrsEstimationPColor(int *pnImageR, int *pnImageG, int *pnImageB, int *pnImageRP,
int *pnImageGP, int *pnImageBP, float *pfTransmissionP, int nStartX, int nStartY, int nWid, int nHei);
float NFTrsEstimationColor(int *pnImageR, int *pnImageG, int *pnImageB, int nStartX, int nStartY, int nWid, int nHei);
// guided filter
void GuidedFilter(int nW, int nH, float fEps);
void BoxFilter(float* pfInArray, int nR, int nWid, int nHei, float*& fOutArray);
void BoxFilter2(float* pfInArray1, float* pfInArray2, float* pfInArray3, int nR, int m_nWid, int m_nHei, float*& pfOutArray1, float*& pfOutArray2, float*& pfOutArray3);
void CalcAcoeff(float* pfSigma, float* pfCov, float* pfA1, float* pfA2, float* pfA3, int nIdx);
//function
void MakeExpLUT();
void GuideLUTMaker();
void GammaLUTMaker(float fParameter);
void ImageToIntColor(Mat imInput);
};
#endif //OPENCV_TEST_DEHAZEING_H
dehazeing.cpp
//
// Created by amax on 2022/9/21.
//
#include "dehazeing.h"
using namespace std;
using namespace cv;
dehazeing::dehazeing() {
}
/*
Constructor: dehazing constructor
Parameters:
nWidth - 输入图像宽度
nHieght - 输入图像高度
nTBlockSize - 传输估计块的大小
bPrevFlag - 判断视频去雾时间一致性
bPosFlag - 判断是否进行后处理
fL1 - 调节信息损失成本参数
fL2 - 时间相干参数
nGBlock - 引导滤波块参数
*/
dehazeing::dehazeing(int nWidth, int nHeight, int nTBlockSize, bool bPrevFlag, bool bPostFlag, float fL1, float fL2, int nGBlock) {
m_nWid = nWidth;
m_nHei = nHeight;
m_bPreviousFlag = bPrevFlag;
m_bPostFLag = bPostFlag;
// 每个成本的参数(损失成本,时间相干成本)
m_fLambda1 = fL1;
m_fLambda2 = fL2;
//传输估计块的大小
m_nTBlockSize = nTBlockSize;
//引导滤波器块大小、步长(采样步长)和查找表参数
m_nGBlockSize = nGBlock;
m_nStepSize = 2;
m_fGsigma = 10.0f;
//指定大气光估计的区域
m_nTopLeftX = 0;
m_nTopLeftY = 0;
m_nBottomRightX = m_nWid;
m_nBottomRightY = 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_pfTransmission = new float[m_nWid*m_nHei];
m_pfTransmissionR = new float[m_nWid*m_nHei];
m_pfGuidedLUT = new float[m_nGBlockSize*m_nGBlockSize];
}
dehazeing::~dehazeing() {
}
void dehazeing::MakeExpLUT()
{
int nIdx;
for ( nIdx = 0 ; nIdx < 256; nIdx++ )
{
m_pfExpLUT[nIdx] = exp(-(float)(nIdx * nIdx) / 10.0f);
}
}
void dehazeing::GuideLUTMaker()
{
int nX, nY;
for (nX = 0 ; nX < m_nGBlockSize / 2; nX++)
{
for (nY = 0 ; nY < m_nGBlockSize / 2 ; nY++)
{
m_pfGuidedLUT[nY*m_nGBlockSize+nX]=(exp(-((nX-m_nGBlockSize/2+1)*(nX-m_nGBlockSize/2+1)+(nY-m_nGBlockSize/2+1)*(nY-m_nGBlockSize/2+1))/(2*m_fGSigma*m_fGSigma)));
m_pfGuidedLUT[(m_nGBlockSize-nY-1)*m_nGBlockSize+nX]=(exp(-((nX-m_nGBlockSize/2+1)*(nX-m_nGBlockSize/2+1)+(nY-m_nGBlockSize/2+1)*(nY-m_nGBlockSize/2+1))/(2*m_fGSigma*m_fGSigma)));
m_pfGuidedLUT[nY*m_nGBlockSize+m_nGBlockSize-nX-1]=(exp(-((nX-m_nGBlockSize/2+1)*(nX-m_nGBlockSize/2+1)+(nY-m_nGBlockSize/2+1)*(nY-m_nGBlockSize/2+1))/(2*m_fGSigma*m_fGSigma)));
m_pfGuidedLUT[(m_nGBlockSize-nY-1)*m_nGBlockSize+m_nGBlockSize-nX-1]=(exp(-((nX-m_nGBlockSize/2+1)*(nX-m_nGBlockSize/2+1)+(nY-m_nGBlockSize/2+1)*(nY-m_nGBlockSize/2+1))/(2*m_fGSigma*m_fGSigma)));
}
}
}
void dehazeing::GammaLUTMaker(float fParameter)
{
int nIdx;
for(nIdx=0; nIdx<256; nIdx++)
{
m_pucGammaLUT[nIdx] = (uchar)(pow((float)nIdx/255, fParameter)*255.0f);
}
}
void dehazeing::piexAverage(Mat imInput, double &std, double &mean) {
double sum, sum2, sum3, sum4 = 0;
double Average, variance;
double vars[imInput.rows];
double vars2[imInput.rows];
for (int i = 0; i < imInput.rows; i++) {
int piex[imInput.cols];
const uchar *imInputpiex = imInput.ptr<uchar>(i);
for (int j = 0; j < imInput.cols; j++) {
piex[j] = imInputpiex[j];
sum += imInputpiex[j];
}
Average = sum / imInput.cols;
vars2[i] = Average;
for(int k = 0; k < imInput.cols; k++){
sum2 += pow(piex[k] - Average,2);
}
variance = sum2 / imInput.cols;
vars[i] = variance;
sum = 0;
sum2 = 0;
}
for (int l = 0; l < imInput.rows; l++) {
sum3 += vars[l];
sum4 += vars2[l];
}
mean = sum4 / imInput.rows;
std = sqrt(sum3 / imInput.rows);
}
void dehazeing::AirlightEstimation(Mat imInput) {
int nMinDistance = 65536;
int nDistance;
int nMaxIndex;
double dpScore[3];
double dpMean[3];
double dpStds[3];
float afMean[4] = {0};
float afScore[4] = {0};
float nMaxScore = 0;
int nWidth = imInput.cols;
int nHeight = imInput.rows;
Mat move[3];
//4 sub-block
Mat ImageR = Mat(Size(nWidth / 2, nHeight / 2), IPL_DEPTH_8U, 1);
Mat ImageG = Mat(Size(nWidth / 2, nHeight / 2), IPL_DEPTH_8U, 1);
Mat ImageB = Mat(Size(nWidth / 2, nHeight / 2), IPL_DEPTH_8U, 1);
Mat topleftImage = Mat(Size(nWidth / 2, nHeight / 2), imInput.type());
Mat toprightImage = Mat(Size(nWidth / 2, nHeight / 2), imInput.type());
Mat bottomleftImage = Mat(Size(nWidth / 2, nHeight / 2), imInput.type());
Mat bottomrightImage = Mat(Size(nWidth / 2, nHeight / 2), imInput.type());
topleftImage = imInput(Rect(0, 0, nWidth / 2, nHeight / 2));
toprightImage = imInput(Rect(nWidth /2 + nWidth % 2, 0, nWidth /2, nHeight / 2));
bottomleftImage = imInput(Rect(0, nHeight / 2 + nHeight % 2, nWidth / 2, nHeight /2));
bottomrightImage = imInput(Rect(nWidth /2 + nWidth % 2, nHeight / 2 + nHeight % 2, nWidth / 2, nHeight / 2));
//四叉树分级
if (nWidth * nHeight > 200){
//upper left sub-block
cv::split(topleftImage, move);
ImageR = move[0]; ImageG = move[1]; ImageB = move[2];
piexAverage(ImageR, dpStds[0], dpMean[0]);
piexAverage(ImageG, dpStds[1], dpMean[1]);
piexAverage(ImageB, dpStds[2], dpMean[2]);
dpScore[0] = dpMean[0] - dpStds[0];
dpScore[1] = dpMean[1] - dpStds[1];
dpScore[2] = dpMean[2] - dpStds[2];
afScore[0] = (double)(dpScore[0] + dpScore[1] + dpScore[2]);
nMaxScore = afScore[0];
nMaxIndex = 0;
// upper right sub-block
cv::split(toprightImage, move);
ImageR = move[0]; ImageG = move[1]; ImageB = move[2];
piexAverage(ImageR, dpStds[0], dpMean[0]);
piexAverage(ImageG, dpStds[1], dpMean[1]);
piexAverage(ImageB, dpStds[2], dpMean[2]);
dpScore[0] = dpMean[0] - dpStds[0];
dpScore[1] = dpMean[1] - dpStds[1];
dpScore[2] = dpMean[2] - dpStds[2];
afScore[1] = (double)(dpScore[0] + dpScore[1] + dpScore[2]);
if (afScore[1] > nMaxScore){
nMaxScore = afScore[1];
nMaxIndex = 1;
}
// lower left sub-block
cv::split(bottomleftImage, move);
ImageR = move[0]; ImageG = move[1]; ImageB = move[2];
piexAverage(ImageR, dpStds[0], dpMean[0]);
piexAverage(ImageG, dpStds[1], dpMean[1]);
piexAverage(ImageB, dpStds[2], dpMean[2]);
dpScore[0] = dpMean[0] - dpStds[0];
dpScore[1] = dpMean[1] - dpStds[1];
dpScore[2] = dpMean[2] - dpStds[2];
afScore[2] = (double)(dpScore[0] + dpScore[1] + dpScore[2]);
if (afScore[2] > nMaxScore){
nMaxScore = afScore[2];
nMaxIndex = 2;
}
// lower right sub-block
cv::split(bottomrightImage, move);
ImageR = move[0]; ImageG = move[1]; ImageB = move[2];
piexAverage(ImageR, dpStds[0], dpMean[0]);
piexAverage(ImageG, dpStds[1], dpMean[1]);
piexAverage(ImageB, dpStds[2], dpMean[2]);
dpScore[0] = dpMean[0] - dpStds[0];
dpScore[1] = dpMean[1] - dpStds[1];
dpScore[2] = dpMean[2] - dpStds[2];
afScore[3] = (double)(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(topleftImage);
break;
case 1: AirlightEstimation(toprightImage);
break;
case 2: AirlightEstimation(bottomleftImage);
break;
case 3: AirlightEstimation(bottomrightImage);
break;
}
} else{
// select the atmospheric light value in the sub-block
IplImage image = IplImage(imInput);
int nStep = image.widthStep;
for (int nY = 0; nY < nHeight; nY++) {
for (int nX = 0; nX < nWidth; nX++) {
nDistance = int(sqrt(float(255-(uchar)image.imageData[nY*nStep+nX*3])*float(255-(uchar)image.imageData[nY*nStep+nX*3])
+float(255-(uchar)image.imageData[nY*nStep+nX*3+1])*float(255-(uchar)image.imageData[nY*nStep+nX*3+1])
+float(255-(uchar)image.imageData[nY*nStep+nX*3+2])*float(255-(uchar)image.imageData[nY*nStep+nX*3+2])));
if (nMinDistance > nDistance){
nMinDistance = nDistance;
m_anAirlight[0] = (uchar)image.imageData[nY*nStep+nX*3];
m_anAirlight[1] = (uchar)image.imageData[nY*nStep+nX*3+1];
m_anAirlight[2] = (uchar)image.imageData[nY*nStep+nX*3+2];
}
}
}
}
}
void dehazeing::ImageToIntColor(Mat imInput){
IplImage image = IplImage(imInput);
int nStep = image.widthStep;
for(int nY=0; nY < m_nHei; nY++){
for(int nX=0; nX < m_nWid; nX++){
m_pnBImg[nY * m_nWid + nX] = (uchar)image.imageData[nY * nStep + nX * 3];
m_pnGImg[nY * m_nWid + nX] = (uchar)image.imageData[nY * nStep + nX * 3 + 1];
m_pnRImg[nY * m_nWid + nX] = (uchar)image.imageData[nY * nStep + nX * 3 + 2];
}
}
}
float dehazeing::NFTrsEstimationColor(int *pnImageR, int *pnImageG, int *pnImageB, int nStartX, int nStartY, int nWid, int nHei){
int nCounter;
int nX, nY;
int nEndX;
int nEndY;
int nOutR, nOutG, nOutB;
int nSquaredOut;
int nSumofOuts;
int nSumofSquaredOuts;
float fTrans, fOptTrs;
int nTrans;
int nSumofSLoss;
float fCost, fMinCost, fMean;
int nNumberofPixels, nLossCount;
nEndX = min(nStartX+m_nTBlockSize, nWid);
nEndY = min(nStartY+m_nTBlockSize, nHei);
nNumberofPixels = (nEndY-nStartY)*(nEndX-nStartX) * 3;
fTrans = 0.3f;
nTrans = 427;
for(nCounter=0; nCounter<7; nCounter++)
{
nSumofSLoss = 0;
nLossCount = 0;
nSumofSquaredOuts = 0;
nSumofOuts = 0;
for(nY=nStartY; nY<nEndY; nY++)
{
for(nX=nStartX; nX<nEndX; nX++)
{
nOutB = ((pnImageB[nY*nWid+nX] - m_anAirlight[0])*nTrans + 128*m_anAirlight[0])>>7; // (I-A)/t + A -. ((I-A)*k*128 + A*128)/128
nOutG = ((pnImageG[nY*nWid+nX] - m_anAirlight[1])*nTrans + 128*m_anAirlight[1])>>7;
nOutR = ((pnImageR[nY*nWid+nX] - m_anAirlight[2])*nTrans + 128*m_anAirlight[2])>>7;
if(nOutR>255)
{
nSumofSLoss += (nOutR - 255)*(nOutR - 255);
nLossCount++;
}
else if(nOutR < 0)
{
nSumofSLoss += nOutR * nOutR;
nLossCount++;
}
if(nOutG>255)
{
nSumofSLoss += (nOutG - 255)*(nOutG - 255);
nLossCount++;
}
else if(nOutG < 0)
{
nSumofSLoss += nOutG * nOutG;
nLossCount++;
}
if(nOutB>255)
{
nSumofSLoss += (nOutB - 255)*(nOutB - 255);
nLossCount++;
}
else if(nOutB < 0)
{
nSumofSLoss += nOutB * nOutB;
nLossCount++;
}
nSumofSquaredOuts += nOutB * nOutB + nOutR * nOutR + nOutG * nOutG;;
nSumofOuts += nOutR + nOutG + nOutB;
}
}
fMean = (float)(nSumofOuts)/(float)(nNumberofPixels);
fCost = m_fLambda1 * (float)nSumofSLoss/(float)(nNumberofPixels)
- ((float)nSumofSquaredOuts/(float)nNumberofPixels - fMean*fMean);
if(nCounter==0 || fMinCost > fCost)
{
fMinCost = fCost;
fOptTrs = fTrans;
}
fTrans += 0.1f;
nTrans = (int)(1.0f/fTrans*128.0f);
}
return fOptTrs;
}
float dehazeing::NFTrsEstimationPColor(int *pnImageR, int *pnImageG, int *pnImageB, int *pnImageRP, int *pnImageGP, int *pnImageBP, float *pfTransmissionP, int nStartX, int nStartY, int nWid, int nHei){
int nCounter;
int nX, nY;
int nEndX;
int nEndY;
float fMean;
int nOutR, nOutG, nOutB;
float fPreTrs;
int nSquaredOut;
int nSumofOuts;
int nSumofSquaredOuts;
int nTrans;
int nSumofSLoss;
float fCost, fMinCost, fTrans, fOptTrs;
int nNumberofPixels;
nEndX = min(nStartX+m_nTBlockSize, nWid);
nEndY = min(nStartY+m_nTBlockSize, nHei);
nNumberofPixels = (nEndY-nStartY)*(nEndX-nStartX) * 3;
fTrans = 0.3f;
nTrans = 427;
fPreTrs = 0;
float fNewKSum = 0;
float fNewK;
float fWiR, fWiG, fWiB;
float fPreJR, fPreJG, fPreJB;
float fWsum = 0;
int nIdx = 0;
int nLossCount;
for(nY=nStartY; nY<nEndY; nY++)
{
for(nX=nStartX; nX<nEndX; nX++)
{
fPreJB = (float)(pnImageBP[nY*nWid+nX]-m_anAirlight[0]);
fPreJG = (float)(pnImageGP[nY*nWid+nX]-m_anAirlight[1]);
fPreJR = (float)(pnImageRP[nY*nWid+nX]-m_anAirlight[2]);
if(fPreJB != 0){
fWiB = m_pfExpLUT[abs(pnImageB[nY*nWid+nX]-pnImageBP[nY*nWid+nX])];
fWsum += fWiB;
fNewKSum += fWiB*(float)(pnImageB[nY*nWid+nX]-m_anAirlight[0])/fPreJB;
}
if(fPreJG != 0){
fWiG = m_pfExpLUT[abs(pnImageG[nY*nWid+nX]-pnImageGP[nY*nWid+nX])];
fWsum += fWiG;
fNewKSum += fWiG*(float)(pnImageG[nY*nWid+nX]-m_anAirlight[1])/fPreJG;
}
if(fPreJR != 0){
fWiR = m_pfExpLUT[abs(pnImageR[nY*nWid+nX]-pnImageRP[nY*nWid+nX])];
fWsum += fWiR;
fNewKSum += fWiR*(float)(pnImageR[nY*nWid+nX]-m_anAirlight[2])/fPreJR;
}
}
}
fNewK = fNewKSum/fWsum;
fPreTrs = pfTransmissionP[nStartY*nWid+nStartX]*fNewK;
for(nCounter=0; nCounter<7; nCounter++)
{
nSumofSLoss = 0;
nLossCount = 0;
nSumofSquaredOuts = 0;
nSumofOuts = 0;
for(nY=nStartY; nY<nEndY; nY++)
{
for(nX=nStartX; nX<nEndX; nX++)
{
nOutB = ((pnImageB[nY*nWid+nX] - m_anAirlight[0])*nTrans + 128*m_anAirlight[0])>>7;
nOutG = ((pnImageG[nY*nWid+nX] - m_anAirlight[1])*nTrans + 128*m_anAirlight[1])>>7;
nOutR = ((pnImageR[nY*nWid+nX] - m_anAirlight[2])*nTrans + 128*m_anAirlight[2])>>7; // (I-A)/t + A -. ((I-A)*k*128 + A*128)/128
if(nOutR>255)
{
nSumofSLoss += (nOutR - 255)*(nOutR - 255);
nLossCount++;
}
else if(nOutR < 0)
{
nSumofSLoss += nOutR * nOutR;
nLossCount++;
}
if(nOutG>255)
{
nSumofSLoss += (nOutG - 255)*(nOutG - 255);
nLossCount++;
}
else if(nOutG < 0)
{
nSumofSLoss += nOutG * nOutG;
nLossCount++;
}
if(nOutB>255)
{
nSumofSLoss += (nOutB - 255)*(nOutB - 255);
nLossCount++;
}
else if(nOutB < 0)
{
nSumofSLoss += nOutB * nOutB;
nLossCount++;
}
nSumofSquaredOuts += nOutB * nOutB + nOutR * nOutR + nOutG * nOutG;
nSumofOuts += nOutR + nOutG + nOutB;
}
}
fMean = (float)(nSumofOuts)/(float)(nNumberofPixels);
fCost = m_fLambda1 * (float)nSumofSLoss/(float)(nNumberofPixels)
- ((float)nSumofSquaredOuts/(float)nNumberofPixels - fMean*fMean)
+ m_fLambda2/fPreTrs/fPreTrs*fWsum/(float)nNumberofPixels*((fPreTrs-fTrans)*(fPreTrs-fTrans)*255.0f*255.0f);
if(nCounter==0 || fMinCost > fCost)
{
fMinCost = fCost;
fOptTrs = fTrans;
}
fTrans += 0.1f;
nTrans = (int)(1/fTrans*128.0f);
}
return fOptTrs;
}
void dehazeing::TransmissionEstimationColor(int *pnImageR, int *pnImageG, int *pnImageB, float *pfTransmission,int *pnImageRP, int *pnImageGP, int *pnImageBP, float *pfTransmissionP,int nFrame, int nWid, int nHei)
{
int nX, nY, nXstep, nYstep;
float fTrans;
if(m_bPreviousFlag == true && nFrame>0)
{
for(nY=0; nY<nHei; nY += m_nTBlockSize)
{
for(nX=0; nX<nWid; nX += m_nTBlockSize)
{
fTrans = NFTrsEstimationPColor(pnImageR, pnImageG, pnImageB, pnImageRP, pnImageGP, pnImageBP, pfTransmissionP, max(nX, 0), max(nY, 0), nWid, nHei);
for(nYstep=nY; nYstep<nY+m_nTBlockSize; nYstep++)
{
for(nXstep=nX; nXstep<nX+m_nTBlockSize; nXstep++)
{
pfTransmission[nYstep*nWid+nXstep] = fTrans;
}
}
}
}
}
else
{
for(nY=0; nY<nHei; nY+=m_nTBlockSize)
{
for(nX=0; nX<nWid; nX+=m_nTBlockSize)
{
fTrans = NFTrsEstimationColor(pnImageR, pnImageG, pnImageB, max(nX, 0), max(nY, 0), nWid, nHei);
for(nYstep=nY; nYstep<nY+m_nTBlockSize; nYstep++)
{
for(nXstep=nX; nXstep<nX+m_nTBlockSize; nXstep++)
{
pfTransmission[nYstep*nWid+nXstep] = fTrans;
}
}
}
}
}
}
void dehazeing::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;
}
void dehazeing::BoxFilter2(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;
}
void dehazeing::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];
}
void dehazeing::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);
BoxFilter2(pfImageR, pfImageG, pfImageB, m_nGBlockSize, nW, nH, pfMeanIr, pfMeanIg, pfMeanIb);
BoxFilter2(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
BoxFilter2(pfInitVarIrr, pfInitVarIrg, pfInitVarIrb, m_nGBlockSize, nW, nH, pfVarIrr, pfVarIrg, pfVarIrb);
BoxFilter2(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;
}
// 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
BoxFilter2(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;
}
void dehazeing::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);
}
}
}
}
}
}
void dehazeing::RestoreImage(Mat imInput, Mat &imOutput){
IplImage imageInput = IplImage(imInput);
IplImage imageOutput = IplImage(imOutput);
int nStep = imageInput.widthStep;
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(imageInput, imageOutput);
}
else
{
#pragma omp parallel for
// (2) I' = (I - Airlight)/Transmission + Airlight
for(int nY = 0; nY<m_nHei; nY++)
{
for(int nX = 0; nX<m_nWid; nX++)
{
// (3) Gamma correction using LUT
imageOutput.imageData[nY*nStep+nX*3] = (uchar)m_pucGammaLUT[(uchar)CLIP((((float)((uchar)imageInput.imageData[nY*nStep+nX*3+0])-fA_B)/CLIP_Z(m_pfTransmissionR[nY*m_nWid+nX]) + fA_B))];
imageOutput.imageData[nY*nStep+nX*3+1] = (uchar)m_pucGammaLUT[(uchar)CLIP((((float)((uchar)imageInput.imageData[nY*nStep+nX*3+1])-fA_G)/CLIP_Z(m_pfTransmissionR[nY*m_nWid+nX]) + fA_G))];
imageOutput.imageData[nY*nStep+nX*3+2] = (uchar)m_pucGammaLUT[(uchar)CLIP((((float)((uchar)imageInput.imageData[nY*nStep+nX*3+2])-fA_R)/CLIP_Z(m_pfTransmissionR[nY*m_nWid+nX]) + fA_R))];
}
}
}
namedWindow("imgIpl3", 1);
cvShowImage("imgIpl3", &imageOutput);
waitKey(0);
imOutput = cvarrToMat(&imageOutput);
}
void dehazeing::ImageHazeRemoval(Mat imInput, Mat &imOutput) {
Mat imAir = imInput.clone();
MakeExpLUT();
GuideLUTMaker();
GammaLUTMaker(0.7f);
AirlightEstimation(imInput);
ImageToIntColor(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);
RestoreImage(imInput, imOutput);
}
主函数
#include <time.h>
#include <iostream>
#include <opencv2/opencv.hpp>
#include <HazeRemoval/dehazeing.h>
using namespace std;
using namespace cv;
int main(int argc, char *argv[]){
Mat imInput = cv::imread("/mnt/hgfs/shared/opencv-test-project/42.jpg");
int nWidth = imInput.cols;
int nHeight = imInput.rows;
Mat imOutput = Mat(imInput.size(), imInput.type());
dehazeing dehazeingImage(nWidth, nHeight, 30, false, false, 5.0f, 1.0f, 40);
dehazeingImage.ImageHazeRemoval(imInput, imOutput);
return 0;
}
处理效果
总之,复现出来的效果还是不经如意吧。作者源码里面还有很多功能函数我没有去尝试,可能搭配其他的函数效果会更佳,最后,希望大神们有需要的,复现优化之后,能够把代码贴出来吧。作者都放出源码了,大家就没必要藏着掩着了。