OpenCV 频率域实现钝化模板、高提升滤波和高频强调滤波 C++

为什么要进行高频提升和高频加强?

高频滤波后的图像,其背景平均强度 减小到接近黑色(因为高通滤波器滤除 了傅里叶变换的零频率成分: F(0,0)=f(x,y)=0)

解决办法:把原始图像加到过滤后的 结果,如拉普拉斯算子增强,这种处理 称为高频提升过滤

 

钝化模板(锐化或高通图像):从一幅图像减去 其自身模糊图像而生成的锐化图像构成。在频率 域,即从图像本身减去低通滤波(模糊)后的图 像而得到高通滤波(锐化)的图像。

钝化模板:

                                                f_{hp}(x,y)=g_{mask}(x,y)=f(x,y)-f_{LP}(x,y)

与                                            f_{LP}(x,y)=\Im ^{-1}\left [ H_{LP}(u,v)F(u,v) \right ]

式中H_{LP}(u,v) 是一个低通滤波器,F(u,v)是f(x,y)的傅里叶变换。这里f_{LP}(x,y)是平滑后的图像,该图像类似于f^{-}(x,y)

 

高频提升过滤:

增加权重系数A

f_{hp}(x,y)=Af(x,y)-f_{lp}(x,y)=(A-1)f(x,y)+f_{hp}(x,y)

所以,当A=1,即高通过滤;当A>1,累加图像本身

由                                           H_{hp}(u,v)=1-H_{lp}(u,v)

高频提升过滤定义为:          H_{hp}(u,v)=(A-1)+H_{hp}(u,v)

 

系数k推导:

在原图像上加上该模板的权重部分g(x,y)=f(x,y)+k*g_{mask}(x,y)

当k=1时 原图像加上钝化模板,k>1时高提升滤波器;

在频率域有

                                       g(x,y)=\Im ^{-1}\left \{ \left [ 1+k*\left [ 1-H_{lp}(u,v) \right ] \right ]F(u,v) \right \}=\Im ^{-1}\left \{ \left [ 1+k*H_{hp}(u,v) \right ]F(u,v) \right \}

 

\left [ 1+k*H_{hp}(u,v) \right ]称为高频强调滤波器。如前面说的那样,高频滤波器将直流项设置为0,这样就把滤波后图像的平均灰度减小为0,。高频强调滤波器不存在这一问题,因为高通项上加了1。常数k决定了影响最终结果的高频比例。

 

高频提升加强:

更为一般的公式

                                        H_{hp}(u,v)=a+bH_{hp}(u,v)                    a >= 0, b >a

                                   g(x,y)=\Im ^{-1}\left \{ \left [ a+b*H_{hp}(u,v) \right ]F(u,v) \right \}

 用图像的高频成分进行增强

当a=A-1,b=1时转化为高频提升过滤

当b>1,高频得到加强,b控制高频的贡献

增加a的目的是使零频率不被滤波器过滤,a控制矩原点的偏移量
OpenCV 频率域实现钝化模板、高提升滤波和高频强调滤波 C++_第1张图片

例子:

使用高斯高通,D0=40,a=0.5,b=0.75

效果图:

 

代码实现:

#include "opencv2/opencv.hpp"

cv::Mat image_add_border( cv::Mat &src )
{
    int w=2*src.cols;
    int h=2*src.rows;
    std::cout << "src: " << src.cols << "*" << src.rows << std::endl;

    cv::Mat padded;
    copyMakeBorder( src, padded, 0, h-src.rows, 0, w-src.cols,
                    cv::BORDER_CONSTANT, cv::Scalar::all(0));
    padded.convertTo(padded,CV_32FC1);
    std::cout << "opt: " << padded.cols << "*" << padded.rows << std::endl;
    return padded;
}

//transform to center 中心化
void center_transform( cv::Mat &src )
{
    for(int i=0; i         float *p = src.ptr(i);
        for(int j=0; j             p[j] = p[j] * pow(-1, i+j);
        }
    }
}

//对角线交换内容
void zero_to_center(cv::Mat &freq_plane)
{
//    freq_plane = freq_plane(Rect(0, 0, freq_plane.cols & -2, freq_plane.rows & -2));
    //这里为什么&上-2具体查看opencv文档
    //其实是为了把行和列变成偶数 -2的二进制是11111111.......10 最后一位是0
    int cx=freq_plane.cols/2;int cy=freq_plane.rows/2;//以下的操作是移动图像  (零频移到中心)
    cv::Mat part1_r(freq_plane, cv::Rect(0,0,cx,cy));  //元素坐标表示为(cx,cy)
    cv::Mat part2_r(freq_plane, cv::Rect(cx,0,cx,cy));
    cv::Mat part3_r(freq_plane, cv::Rect(0,cy,cx,cy));
    cv::Mat part4_r(freq_plane, cv::Rect(cx,cy,cx,cy));

    cv::Mat tmp;
    part1_r.copyTo(tmp);  //左上与右下交换位置(实部)
    part4_r.copyTo(part1_r);
    tmp.copyTo(part4_r);

    part2_r.copyTo(tmp);  //右上与左下交换位置(实部)
    part3_r.copyTo(part2_r);
    tmp.copyTo(part3_r);
}


