(Opencv C++)数字图像处理-频域增强

    这里我们将从两个方面进行频域增强的学习

一、任选两幅图像(包括一副自备图像),计算其频谱图,并显示

 

 

二、采用频域滤波的方法进行图像降采样和升采样

一、首先计算其频谱图,用到的库函数如下:

CV_EXPORTS_W void dft(InputArray src, OutputArray dst, int flags = 0, int nonzeroRows = 0);

在进行dft之前我们需要提取图片的行和列的像素值,然后创建一个二维的数组来储存傅里叶变换的实部和虚部。

进行完dft之后,我们需要重新排列傅里叶图像的象限,使原点位于中心。

代码实现如下:

Mat Fourier_transform(Mat& imag)
{
	int r = getOptimalDFTSize(imag.rows);
	int c = getOptimalDFTSize(imag.cols);
	Mat padded;
	copyMakeBorder(imag, padded, 0, r - imag.rows, 0, c - imag.cols, BORDER_CONSTANT, Scalar::all(0));

	//为傅里叶变换的结果(复数,包含实部和虚部,所以需要创建一个二维的数组
	//分配存储空间,
	//需要用至少float型来存储
	//最后将二维数组合并为二通道--傅里叶变换需要
	Mat dst1[] = { Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F) };
	Mat dst2;
	merge(dst1, 2, dst2);

	//傅里叶变换,结果依旧存储在dst2中
	dft(dst2, dst2);
	//将复数换算成幅值
	split(dst2, dst1);//把二通道图像分解为二维数组,保存到dst1中,dst1[0]中存放的为实部
	magnitude(dst1[0], dst1[1], dst1[0]);//结果存放在dst1[0]中
	Mat magnitudeImage = dst1[0];


	//对数尺度缩放以便于显示
	//计算log(1 + sqrt(Re(DFT(dst2))**2 + Im(DFT(dst2))**2))
	magnitudeImage += Scalar::all(1);
	log(magnitudeImage, magnitudeImage);

	//剪切和重分布幅度图象限
	//若有奇数行或奇数列,进行频谱裁剪
	magnitudeImage = magnitudeImage(Rect(0, 0, magnitudeImage.cols & -2,    magnitudeImage.rows & -2));//任何一个数&-2的结果一定是偶数

	//重新排列傅里叶图像的象限,使原点位于图像中心
	int cx = magnitudeImage.cols / 2;
	int cy = magnitudeImage.rows / 2;
	Mat q0(magnitudeImage(Rect(0, 0, cx, cy)));
	Mat q1(magnitudeImage(Rect(cx, 0, cx, cy)));
	Mat q2(magnitudeImage(Rect(0, cy, cx, cy)));
	Mat q3(magnitudeImage(Rect(cy, cy, cx, cy)));

	Mat tmp;
	q0.copyTo(tmp);
	q3.copyTo(q0);
	tmp.copyTo(q3);
	q1.copyTo(tmp);
	q2.copyTo(q1);
	tmp.copyTo(q2);

	//将幅度值归一化到0~1之间,这是因为magnitudeImage中的数据类型是浮点型,这时用imshow()来显示函数,会将像素值乘于255,因此需要归一化到0~1之间
         normalize(magnitudeImage, magnitudeImage, 0, 1,NORM_MINMAX);


	//返回最后的频谱图像
	return magnitudeImage;
}

其效果图如下:

二、采用频域滤波的方法进行图像降采样和升采样

这里我们主要用到的库函数如下:

CV_EXPORTS_W void pyrDown( InputArray src, OutputArray dst,const Size& dstsize = Size(), int borderType = BORDER_DEFAULT ); //降采样函数
CV_EXPORTS_W void pyrUp( InputArray src, OutputArray dst,const Size& dstsize = Size(), int borderType = BORDER_DEFAULT );//升采样函数

高斯金字塔–降采样

高斯金字塔从底向上,逐层降采样取得,不能跨域越层;

对当前层删除偶数行与列就得到降采样后上一层的图片;

高斯金字塔生成步骤:

①进行高斯模糊;

②删除偶数行与列。

升采样则与之相反。

代码如下:

//降采样
Mat PyrDownTest(Mat& imag)
{
	Mat dest1, dest2;
	pyrDown(imag, dest1, Size(imag.cols/2 , imag.rows/2 ));
	pyrDown(dest1, dest2, Size(dest1.cols / 2, dest1.rows / 2));
	return dest2;
}
//升采样
Mat PyrupTest(Mat& imag)
{
	Mat dest1, dest2;
	pyrUp(imag, dest1, Size(imag.cols * 2, imag.rows * 2));
	pyrUp(dest1, dest2, Size(dest2.cols * 2, dest2.rows * 2));
	return dest2;
}

效果图如下:

主函数如下:

int main()
{
	/*
        Mat img = imread("5.jpg");
	Mat src = imread("p3-05.tif", CV_LOAD_IMAGE_GRAYSCALE);
	Mat src_1 = imread("1.jpg", CV_LOAD_IMAGE_GRAYSCALE);

	if (!img.data)
	{
		std::cout << "Image->img Load Fail!!!" << "\n";
		return 1;
	}
	if (!src.data)
	{
		std::cout << "Image->scr Load Fail!!!" << "\n";
		return 1;
	}
	if (!src_1.data)
	{
		std::cout << "Image-scr_1 Load Fail!!!" << "\n";
		return 1;
	}*/

	/**********************傅里叶变换*************************/
	//namedWindow("【载入的图片1】", CV_WINDOW_AUTOSIZE);
	//imshow("【载入的图片1】", src);

	//namedWindow("【载入的图片2】", CV_WINDOW_AUTOSIZE);
	//imshow("【载入的图片2】", src_1);
	// Mat show_img, show_img_1;
	//show_img = Fourier_transform(src);
	//show_img_1 = Fourier_transform(src_1);
	//imshow("【傅里叶变换后的图片1】", show_img);
	//imshow("【傅里叶变换后的图片2】", show_img_1);
	/*****************************************************/
	/**********************升采样,降采样*************************/
	/*namedWindow("【载入的图片】", CV_WINDOW_AUTOSIZE);
	imshow("【载入的图片】", img);
	Mat show_img;
	show_img = PyrDownTest(img);
	imshow("【降采样后的图片】", show_img);
	show_img = PyrupTest(show_img);
	imshow("【升采样后的图片】", show_img);*/
	/*****************************************************/
	waitKey(0);
	return 0;
}

按照自己的需要进行相应的处理即可。

完。

猜你喜欢

转载自blog.csdn.net/qq_40598185/article/details/85346126