OpenCV C++(十一)----频率域滤波

2020-03-08  本文已影响0人  肉松饼饼

11.1概述和原理

频率域滤波器在程序或者数学运算中的呈现可以理解为一个矩阵。下面所涉及的常用的低通、 高通、 带通、 带阻 等滤波的关键步骤, 就是通过一定的准则构造该矩阵的。

image.png

算法步骤:

11.2、低通滤波器和高通滤波器

11.2.1、低通滤波器

1、理想低通滤波器

image.png

2、巴特沃斯低通滤波器

image.png

3、高斯低通滤波器

image.png
//创建三种常见的低通滤波器
enum FILTER_TYPE {
    ILP_FILTER = 0,
    BLP_FILTER = 1,
    GLP_FILTER = 2
};

Mat creatLPFilter(Size size, Point center, float radius, FILTER_TYPE type, int n)
{
    Mat lpFilter = Mat::zeros(size, CV_32FC1);
    int rows = size.height;
    int cols = size.width;
    if (radius <= 0)
    {
        return lpFilter;
    }
    //构建理想低通滤波器
    if (type == ILP_FILTER)
    {
        for (int r = 0; r < rows; r++)
        {
            for (int c = 0; c < cols; c++)
            {
                float norm2 = pow(abs(float(r - center.y)), 2) + pow(abs(float(c - center.x)), 2);
                if (sqrt(norm2) < radius)
                {
                    lpFilter.at<float>(r,c) = 1;
                }
                else
                {
                    lpFilter.at<float>(r, c) = 0;
                }
            }
        }
    }
    //构建巴特沃斯低通滤波器
    if (type == BLP_FILTER)
    {
        for (int r = 0; r < rows; r++)
        {
            for (int c = 0; c < cols; c++)
            {
                lpFilter.at<float>(r, c) = float(1.0 / (1.0 + pow(sqrt(pow(r - center.y, 2.0) + pow(c - center.x, 2.0)) / radius, 2.0*n)));
            }
        }
    }
    //构建高斯低通滤波器
    if (type == GLP_FILTER)
    {
        for (int r = 0; r < rows; r++)
        {
            for (int c = 0; c < cols; c++)
            {
                lpFilter.at<float>(r, c) = float(exp(-(pow(r - center.y, 2.0) + pow(c - center.x, 2.0)) / (2 * pow(radius, 2.0))));
            }
        }
    }
    return lpFilter;
}

Mat I;//输入的图像矩阵
Mat F;//图像的快速傅里叶变换
Point maxLoc;//傅里叶谱的最大值的坐标
int radius = 20;//截断频率
const int Max_RADIUS = 100;//设置的最大的截断频率
Mat lpFilter;//低通滤波器
int lpType = 0;//低通滤波器的类型
const int MAX_LPTYPE = 2;
Mat F_lpFilter;//低通傅里叶变换
Mat flpSpectrum;//低通傅里叶变换的傅里叶谱的灰度级
Mat result;//低通滤波后的效果
string lpFilterspectrum = "低通傅里叶谱";//显示窗口的名称
void callback_lpFilter(int, void*);
int main()
{
    //step1:读入图像矩阵
    Mat I = imread("Koala.jpg", CV_LOAD_IMAGE_GRAYSCALE);
    if (!I.data)
    {
        return -1;
    }
    //数据类型转换为浮点型
    Mat fI;
    I.convertTo(fI, CV_32FC1, 1.0, 0.0);
    //step2:每一个数乘于(-1)^(r+c)
    for (int r = 0; r < fI.rows; r++)
    {
        for (int c = 0; c < fI.cols; c++)
        {
            if ((r + c) % 2)
            {
                fI.at<float>(r, c) *= -1;
            }
        }
    }
    //step3:补零;step4:快速傅里叶变换
    fft2Image(fI, F);
    //傅里叶谱
    Mat amplSpec;
    amplitudeSpectrum(F, amplSpec);
    //傅里叶谱的灰度级显示
    Mat spectrum = graySpectrum(amplSpec);
    //找到傅里叶谱的最大值的坐标
    minMaxLoc(spectrum, NULL, NULL, NULL, &maxLoc);
    //低通滤波
    namedWindow(lpFilterspectrum, WINDOW_AUTOSIZE);
    createTrackbar("低通类型", lpFilterspectrum, &lpType, MAX_LPTYPE, callback_lpFilter);
    createTrackbar("半径", lpFilterspectrum, &radius, Max_RADIUS, callback_lpFilter);
    callback_lpFilter(0, 0);
    waitKey(0);
    return 0;
}


