数字图像处理基础实验(五):频域滤波

一、实验内容及原理

1、 灰度图像的 DFT 和 IDFT

具体内容:利用 OpenCV 提供的 cvDFT 函数对图像进行 DFT 和 IDFT 变换 。

2、 利用理想高通和低通滤波器对灰度图像进行频域滤波

具体内容:利用 cvDFT 函数实现 DFT,在频域上利用理想高通和低通滤波 器进行滤波,并把滤波过后的图像显示在屏幕上(观察振铃现象),要求截止频 率可输入。

3、 利用布特沃斯高通和低通滤波器对灰度图像进行频域滤波

具体内容:利用 cvDFT 函数实现 DFT,在频域上进行利用布特沃斯高通和 低通滤波器进行滤波,并把滤波过后的图像显示在屏幕上(观察振铃现象),要 求截止频率和 n 可输入。

二、实验代码

实验环境:
(1)OpenCV3.4.3
(2)Ubuntu16.04
(3)VS Code
(4)C++

#include   
#include 
#include 
#include 
#include 
#include 

class Experiment5 {
public:
    Experiment5(std::vector path){
        filter_name.push_back("理想低通滤波器");
        filter_name.push_back("理想高通滤波器");
        filter_name.push_back("布特沃斯低通滤波器");
        filter_name.push_back("布特沃斯高通滤波器");

        for(int i = 0; i < path.size(); i++){
            original_color_image.push_back(cv::imread(path[i]));
            original_gray_image.push_back(color2Gray(original_color_image[i]));
            zeroPadding(i);
            gray_fourier.push_back(imageDFT(gray_image_padding[i]));
        }

        int row = gray_image_padding[0].rows, col = gray_image_padding[0].cols;
        makeIdealLowPassFilterKernel(row, col);
        makeIdealHighPassFilterKernel(row, col);
        makeButterworseLowPassFilterKernel(row, col);
        makeButterworseHighPassFilterKernel(row, col);
        moveFourier();
        std::cout<< "初始化结束" << "\n";
    }
    // 0 彩色图像转灰度图像
    cv::Mat color2Gray(cv::Mat& src){
        //创建与原图同类型和同大小的矩阵
	    cv::Mat gray_image = cv::Mat::zeros(src.rows, src.cols, CV_8UC1);
        if(src.channels()!=1){
            for(int i = 0; i < src.rows; i++)
                for(int j = 0; j < src.cols; j++)
                    gray_image.at(i, j) = (src.at(i, j)[0] + src.at(i, j)[1] + src.at(i, j)[2]) / 3;
        }
        else
            gray_image = src.clone();
        return gray_image;
    }
    // 0.1 零填充
    void zeroPadding(int pic_id){
        int centeri = original_gray_image[pic_id].rows, centerj = original_gray_image[pic_id].cols;
        cv::Mat image = cv::Mat::zeros(2*centeri, 2*centerj, CV_8UC1);
        image(cv::Rect(centeri/2, centerj/2, centerj, centeri)) += original_gray_image[pic_id];  
        gray_image_padding.push_back(image);
    }
    // 0.2 生成理想低通滤波器
    void makeIdealLowPassFilterKernel(int row, int col, double d0=80){
        int centeri =row/2, centerj = col/2;
        ideal_low_pass_filter = cv::Mat::zeros(row, col, CV_32F);
        for(int i=0; i < ideal_low_pass_filter.rows; i++)
            for(int j=0; j < ideal_low_pass_filter.cols; j++){
                double d = sqrt(pow(i - centeri, 2) + pow(j - centerj, 2));
                if(d < d0)
                    ideal_low_pass_filter.at(i,j) = 1;
            }
    }
    // 0.3 生成理想高通滤波器
    void makeIdealHighPassFilterKernel(int row, int col, double d0=12){
        int centeri =row/2, centerj = col/2;
        ideal_high_pass_filter = cv::Mat::zeros(row, col, CV_32F);
        for(int i=0; i < ideal_high_pass_filter.rows; i++)
            for(int j=0; j < ideal_high_pass_filter.cols; j++){
                double d = sqrt(pow(i - centeri, 2) + pow(j - centerj, 2));
                if(d > d0)
                    ideal_high_pass_filter.at(i,j) = 1;
            }
    }
    // 0.4 布特沃斯低通
    void makeButterworseLowPassFilterKernel(int row, int col, int n=2, double d0=80){
        int centeri =row/2, centerj = col/2;
        butter_low_pass_filter = cv::Mat::zeros(row, col, CV_32F);
        for(int i=0; i < butter_low_pass_filter.rows; i++)
            for(int j=0; j < butter_low_pass_filter.cols; j++){
                double d = sqrt(pow(i - centeri, 2) + pow(j - centerj, 2));
                butter_low_pass_filter.at(i,j) = 1/(1 + pow(d/d0,n));
            }
    }
    // 0.5 布特沃斯高通
    void makeButterworseHighPassFilterKernel(int row, int col, int n=2, double d0=10){
        int centeri =row/2, centerj = col/2;
        butter_high_pass_filter = cv::Mat::zeros(row, col, CV_32F);
        for(int i=0; i < butter_high_pass_filter.rows; i++)
            for(int j=0; j < butter_high_pass_filter.cols; j++){
                double d = sqrt(pow(i - centeri, 2) + pow(j - centerj, 2));
                butter_high_pass_filter.at(i,j) = 1/(1 + pow(d0/d,n));
            }
    }
    // 0.6 傅里叶变换
    cv::Mat imageDFT(cv::Mat& src_image){
        cv::Mat src, fourier;
        cv::Mat image = src_image;
        // 实部:图像 , 虚部:全部用0填充
        cv::Mat re_im[] = {cv::Mat_(image), cv::Mat::zeros(image.size(), CV_32FC1)};
        // 将实部与虚部合并,形成一个复数
        cv::merge(re_im, 2, src);
        // 离散傅里叶变换
        cv::dft(src, fourier);
        return fourier;
    }
    // 0.7 移动傅里叶变换,将低频从四个角,移动到中心
    void moveFourier(){
        cv::Mat src = gray_image_padding[0];
        //int row = src.rows, col = src.cols;
        for(int i = 0; i < gray_fourier.size(); i++){
            cv::Mat fourier = gray_fourier[i];
            cv::Mat plane[]={cv::Mat_(src), cv::Mat::zeros(src.size() , CV_32FC1)}; //创建通道,存储dft后的实部与虚部(CV_32F,必须为单通道数)
            cv::split(fourier, plane);
            cv::Mat tempu;
            // 获取未移动时的频谱
            cv::magnitude(plane[0],plane[1],tempu);
            tempu += cv::Scalar::all(1);
            cv::log(tempu, tempu);
            // 归一化操作
            cv::normalize(tempu, tempu, 1, 0, CV_MINMAX);
            gray_fourier_re.push_back(tempu);
            // 以下的操作是移动图像  (零频移到中心)
            shiftCenter(plane[0]);  // 实部
            shiftCenter(plane[1]);  // 虚部
            // 存入向量
            cv::Mat temp0 = plane[0].clone();
            cv::Mat temp1 = plane[1].clone();
            std::vector temp;
            temp.push_back(temp0);
            temp.push_back(temp1);
            gray_fourier_center.push_back(temp);
            // 获取原始图像的频谱图
            cv::magnitude(plane[0],plane[1],plane[0]);
            plane[0] += cv::Scalar::all(1);
            cv::log(plane[0],plane[0]);
            // 归一化操作便于显示
            cv::normalize(plane[0],plane[0],1,0,CV_MINMAX);
            gray_fourier_center_re.push_back(plane[0]);
        }
    }
    // 0.8 移动到中心
    void shiftCenter(cv::Mat& mat){
        int cx = mat.cols/2;
        int cy = mat.rows/2;
        //元素坐标表示为(cx,cy)
        cv::Mat part1(mat,cv::Rect(0,0,cx,cy));      
        cv::Mat part2(mat,cv::Rect(cx,0,cx,cy));
        cv::Mat part3(mat,cv::Rect(0,cy,cx,cy));
        cv::Mat part4(mat,cv::Rect(cx,cy,cx,cy));
        cv::Mat temp;
        // 位置交换
        part1.copyTo(temp); //左上与右下交换位置
        part4.copyTo(part1);
        temp.copyTo(part4);
        part2.copyTo(temp); //右上与左下交换位置
        part3.copyTo(part2);
        temp.copyTo(part3);
    }
    // 0.9 计算Mat类型的指数
    void MatPow(cv::Mat& src, double exp){
        for(int i = 0; i < src.rows; i++)
            for(int j = 0; j < src.cols; j++)
                src.at(i, j) = pow(src.at(i, j), exp);
    }
    // 2 频域滤波
    void frequencyDomainFilter(int select=0){
        cv::Mat filter_kernel;
        cv::Mat re, im;
        cv::Mat blur_r, blur_i, blur;
        for(int i = 0; i < gray_fourier_center.size(); i++){
            re = gray_fourier_center[i][0].clone();
            im = gray_fourier_center[i][1].clone();
            if(select == 0)
                filter_kernel = ideal_low_pass_filter;
            else if(select == 1)
                filter_kernel = ideal_high_pass_filter;
            else if(select == 2)
                filter_kernel = butter_low_pass_filter;
            else if(select == 3)
                filter_kernel = butter_high_pass_filter;
            // 相乘,滤波
            cv::multiply(re, filter_kernel, blur_r);
            cv::multiply(im, filter_kernel, blur_i);
            cv::Mat plane1[] = {blur_r, blur_i};
            // 实部与虚部合并
            cv::merge(plane1, 2, blur);
            imageIDFT(blur);
            moveImage(i);
        }
    }
    // 3 傅里叶逆变换
    cv::Mat imageIDFT(cv::Mat& fourier){
        cv::Mat invfourier;
        cv::idft(fourier, invfourier, 0);
        cv::Mat re_im[2];
        // 分离傅里叶变换的实部与虚部
        cv::split(invfourier, re_im);
        cv::normalize(re_im[0], re_im[0], 0, 1, CV_MINMAX); 
        gray_ifourier_center.push_back(re_im[0]);
        return re_im[0];
    }
    // 3.1 移动图像到中心位置
    void moveImage(int id){
        cv::Mat src_image = gray_ifourier_center[id];
        int row = original_gray_image[id].rows, col = original_gray_image[id].cols;
        cv::Mat dst_image = src_image(cv::Rect(row/2, col/2, col, row));
        gray_image_process.push_back(dst_image);
    }
    // 3.2 数据类型转换
    void Mat_convert2int(cv::Mat& src, cv::Mat& dst){
        double value;
        double max = findMatMax(src);
        for(int i = 0; i < src.rows; i++)
            for(int j = 0; j < src.cols; j++){
                value = 255 * src.at(i, j) / max;
                if(value > 255)
                    value = 255;
                if(value < 0)
                    value = 0;
                dst.at(i, j) = int(value);
            }
    }
    // 3.3 寻找矩阵最大值:
    double findMatMax(cv::Mat& src){
        double max = 0;
        for(int i = 0; i < src.rows; i++)
            for(int j = 0; j < src.cols; j++){
                if(src.at(i, j) > max)
                    max = src.at(i, j);
            }
        return max;
    }
    // 4 运行
    void test_filter(int id){
        frequencyDomainFilter(id);
        std::cout< filter_name;
    cv::Mat filter_kernel;

    std::vector original_color_image;
    std::vector original_gray_image;

    std::vector gray_image_padding;

    // 傅里叶变换
    std::vector gray_fourier;
    std::vector gray_fourier_re;
    // 中心化
    std::vector > gray_fourier_center;
    std::vector gray_fourier_center_re;
    // 傅里叶逆变换
    std::vector gray_ifourier;
    // 中心化的傅里叶变换,直接逆变换:
    std::vector gray_ifourier_center;
    // 频域滤波后的图像
    std::vector  gray_image_process;
    // 滤波器在频域的表示:
    cv::Mat ideal_low_pass_filter;
    cv::Mat ideal_high_pass_filter;
    cv::Mat butter_low_pass_filter;
    cv::Mat butter_high_pass_filter;
};

int main(){
    std::vector path;
    path.push_back("/home/lyd/image_process/pic/lena.jpg");
    Experiment5 a(path);
    for(int i = 0; i < 4; i++)
        a.test_filter(i);
    return 1;
}

三、实验结果

1、 灰度图像的 DFT 和 IDFT
数字图像处理基础实验(五):频域滤波_第1张图片
2、 利用理想高通和低通滤波器对灰度图像进行频域滤波
数字图像处理基础实验(五):频域滤波_第2张图片
数字图像处理基础实验(五):频域滤波_第3张图片

3、 利用布特沃斯高通和低通滤波器对灰度图像进行频域滤波
数字图像处理基础实验(五):频域滤波_第4张图片

你可能感兴趣的:(图像处理)