前言
为了验证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()
网友评论