OpenCV:同态滤波器

时间:2014-05-19 14:53:55

标签: c++ opencv image-processing filtering fft

我想使用同态滤镜来处理水下图像。我尝试使用互联网上的代码对其进行编码,但我总是使用黑色图像...我试图将结果标准化但是没有用。

这是我的职能:

void HomomorphicFilter::butterworth_homomorphic_filter(Mat &dft_Filter, int D, int n, float high_h_v_TB, float low_h_v_TB)
{
Mat single(dft_Filter.rows, dft_Filter.cols, CV_32F);
Point centre = Point(dft_Filter.rows/2, dft_Filter.cols/2);
double radius;
float upper = (high_h_v_TB * 0.01);
float lower = (low_h_v_TB * 0.01);

//create essentially create a butterworth highpass filter
//with additional scaling and offset
for(int i = 0; i < dft_Filter.rows; i++)
{
    for(int j = 0; j < dft_Filter.cols; j++)
    {
        radius = (double) sqrt(pow((i - centre.x), 2.0) + pow((double) (j - centre.y), 2.0));
        single.at<float>(i,j) =((upper - lower) * (1/(1 + pow((double) (D/radius), (double) (2*n))))) + lower;
    }
}
//normalize(single, single, 0, 1, CV_MINMAX);
//Apply filter
mulSpectrums( dft_Filter, single, dft_Filter, 0);
}

void HomomorphicFilter::Shifting_DFT(Mat &fImage)
{
//For visualization purposes we may also rearrange the quadrants of the result, so that the origin (0,0), corresponds to the image center.
Mat tmp, q0, q1, q2, q3;

/*First crop the image, if it has an odd number of rows or columns.
Operator & bit to bit by -2 (two's complement : -2 = 111111111....10) to eliminate the first bit 2^0 (In case of odd number on row or col, we take the even number in below)*/
fImage = fImage(Rect(0, 0, fImage.cols & -2, fImage.rows & -2));
int cx = fImage.cols/2;
int cy = fImage.rows/2;

/*Rearrange the quadrants of Fourier image so that the origin is at the image center*/
q0 = fImage(Rect(0, 0, cx, cy));
q1 = fImage(Rect(cx, 0, cx, cy));
q2 = fImage(Rect(0, cy, cx, cy));
q3 = fImage(Rect(cx, cy, cx, cy));

/*We reverse each quadrant of the frame with its other quadrant diagonally opposite*/
/*We reverse q0 and q3*/
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);

/*We reverse q1 and q2*/
q1.copyTo(tmp);
q2.copyTo(q1);
tmp.copyTo(q2);
}

void HomomorphicFilter::Fourier_Transform(Mat frame_bw, Mat &image_phase, Mat &image_mag)
{
Mat frame_log;
frame_bw.convertTo(frame_log, CV_32F);
/*Take the natural log of the input (compute log(1 + Mag)*/
frame_log += 1;
log( frame_log, frame_log); // log(1 + Mag)

/*2. Expand the image to an optimal size
The performance of the DFT depends of the image size. It tends to be the fastest for image sizes that are multiple of 2, 3 or 5.
We can use the copyMakeBorder() function to expand the borders of an image.*/
Mat padded;
int M = getOptimalDFTSize(frame_log.rows);
int N = getOptimalDFTSize(frame_log.cols);
copyMakeBorder(frame_log, padded, 0, M - frame_log.rows, 0, N - frame_log.cols, BORDER_CONSTANT, Scalar::all(0));

/*Make place for both the complex and real values
The result of the DFT is a complex. Then the result is 2 images (Imaginary + Real), and the frequency domains range is much larger than the spatial one. Therefore we need to store in float !
That's why we will convert our input image "padded" to float and expand it to another channel to hold the complex values.
Planes is an arrow of 2 matrix (planes[0] = Real part, planes[1] = Imaginary part)*/
Mat image_planes[] = {Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F)};
Mat image_complex;
/*Creates one multichannel array out of several single-channel ones.*/
merge(image_planes, 2, image_complex);

/*Make the DFT
The result of thee DFT is a complex image : "image_complex"*/
dft(image_complex, image_complex);

/***************************/
//Create spectrum magnitude//
/***************************/
/*Transform the real and complex values to magnitude
NB: We separe Real part to Imaginary part*/
split(image_complex, image_planes);
//Starting with this part we have the real part of the image in planes[0] and the imaginary in planes[1]
phase(image_planes[0], image_planes[1], image_phase);
magnitude(image_planes[0], image_planes[1], image_mag);
}

void HomomorphicFilter::Inv_Fourier_Transform(Mat image_phase, Mat image_mag, Mat &inverseTransform)
{
/*Calculates x and y coordinates of 2D vectors from their magnitude and angle.*/
Mat result_planes[2];
polarToCart(image_mag, image_phase, result_planes[0], result_planes[1]);

/*Creates one multichannel array out of several single-channel ones.*/
Mat result_complex;
merge(result_planes, 2, result_complex);

/*Make the IDFT*/
dft(result_complex, inverseTransform, DFT_INVERSE|DFT_REAL_OUTPUT);

/*Take the exponential*/
exp(inverseTransform, inverseTransform);
}

