美文网首页
FFT的计算—(使用FFTW库)

FFT的计算—(使用FFTW库)

作者: 侠之大者_7d3f | 来源:发表于2019-07-06 11:32 被阅读0次

    前言

    为了验证DSP(Digital Singal Processor 数字信号处理器)上的目标跟踪算法(KCF, Kernalized Correlation Filter 核化相关滤波),但是DSP端调试相对麻烦,尤其是输入输出不像PC方便, 因此打算将DSP端的算法在PC上测试一下(都是C语言的,移植也不难)。在DSP上算法使用了TI提供的dsplib, imagelib, mathlib库, 这些库中的部分函数PC上没有直接对应的, 比如dsplib中的FFT、IFFT计算等。

    研一期间选过一门课,当时使用了Intel MKL计算FFT, MKL功能强大,专门为Intel处理器进行了优化,包含大量的数学计算函数,体积也相对大,下载还需要注册账户之类,比较麻烦。简单快速起见, 本人决定使用FFTW库进行FFT/IFFT计算


    开发,测试环境

    • windows 10 64bit
    • pycharm, python 3.6
    • FFTW 64bit

    FFTW安装配置

    FFTW官网真心不错,提供源码,编译好的dll,方便多了,最重要的是还有在线文档。

    • 下载FFTW


      image.png

    选择对应的平台,这里选择windwos, 64bit, precomplied

    image.png

    注意FFTW提供了windows预编译好的DLL, 如果要用VS调用FFTW, 还需要生成.lib
    上面已经有详细的步骤生成lib, lib.exe是Visual Studio安装目录下自带的工具。

    整理一下库:


    image.png
    • include目录


      image.png
    • lib 目录


      image.png
    • bin目录


      image.png

    将bin目录加入到系统环境变量,程序运行时候才可以加载到DLL。


    测试代码

    
    #include<iostream>
    #include <fftw3.h>
    
    using namespace std;
    
    int main()
    {
        int N = 32;
        fftw_complex *in, *out;
        fftw_plan p;
        
        in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * N);
        out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * N);
    
        for (int i = 0; i < N; i++)
        {
            in[i][0] = i;
            in[i][1] = 0;
        }
    
        p = fftw_plan_dft_1d(N, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
        
        fftw_execute(p); /* repeat as needed */
    
        for (int i = 0; i < N; i++)
        {
            cout << out[i][0] << " " << out[i][1] << endl;
        }
        
        fftw_destroy_plan(p);
        fftw_free(in); 
        fftw_free(out);
    
    
    
    

    为了验证结果的正确性,笔者使用python scipy进行同样的fft

    python测试代码

    import scipy.fftpack as fftpack
    import numpy as np
    
    
    x = np.arange(0, 32)
    y = fftpack.fft(x, 32)
    
    y_real = np.real(y)
    y_imag = np.imag(y)
    
    print(y_real)
    print(y_imag)
    
    

    结果

    C++ 调用FFTW的计算结果:


    image.png

    python scipy的计算结果:


    image.png

    FFT封装

    直接调用FFTW库的函数不方便,因此对函数进行封装,使得API接口简单,这样在C++中也可以像Python一样直接fft()

    一维FFT

    
    /*
     计算1维FFT
     http://www.fftw.org/fftw3_doc/Complex-One_002dDimensional-DFTs.html#Complex-One_002dDimensional-DFTs
    */
    void fft1d(const vector<complex<float>>& input, vector<complex<float>>& output, int n) {
        fftw_complex *in, *out;
        fftw_plan p;
    
        in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * input.size());
        out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * n);
    
        for (int i = 0; i < input.size(); i++)
        {
            in[i][0] = input.at(i).real();
            in[i][1] = input.at(i).imag();
        }
    
        p = fftw_plan_dft_1d(n, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
    
        fftw_execute(p); /* repeat as needed */
    
        for (int i = 0; i < n; i++)
        {
            output.push_back(complex<float>(out[i][0], out[i][1]));
        }
    
        fftw_destroy_plan(p);
        fftw_free(in);
        fftw_free(out);
    }
    
    

    二维FFT

    /*
    2维 FFT
    @param input [in] 输入数据,复数类型, rows*cols
    @param output [out] fft2d计算结果, same size as input
    @param rows [in] 矩阵行数
    @param cols [in] 矩阵列数
    
    http://www.fftw.org/fftw3_doc/Complex-Multi_002dDimensional-DFTs.html#Complex-Multi_002dDimensional-DFTs
    */
    void fft2d(const vector<complex<float>>& input, vector<complex<float>>& output, int rows, int cols) {
    
        fftw_complex *in, *out;
        fftw_plan p;
    
        in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * input.size());
        out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * rows*cols);
    
        for (int i = 0; i < input.size(); i++)
        {
            in[i][0] = input.at(i).real();
            in[i][1] = input.at(i).imag();
        }
    
        p = fftw_plan_dft_2d(rows, cols, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
        fftw_execute(p); /* repeat as needed */
    
        int size = rows * cols;
        for (int i = 0; i < size; i++)
        {
            output.push_back({ static_cast<float>(out[i][0]), static_cast<float>(out[i][1]) });
        }
    
        fftw_destroy_plan(p);
        fftw_free(in);
        fftw_free(out);
    
    }
    

    图像的二维FFT变换

    利用上面封装好的C++ API函数 fft2d(), 图像的读取采用opencv, 为了验证结果,将fft的结果保存到文本,最后使用python加载,可视化。

    C++测试函数

    void test_fft2d() {
    
        int M = 512;
        int N = 512;
    
        vector<complex<float>> input, output;
    
        //使用opencv读取一张512x512图像
        Mat image = imread("./lena_gray.jpg", ImreadModes::IMREAD_GRAYSCALE);
    
        for (int i = 0; i < image.rows; i++)
        {
            for (int j = 0; j < image.cols; j++)
            {
                input.push_back({ static_cast<float>(image.at<unsigned char>(i,j)), 0 });
            }
        }
        
        // 调用FFT2d
        fft2d(input, output, 512, 512);
    
        //将FFT的结果保存到文本
        ofstream fileOut("./fft2d.dat", ios::out);
        for (auto& i:output)
        {
            fileOut << i.real() << " " << i.imag() << endl;
        }
    
        fileOut.close();
    
        cout << "FFT2d test finish!" << endl;
    
    }
    
    • C++ fft2d可视化 (python代码)
    from scipy.fftpack import fft, fftshift
    import numpy as np
    import matplotlib.pyplot as plt
    import cv2
    
    
    image = cv2.imread('./lena_gray.jpg',cv2.IMREAD_GRAYSCALE)
    
    fft_data = np.loadtxt('./fft2d.dat')
    print(fft_data.shape)
    
    fft_result = np.empty(shape=[fft_data.shape[0]], dtype=np.complex)
    for i in range(fft_data.shape[0]):
        data_real, data_imag = fft_data[i]
        fft_result[i] = np.complex(data_real, data_imag)
    
    fft_result = fft_result.reshape([512, 512])
    
    #
    plt.figure()
    plt.subplot(2, 3, 1)
    plt.imshow(image, cmap=plt.gray())
    plt.title('image')
    
    plt.subplot(2, 3, 2)
    plt.imshow(np.abs(fft_result), cmap=plt.gray())
    plt.title('fft')
    
    plt.subplot(2, 3, 3)
    plt.imshow(np.abs(fftshift(fft_result)), cmap=plt.gray())
    plt.title('fft-shift')
    
    plt.subplot(2, 3, 4)
    plt.imshow(np.log(1 + np.abs(fft_result)), cmap=plt.gray())
    plt.title('fft-log')
    
    plt.subplot(2, 3, 5)
    plt.imshow(np.log(1 + np.abs(fftshift(fft_result))), cmap=plt.gray())
    plt.title('fft-shiift-log')
    
    plt.show()
    
    
    image.png

    为了对比,再次采用scipy中的fft2d直接对图像进行fft

    
    from scipy.fftpack import fft, fftshift, fft2
    import numpy as np
    import cv2
    import matplotlib.pyplot as plt
    
    
    image = cv2.imread('./lena_gray.jpg', cv2.IMREAD_GRAYSCALE)
    
    img_fft = fft2(image, shape=[512, 512])
    print(img_fft.shape)
    
    img_fftshift = fftshift(img_fft)
    
    plt.figure()
    plt.subplot(2, 3, 1)
    plt.imshow(image, cmap=plt.gray())
    plt.title('image')
    plt.subplot(2, 3, 2)
    plt.imshow(np.abs(img_fft), cmap=plt.gray())
    plt.title('fft')
    plt.subplot(2, 3, 3)
    plt.imshow(np.abs(img_fftshift), cmap=plt.gray())
    plt.subplot(2, 3, 4)
    plt.imshow(np.log(1 + np.abs(img_fft)), cmap=plt.gray())
    plt.title('fft-log')
    plt.subplot(2, 3, 5)
    plt.imshow(np.log(1 + np.abs(img_fftshift)), cmap=plt.gray())
    plt.title('fftshift-log')
    plt.show()
    
    
    image.png

    对比发现,C++ FFTW 与python scipy的FFT2d结果完全一致。


    完整工程

    • C++
    #include<iostream>
    #include <fftw3.h>
    #include<vector>
    #include<complex>
    #include<fstream>
    #include<opencv2/opencv.hpp>
    
    using namespace std;
    using namespace cv;
    
    void fft1d(const vector<complex<float>>& input, vector<complex<float>>& output, int n);
    void fft2d(const vector<complex<float>>& input, vector<complex<float>>& output, int rows, int cols);
    void test_fft2d();
    void test_fft1d();
    
    int main()
    {
    
        test_fft2d();
    
        system("pause");
    }
    
    
    void test_fft1d() {
    
        int N = 32;
    
        //fft1d测试
        vector<complex<float>> input, output;
        for (int i = 0; i < N; i++)
        {
            input.push_back({ static_cast<float>(i), 0 });
        }
    
        //fft1d
        fft1d(input, output, N);
    
        for (auto& i : output)
        {
            cout << i.real() << " " << i.imag() << endl;
        }
    }
    
    
    void test_fft2d() {
    
        int M = 512;
        int N = 512;
    
        vector<complex<float>> input, output;
    
        //使用opencv读取一张512x512图像
        Mat image = imread("./lena_gray.jpg", ImreadModes::IMREAD_GRAYSCALE);
    
        for (int i = 0; i < image.rows; i++)
        {
            for (int j = 0; j < image.cols; j++)
            {
                input.push_back({ static_cast<float>(image.at<unsigned char>(i,j)), 0 });
            }
        }
        
        // 调用FFT2d
        fft2d(input, output, 512, 512);
    
        //将FFT的结果保存到文本
        ofstream fileOut("./fft2d.dat", ios::out);
        for (auto& i:output)
        {
            fileOut << i.real() << " " << i.imag() << endl;
        }
    
        fileOut.close();
    
        cout << "FFT2d test finish!" << endl;
    
    }
    
    /*
     计算1维FFT
     http://www.fftw.org/fftw3_doc/Complex-One_002dDimensional-DFTs.html#Complex-One_002dDimensional-DFTs
    */
    void fft1d(const vector<complex<float>>& input, vector<complex<float>>& output, int n) {
        fftw_complex *in, *out;
        fftw_plan p;
    
        in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * input.size());
        out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * n);
    
        for (int i = 0; i < input.size(); i++)
        {
            in[i][0] = input.at(i).real();
            in[i][1] = input.at(i).imag();
        }
    
        p = fftw_plan_dft_1d(n, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
    
        fftw_execute(p); /* repeat as needed */
    
        for (int i = 0; i < n; i++)
        {
            output.push_back(complex<float>(out[i][0], out[i][1]));
        }
    
        fftw_destroy_plan(p);
        fftw_free(in);
        fftw_free(out);
    }
    
    /*
    2维 FFT
    @param input [in] 输入数据,复数类型, rows*cols
    @param output [out] fft2d计算结果, same size as input
    @param rows [in] 矩阵行数
    @param cols [in] 矩阵列数
    
    http://www.fftw.org/fftw3_doc/Complex-Multi_002dDimensional-DFTs.html#Complex-Multi_002dDimensional-DFTs
    */
    void fft2d(const vector<complex<float>>& input, vector<complex<float>>& output, int rows, int cols) {
    
        fftw_complex *in, *out;
        fftw_plan p;
    
        in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * input.size());
        out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * rows*cols);
    
        for (int i = 0; i < input.size(); i++)
        {
            in[i][0] = input.at(i).real();
            in[i][1] = input.at(i).imag();
        }
    
        p = fftw_plan_dft_2d(rows, cols, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
        fftw_execute(p); /* repeat as needed */
    
        int size = rows * cols;
        for (int i = 0; i < size; i++)
        {
            output.push_back({ static_cast<float>(out[i][0]), static_cast<float>(out[i][1]) });
        }
    
        fftw_destroy_plan(p);
        fftw_free(in);
        fftw_free(out);
    
    }
    
    • python
    from scipy.fftpack import fft, fftshift, fft2
    import numpy as np
    import cv2
    import matplotlib.pyplot as plt
    
    
    image = cv2.imread('./lena_gray.jpg', cv2.IMREAD_GRAYSCALE)
    
    img_fft = fft2(image, shape=[512, 512])
    print(img_fft.shape)
    
    img_fftshift = fftshift(img_fft)
    
    plt.figure()
    plt.subplot(2, 3, 1)
    plt.imshow(image, cmap=plt.gray())
    plt.title('image')
    plt.subplot(2, 3, 2)
    plt.imshow(np.abs(img_fft), cmap=plt.gray())
    plt.title('fft')
    plt.subplot(2, 3, 3)
    plt.imshow(np.abs(img_fftshift), cmap=plt.gray())
    plt.subplot(2, 3, 4)
    plt.imshow(np.log(1 + np.abs(img_fft)), cmap=plt.gray())
    plt.title('fft-log')
    plt.subplot(2, 3, 5)
    plt.imshow(np.log(1 + np.abs(img_fftshift)), cmap=plt.gray())
    plt.title('fftshift-log')
    plt.show()
    
    
    
    from scipy.fftpack import fft, fftshift
    import numpy as np
    import matplotlib.pyplot as plt
    import cv2
    
    
    image = cv2.imread('./lena_gray.jpg',cv2.IMREAD_GRAYSCALE)
    
    fft_data = np.loadtxt('./fft2d.dat')
    print(fft_data.shape)
    
    fft_result = np.empty(shape=[fft_data.shape[0]], dtype=np.complex)
    for i in range(fft_data.shape[0]):
        data_real, data_imag = fft_data[i]
        fft_result[i] = np.complex(data_real, data_imag)
    
    fft_result = fft_result.reshape([512, 512])
    
    #
    plt.figure()
    plt.subplot(2, 3, 1)
    plt.imshow(image, cmap=plt.gray())
    plt.title('image')
    
    plt.subplot(2, 3, 2)
    plt.imshow(np.abs(fft_result), cmap=plt.gray())
    plt.title('fft')
    
    plt.subplot(2, 3, 3)
    plt.imshow(np.abs(fftshift(fft_result)), cmap=plt.gray())
    plt.title('fft-shift')
    
    plt.subplot(2, 3, 4)
    plt.imshow(np.log(1 + np.abs(fft_result)), cmap=plt.gray())
    plt.title('fft-log')
    
    plt.subplot(2, 3, 5)
    plt.imshow(np.log(1 + np.abs(fftshift(fft_result))), cmap=plt.gray())
    plt.title('fft-shiift-log')
    
    plt.show()
    
    
    

    参考

    https://www.cnblogs.com/youmuchen/p/8361713.html

    相关文章

      网友评论

          本文标题:FFT的计算—(使用FFTW库)

          本文链接:https://www.haomeiwen.com/subject/zrpjsqtx.html