void callback_lpFilter(int, void*)
{
    //step5:构建低通滤波器
    lpFilter = creatLPFilter(F.size(), maxLoc, radius, lpType, 2);
    //step6:低通滤波器和图像的快速傅里叶变换点乘
    F_lpFilter.create(F.size(), F.type());
    for (int r = 0; r < F_lpFilter.rows; r++)
    {
        for (int c = 0; c < F_lpFilter.cols; c++)
        {
            //分别取出当前位置的快速傅里叶变换和理想低通滤波器的值
            Vec2f F_rc = F.at<Vec2f>(r, c);
            float lpFilter_rc = lpFilter.at<float>(r, c);
            //低通滤波器和图像的快速傅里叶变换的对应位置相乘
            F_lpFilter.at<Vec2f>(r, c) = F_rc * lpFilter_rc;
        }
    }
    //低通傅里叶变换的傅里叶谱
    amplitudeSpectrum(F_lpFilter, flpSpectrum);
    //低通傅里叶谱的灰度级显示
    flpSpectrum = graySpectrum(flpSpectrum);
    //step7、8:对低通滤波器变换执行傅里叶逆变换,并只取实部
    dft(F_lpFilter, result, DFT_SCALE + DFT_INVERSE + DFT_REAL_OUTPUT);
    //step9:同乘以(-1)^(x+y)
    for (int r = 0; r < result.rows; r++)
    {
        for (int c = 0; c < result.cols; c++)
        {
            if ((r + c) % 2)
            {
                result.at<float>(r, c)  *= -1;
            }
        }
    }
    //注意将结果转换为CV_8U类型
    result.convertTo(result, CV_8UC1, 1.0, 0);
    //step10:截取左上部分,其大小和输入图像的大小相同
    result = result(Rect(0, 0, I.cols, I.rows)).clone();
}

11.2.2、高通滤波器

1、理想高通滤波器

image.png

2、巴特沃斯高通滤波器

image.png

3、高斯高通滤波器

image.png

显然, 高通滤波器和低通滤波器满足这样的关系:

hpFilter=1-lpFilter

即1减去通过createLPFilter得到的矩阵就可以得到高通滤波器 。

11.3、带通和带阻滤波器

带通滤波是指只保留某一范围区域的频率带。

11.3.1、带通滤波器

1、理想带通滤波器

image.png

2、巴特沃斯带通滤波器

image.png

3、高斯带通滤波器

image.png

11.3.2、带阻滤波器

与带通滤波相反, 带阻滤波是指撤销或者消弱指定范围区域的频率带。

1、理想带阻滤波器

image.png

2、巴特沃斯带阻滤波器

image.png

3、高斯带阻滤波器

image.png

显然, 1减去带通滤波就可以得到相应的带阻滤波。

11.4、自定义滤波器

有一种通过交互式的方式, 构建自定义滤波, 便于消除指定的频率。 自定义滤波器通常用于消除结构化噪声或者目标。

11.5、同态滤波

同态滤波是一种减少低频增加高频,从而减少光照变化并锐化边缘或者细节的滤波方法。

对于一幅图像f(x,y),可以表示为照射分量i(x,y)和反射分量r(x,y)的乘积。
其中0<i(x,y)<∞,0<r(x,y)<1。

i(x,y)描述景物的照明,变化缓慢,处于低频成分。

r(x,y)描述景物的细节,变化较快,处于高频成分。

因为该性质是乘性的,所以不能直接使用傅里叶变换对i(x,y)和r(x,y)进行控制,因此可以先对f(x,y)取对数,分离i(x,y)和r(x,y)。令z(x,y) = ln f(x,y) = ln i(x,y) + ln r(x,y)。由于f(x,y)的取值范围为[0, L-1],为了避免出现ln(0)的情况,故采用ln ( f(x,y) + 1 ) 来计算。

image.png image.png

同态滤波与频率域滤波的不同之处是, 它在最开始对输入的图像矩阵进行对数运 算, 在最后一步进行对数运算的逆运算, 即指数运算, 其中间步骤就是频率域滤波的步骤。

上一篇下一篇

猜你喜欢

热点阅读