这里是我的主要代码:

    /**************************/
    /****Homomorphic filter****/
    /**************************/
    /**********************************************/
    //Getting the frequency and magnitude of image//
    /**********************************************/
    Mat image_phase, image_mag;
    HomomorphicFilter().Fourier_Transform(frame_bw, image_phase, image_mag);
    /******************/
    //Shifting the DFT//
    /******************/
    HomomorphicFilter().Shifting_DFT(image_mag);
    /********************************/
    //Butterworth homomorphic filter//
    /********************************/
    int high_h_v_TB = 101;
    int low_h_v_TB = 99;
    int D = 10;// radius of band pass filter parameter
    int order = 2;// order of band pass filter parameter
    HomomorphicFilter().butterworth_homomorphic_filter(image_mag, D, order, high_h_v_TB, low_h_v_TB);
    /******************/
    //Shifting the DFT//
    /******************/
    HomomorphicFilter().Shifting_DFT(image_mag);
    /*******************************/
    //Inv Discret Fourier Transform//
    /*******************************/
    Mat inverseTransform;
    HomomorphicFilter().Inv_Fourier_Transform(image_phase, image_mag, inverseTransform);
    imshow("Result", inverseTransform);

如果有人能解释我的错误,我会非常感激:)。谢谢,抱歉我的英语很差。

编辑:现在,我有一些东西,但它并不完美......我在代码中修改了两件事。 我在dft之后应用log(mag + 1)而不是输入图像。 我在idft之后删除了exp()。

这里的结果(我只能发布2个链接......):

我的输入图片:http://i.imgur.com/Kw0Wdo4.png 最终结果:http://i.imgur.com/7AX9j5u.png

在看过几个主题之后,我在我的butterworth过滤器上发现了类似的结果,并在dft / shift后发现了我的幅度。 不幸的是,我的最终结果并不是很好。为什么我有这么多&#34;噪音&#34; ?

2 个答案:

答案 0 :(得分:3)

我正在使用此方法来平衡相机更换时的照明导致图像变暗!

我尝试使用FFT来频率来过滤图像!这是工作。但是使用太多时间。(2750 * 3680RGB图片)。所以我在Spatial域中做。

这是我的代码!

//IplImage *imgSrcI=cvLoadImage("E:\\lean.jpg",-1);
Mat imgSrcM(imgSrc,true);
Mat imgDstM;

Mat imgGray;
Mat imgHls;
vector<Mat> vHls;

Mat imgTemp1=Mat::zeros(imgSrcM.size(),CV_64FC1);
Mat imgTemp2=Mat::zeros(imgSrcM.size(),CV_64FC1);

if(imgSrcM.channels()==1)
{
    imgGray=imgSrcM.clone();
}
else if (imgSrcM.channels()==3)
{
    cvtColor(imgSrcM, imgHls, CV_BGR2HLS);
    split(imgHls, vHls);
    imgGray=vHls.at(1);
}
else
{
    return -1;
}
imgGray.convertTo(imgTemp1,CV_64FC1);
imgTemp1=imgTemp1+0.0001;
log(imgTemp1,imgTemp1);

GaussianBlur(imgTemp1, imgTemp2, Size(21, 21), 0.1, 0.1, BORDER_DEFAULT);//imgTemp2是低通滤波的结果
imgTemp1 = (imgTemp1 - imgTemp2);//imgTemp1是对数减低通的高通
addWeighted(imgTemp2, 0.7, imgTemp1, 1.4, 1, imgTemp1, -1);//imgTemp1是压制低频增强高频的结构

exp(imgTemp1,imgTemp1);
normalize(imgTemp1,imgTemp1,0,1,NORM_MINMAX);
imgTemp1=imgTemp1*255;

imgTemp1.convertTo(imgGray, CV_8UC1);

//imwrite("E:\\leanImgGray.jpg",imgGray);
if (imgSrcM.channels()==3)
{
    vHls.at(1)=imgGray;
    merge(vHls,imgHls);
    cvtColor(imgHls, imgDstM, CV_HLS2BGR);

}
else if (imgSrcM.channels()==1)
{
    imgDstM=imgGray.clone();
}

cvCopy(&(IplImage)imgDstM,imgDst);
//cvShowImage("jpg",imgDst);

return 0;

答案 1 :(得分:1)

我在几个地方修改了你的代码,并且在均值滤波器输出方面得到了不错的结果。

以下是我所做的更正。

1) 而不是只在image_mag上工作,而是处理FFT的完整输出。

2) 您的过滤器值high_h_v_TB = 101和low_h_v_TB = 99几乎不会对过滤产生什么影响。

以下是我使用的值。

int high_h_v_TB = 100;
int low_h_v_TB = 20;
int D = 10;// radius of band pass filter parameter
int order = 4;

这是我的主要代码

//float_img == grayscale image in 0-1 scale
Mat log_img;
log(float_img, log_img);


Mat fft_phase, fft_mag;
Mat fft_complex;
HomomorphicFilter::Fourier_Transform(log_img, fft_complex);
HomomorphicFilter::ShiftFFT(fft_complex);

int high_h_v_TB = 100;
int low_h_v_TB = 30;
int D = 10;// radius of band pass filter parameter
int order = 4;

//get a butterworth filter of same image size as the input image
//dont call mulSpectrums yet, just get the filter of correct size
Mat butterWorthFreqDomain;
HomomorphicFilter::ButterworthFilter(fft_complex.size(), butterWorthFreqDomain,  D, order, high_h_v_TB, low_h_v_TB);


//this should match fft_complex in size and type
//and is what we will be using for 'mulSpectrums' call
Mat butterworth_complex;
//make two channels to match fft_complex
Mat butterworth_channels[] = {Mat_<float>(butterWorthFreqDomain.size()), Mat::zeros(butterWorthFreqDomain.size(), CV_32F)};
merge(butterworth_channels, 2, butterworth_complex);


//do mulSpectrums on the full fft
mulSpectrums(fft_complex, butterworth_complex, fft_complex, 0);

//shift back the output
HomomorphicFilter::ShiftFFT(fft_complex);
Mat log_img_out;

HomomorphicFilter::Inv_Fourier_Transform(fft_complex,  log_img_out);

Mat float_img_out;
exp(log_img_out, float_img_out);
//float_img_out is gray in 0-1 range

这是我的输出。 Here is my output