(九)OpenCV其它功能_02_离散傅立叶变换

  1. 离散傅立叶变换:
    对一张图像使用傅立叶变换就是将它分解成正弦和余弦两部分(任一函数都可以表示成无数个正弦和余弦函数的和的形式);
    就是将图像从空间域(spatial domain)转换到频域(frequency domain)
  2. 经过象限变化,如果中心(聚)亮,说明高频多,图像包含的细节/边/角信息较多;
    而如果四角亮,说明低频多,图像模糊
#include "opencv2/opencv.hpp"
#include <iostream>

using namespace cv;
using namespace std;

int main(int argc, char ** argv)
{
	Mat src;
	src = imread("../path.jpg", IMREAD_GRAYSCALE);
	if (src.empty())
	{
		cout << "could not load image..." << endl;
		return -1;
	}

	//--------1.将图像延扩到最佳尺寸//当图像的尺寸是2,3,5的整数倍时,计算速度最快
	//为了达到快速计算的目的,经常通过添凑新的边缘像素的方法获取最佳图像尺寸
	Mat temp; //将输入图像延扩到最佳的尺寸
	int row = getOptimalDFTSize(src.rows); //getOptimalDFTSize返回最佳尺寸
	int col = getOptimalDFTSize(src.cols); //在边缘添加0
	copyMakeBorder(src, temp, 0, row - src.rows, 0, col - src.cols, BORDER_CONSTANT, Scalar::all(0));//填充边缘像素//添加的像素初始化为0

	//--------2.为傅里叶变换的结果(实部和虚部)分配存储空间
	//傅立叶变换的结果是复数,这就是说对于每个原图像值,结果是两个图像值
	//频域值范围远远超过空间值范围,因此至少要将频域储存在 float 格式中
	Mat planes[] = { Mat_<float>(temp), Mat::zeros(temp.size(), CV_32F) };
	Mat complexI;
	merge(planes, 2, complexI);//将多个单通道矩阵合并成一个多通道矩阵//为延扩后的图像增添一个初始化为0的通道

	//--------3.进行离散傅立叶变换
	dft(complexI, complexI);//变换结果保存在原始矩阵中

	//--------4.将复数转换为幅度
	// compute the magnitude and switch to logarithmic scale
	// => log(1 + sqrt(Re(DFT(I))^2 + Im(DFT(I))^2))
	split(complexI, planes); //实部planes[0] = Re(DFT(I),虚部planes[1] = Im(DFT(I))
	/*
	magnitude()计算二维矢量的幅值
	第一个参数:InputArray类型的x,表示矢量的浮点型x坐标值,也就是实部
	第二个参数:InputArray类型的y,表示矢量的浮点型y坐标值,也就是虚部
	第三个参数:OutputArray类型的magnitude,输出的幅值,它和第一个参数x有着同样的尺寸和类型
	*/
	magnitude(planes[0], planes[1], planes[0]);//planes[0] = magnitude  
	Mat dst = planes[0];

	//--------5.对数尺度(logarithmic scale)缩放
	//傅立叶变换的幅度值范围大到不适合在屏幕上显示
	//高值在屏幕上显示为白点,而低值为黑点,高低值的变化无法有效分辨
	//为了在屏幕上凸显出高低变化的连续性,可以用对数尺度来替换线性尺度
	dst += Scalar::all(1);//转换到对数尺度
	log(dst, dst);

	//--------6.剪切和重分布幅度图象限
	dst = dst(Rect(0, 0, dst.cols & -2, dst.rows & -2));

	//第五步得到的幅度图从中间划开得到四张1/4子图像,将每张子图像看成幅度图的一个象限,
	//重新分布即将四个角点重叠到图片中心)
	//这样的话原点(0,0)就位移到图像中心
	//重新排列傅里叶图像的象限,使原点位于图像中心        
	int cx = dst.cols / 2;
	int cy = dst.rows / 2;

	Mat q0(dst, Rect(0, 0, cx, cy));   // Top-Left - 为每一个象限创建ROI 
	Mat q1(dst, Rect(cx, 0, cx, cy));  // Top-Right
	Mat q2(dst, Rect(0, cy, cx, cy));  // Bottom-Left
	Mat q3(dst, Rect(cx, cy, cx, cy)); // Bottom-Right

	Mat tmp;                           // 交换象限 (Top-Left with Bottom-Right)
	q0.copyTo(tmp);
	q3.copyTo(q0);
	tmp.copyTo(q3);

	q1.copyTo(tmp);                    // 交换象限 (Top-Right with Bottom-Left)
	q2.copyTo(q1);
	tmp.copyTo(q2);

	//--------7.归一化
	normalize(dst, dst, 0, 1, NORM_MINMAX); // 将float类型的矩阵转换到可显示图像范围 
											// (float [0, 1])

	imshow("src", src); 
	imshow("dst", dst);
	waitKey();

	return 0;
}

输出结果:
(九)OpenCV其它功能_02_离散傅立叶变换

上一篇:Asteroids


下一篇:洛谷 P3801 红色的幻想乡