void show_spectrum( cv::Mat &complexI )
{
    cv::Mat temp[] = {cv::Mat::zeros(complexI.size(),CV_32FC1),
                      cv::Mat::zeros(complexI.size(),CV_32FC1)};
    //显示频谱图
    cv::split(complexI, temp);
    cv::Mat aa;
    cv::magnitude(temp[0], temp[1], aa);
//    zero_to_center(aa);
    cv::divide(aa, aa.cols*aa.rows, aa);
    cv::imshow("src_img_spectrum",aa);
}

//频率域滤波
cv::Mat frequency_filter(cv::Mat &padded,cv::Mat &blur)
{
    cv::Mat plane[]={padded, cv::Mat::zeros(padded.size(), CV_32FC1)};
    cv::Mat complexIm;

    cv::merge(plane,2,complexIm);
    cv::dft(complexIm,complexIm);//fourior transform
    show_spectrum(complexIm);

    cv::multiply(complexIm, blur, complexIm);
    cv::idft(complexIm, complexIm, CV_DXT_INVERSE);       //idft
    cv::Mat dst_plane[2];
    cv::split(complexIm, dst_plane);
    center_transform(dst_plane[0]);
//    center_transform(dst_plane[1]);

    cv::magnitude(dst_plane[0],dst_plane[1],dst_plane[0]);  //求幅值(模)
//    center_transform(dst_plane[0]);        //center transform

    return dst_plane[0];
}

//高斯高通滤波器
cv::Mat gaussian_high_kernel( cv::Mat &scr, float D0 )
{
    cv::Mat gaussian_high_pass(scr.size(),CV_32FC2);
    int row_num = scr.rows;
    int col_num = scr.cols;
    float d0 = 2 * D0 * D0;
    for(int i=0; i         float *p = gaussian_high_pass.ptr(i);
        for(int j=0; j             float d = pow((i - row_num/2),2) + pow((j - col_num/2),2);
            p[2*j]   = 0.5 + 0.75*(1 - expf(-d/d0));
            p[2*j+1] = 0.5 + 0.75*(1 - expf(-d/d0));
        }
    }

    cv::Mat temp[] = { cv::Mat::zeros(scr.size(), CV_32FC1),
                       cv::Mat::zeros(scr.size(), CV_32FC1) };
    cv::split(gaussian_high_pass, temp);
    std::string name = "高斯高通滤波器d0=" + std::to_string(D0);
    cv::Mat show;
    cv::normalize(temp[0], show, 1, 0, CV_MINMAX);
    cv::imshow(name, show);
    return gaussian_high_pass;
}

//高斯高通滤波器
cv::Mat gaussian_highpass_filter(cv::Mat &src,  float D0 )
{
    cv::Mat padded = image_add_border(src);
    center_transform( padded );
    cv::Mat gaussian_kernel = gaussian_high_kernel(padded,D0 );
    cv::Mat result = frequency_filter(padded,gaussian_kernel);
    return result;
}

int main(int argc, char * argv[])
{
    if( argc != 3 ){
        std::cerr << "Usage: " << argv[0] << " " << std::endl;
        return -1;
    }

    cv::Mat image = cv::imread(argv[1], cv::IMREAD_GRAYSCALE);
    if( image.empty() )
        return -1;
    float radius = std::stof( argv[2] );
//    cv::resize( image, image, cv::Size(), 0.25, 0.25);
    cv::imshow("src",image);
    cv::Mat src_eq;
    cv::equalizeHist( image, src_eq );
    cv::imshow("src_eq",src_eq);
    cv::Mat gaussian_result = gaussian_highpass_filter(image, radius);
    gaussian_result = gaussian_result( cv::Rect(0, 0, image.cols, image.rows) );

    cv::normalize(gaussian_result, gaussian_result, 255, 0, CV_MINMAX);
    gaussian_result.convertTo(gaussian_result, CV_8U);
     cv::equalizeHist( gaussian_result, gaussian_result );
    cv::imshow("gaussian_result",gaussian_result);
    cv::waitKey(0);

    return 1;
}


 

 

 

你可能感兴趣的:(OpenCV,C++,数字图像处理,OpenCV,C++数字图像处理,冈萨雷斯第三版)