Дискретное преобразование Фурье (ДПФ)
определение
Дискретное преобразование Фурье (дискретное преобразование Фурье, сокращенно ДПФ) — это дискретная форма преобразования Фурье как во временной, так и в частотной областях, которая преобразует выборку сигнала во временной области в его выборку ДПФ в частотной области.
Для последовательности из N точек {X[n]} (0
функция дфт()
Роль функции dft() заключается в выполнении прямого или обратного дискретного преобразования Фурье для одномерного или двумерного массива чисел с плавающей запятой.
函数原型
void dft(
InoutArray src, //输入矩阵
OutputArray dst, ///输出矩阵
int flags = 0, //转换的标识符
int onozeroRows,
)
Третий параметр, преобразованный идентификатор делится на:
- DFT_INVERSE заменяет прямое преобразование по умолчанию одномерным или двумерным обратным преобразованием.
- DFT_SCALE Идентификатор масштабирования, выходные результаты будут масштабированы на 1/N.
- DFT_CMPLEX_OUTPUT, DFT_REAL_OUTPUT Выполнение обратного преобразования одномерного или двумерного массива.
Возвращает оптимальный размер ДПФ: функция getOptimalDFTSize()
void int getOptimalDFTSize(int vecsize);
Расширьте границы изображения: функция copyMakeBorder()
void copyMakeBorder(
InputArray src, //输入图像
OutputArray dst, //输出图像
int top, //在图像上方扩充的像素值
int bottom, //在图像下方扩充的像素值
int left, //在图像左方扩充的像素值
int right, //在图像右方扩充的像素值
int borderType, //边界类型·
const Scalars,
)
Вычислить величину двумерного вектора: функция величина()
Используется для вычисления величины двумерного вектора.
void magnitude(
InputArray x, //表示矢量的浮点型X坐标值,即实部
InputArray y, //表示矢量的浮点型Y坐标值,即虚部
OutputArray magnitude, //输出的幅值
)
Вычислить натуральный логарифм: функция log()
Функция функции log() заключается в вычислении натурального логарифма абсолютного значения каждого элемента массива.
void log(
InputArray src,
OutputArray dst,
);
原理即为:
if(src(I) != 0)
log|src(I)|
else
C
Нормализация матрицы: функция normalize()
void normalize(
InputArray src,
OutputArray dst,
double alpha = 1, //归一化之后的最大值,有默认值1
double beta = 0, //归一化之后的最大值,有默认值0
int norm_type = NORM_L2, //归一化类型
int dtype = -1, //为负数时输出矩阵和src有同样的类型,否则,它和src有同样的通道数,深度为CV_MAT_DEPTH
InputArray mask=noArray(), //可选的操作掩模
)
функция getOptimalDFTSize
Эта функция возвращает оптимальный размер Фурье заданного размера вектора. Для увеличения скорости работы дискретного преобразования Фурье необходимо расширить изображение.
Пример основного фрагмента для вычисления свертки двух реальных 2D-матриц с использованием функции dft
- где роль MulSpectrums заключается в вычислении произведения каждого элемента двух спектров Фурье.
void convolveDft(InputArray A, InputArray B, OutputArray C)
{
//初始化输出矩阵
C.create(abs(A.rows - B.rows) + 1, abs(A.cols - B.cols) + 1, A.type);
//计算DFT变换的尺寸
dftSize.width = getOptimalDFTSize(A.cols + B.cols - 1);
dftSize.height = getOptimalDFTSize(A.rows + B.rows - 1);
//分配临时缓冲区并初始化置0
Mat tempA(dftSize,A.type(),Scalar::all(0));
Mat tempB(dftSize,B.type(),Scalar::all(0));
//分别复制A和B到tempA和tempB的左上角
Mat roiA(tempA,Rect(0,0,A.cols,A.rows));
A.copyTo(roiA);
Mat roiB(tempB,Rect(0,0,B.cols,B.rows));
B.copyTO(roiB);
//就地操作,进行快速傅里叶变换,并将nonzeroRows 参数置为零,以进行更加快速的处理。
dft(tempA,tempA,0,A.rows);
dft(tempB,tempB,0,B.rows);
//将得到的频谱相乘,结果存放于tempA当中
mulSpectrums(tempA,tempB,tempA);
//将结果变换为频域,尽管结果行(result.rows)都为非零,我们只需其中的C.rows的第一行,所以采用nonzeroRows == C.rows
dft(tempA,tempA,EFT_INVERSE + EFT_SCALE,C.rows);
//将结果复制到C当中
tempA(Rect(0,0,C.cols,C.rows)).copyTo(C);
//所有的临时缓存区将被自动释放,所以无需收尾操作
}
Пример программы: дискретное преобразование Фурье
[1] Загрузите исходное изображение
//【1】ui灰度模式读取原始图像并显示
Mat srcImage = imread("D:\\Desktop\\lena.jpg",0);
if (!srcImage.data)
{
cout << "lena图片读取错误" << endl;
return false;
}
imshow("原始图像", srcImage);
[2] Увеличить изображение до нужного размера
//【2】将输入的图像延扩到最佳的尺寸,边界用0补充
int m = getOptimalDFTSize(I.rows);
int n = getOptimalDFTSize(I.cols);
//将添加的像素初始化为0
Mat padded;
copyMakeBorder(I,padded,0,m - I,rows,0,n - I.cols,BORDER_CONSTANT,Scalar::all(0));
[3] Выделить место для хранения результата преобразования Фурье
Результатом преобразования Фурье является комплексное число, и для каждого исходного значения изображения результат будет иметь два значения изображения.
为傅里叶变换的结果(实部和虚部)分配储存空间
//将planes数组组合合并成一个多通道的数组complexI
Mat planes[] = (Mat_<float>(padded),Mat::zeros(padded.size(),CV_32F));
Mat complexI;
merge(planes,2,complexI);
[4] Выполнение дискретного преобразования Фурье
def(complexI,complexI);
[5] Преобразование комплексных чисел в величины
Результатом дискретного преобразования Фурье является комплексное число, и соответствующая величина может быть выражена как:
//将复数转换为幅值,即=> log(1 + sqrt(Re(DFT(I)) ^ 2 + Im(DFT(I)) ^ 2))
split(complexI,planes); //将多通道complexI分离成几个单通道数组
planes[0] = Re(DFT(I),planes[1] = Im(DFT(I))
magnitude(planes[0],planes[1],planes[0]);
Mat magnitudeImage = planes[0];
[6] Выполнить логарифмическое масштабирование
Величина преобразования Фурье слишком велика, чтобы уместиться на экране. Высокое значение отображается в виде белой точки на экране, а низкое значение — в виде черной точки, и изменение высоких и низких значений не может быть эффективно оценено. Чтобы подчеркнуть непрерывность высоких и низких изменений на экране, вместо линейной шкалы можно использовать логарифмическую шкалу по следующей формуле:
//进行对数尺度缩放
magnitudeImage += Scalar::all(1);
log(magnitudeImage,magnitudeImage); //求自然对数
[7] Отсечение и перераспределение квадрантов изображения магнитуды
Поскольку на втором шаге изображение было расширено, пришло время отсеять вновь добавленные пиксели. Позиции квадрантов изображения могут быть перераспределены для удобства отображения.
//若有奇数行或技术列,进行谱写裁剪
magnitudeImage = magnitudeImage(Rect(0,0,magnitudeImage.cols & -2,magnitudeImage.rows & -2));
//重新排列傅里叶图像中的象限,使得原点位于图像中心
int cx = magnitudeImage.cols / 2;
int cy = magnitudeImage.rows / 2;
Mat q0(magnitudeImage,Rect(0,0,cx,cy)); //ROI区域的左上
Mat q1(magnitudeImage,Rect(cx,0,cx,cy)); //ROI区域的右上
Mat q2(magnitudeImage,Rect(0,cy,cx,cy)); //ROI区域的左下
Mat q3(magnitudeImage,Rect(cx,cy,cx,cy)); //ROI区域的右下
//交换象限(左上与右下)
Mat tmp;
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
//交换象限(右上与左下)
q1.copyTo(tmp);
q4.copyTo(q1);
tmp.copyTo(q4);
[8] Нормализация
Теперь у нас есть карта перераспределенных величин, но значение величины все еще превышает отображаемый диапазон [0,1], мы можем использовать функцию normalize() для нормализации до отображаемого диапазона.
normalize(magnitudeImage,magnitudeImage,0,1,NORM_MINMAX);
【9】Эффект отображения
imshow("频谱幅值",magnitudeImage);