OpenCV-计算二维矢量幅值cv::magnitude

Posted 翟大宝Steven

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenCV-计算二维矢量幅值cv::magnitude相关的知识,希望对你有一定的参考价值。

函数原型

void magnitude(InputArray x, InputArray y, OutputArray magnitude);

参数说明

  1. InputArray类型的x,表示矢量的浮点型X坐标值,也表示复数中的实部。
  2. InputArray类型的y,表示矢量的浮点型Y坐标值,也表示复数中的虚部。
  3. OutputArray类型的magnitude,输出的幅值,同第一个参数x有着同样的尺寸和类型。

      计算公式为:

      magnitude=\\sqrt{x^2+y^2}

测试代码

#include<iostream>
#include<opencv2/opencv.hpp>
#include<ctime>
using namespace std;
using namespace cv;

void fftshift(cv::Mat &plane0, cv::Mat &plane1);

int main(void)
{
	Mat test = imread("test.jpg", 0);
	test.convertTo(test, CV_32FC1);

	//创建通道,存储dft后的实部与虚部(CV_32F,必须为单通道数)
	cv::Mat plane[] = { test.clone(), cv::Mat::zeros(test.size() , CV_32FC1) };
	cv::Mat complexIm;
	cv::merge(plane, 2, complexIm); // 合并通道 (把两个矩阵合并为一个2通道的Mat类容器)
	cv::dft(complexIm, complexIm, 0); // 进行傅立叶变换,结果保存在自身
	
    // 分离通道(数组分离)
	cv::split(complexIm, plane);
	// 以下的操作是频域迁移
	fftshift(plane[0], plane[1]);
	// 计算幅值
	cv::Mat mag,mag_log,mag_nor;
	cv::magnitude(plane[0], plane[1], mag);
	// 幅值对数化:log(1+m),便于观察频谱信息
	mag += Scalar::all(1);
	cv::log(mag, mag_log);
	cv::normalize(mag_log, mag_nor, 1,0, NORM_MINMAX);

	cv::Mat BLUR;
	// 再次搬移回来进行逆变换
	fftshift(plane[0], plane[1]);
	cv::merge(plane, 2, BLUR); // 实部与虚部合并
	cv::idft(BLUR, BLUR);       // idft结果也为复数
	BLUR = BLUR / BLUR.rows / BLUR.cols;
	cv::split(BLUR, plane);//分离通道,主要获取通道

	imshow("original", test / 255);
	imshow("result", plane[0] / 255);
	waitKey(0);
	system("pause");
	return 0;
}

// fft变换后进行频谱搬移
void fftshift(cv::Mat &plane0, cv::Mat &plane1)
{
	// 以下的操作是移动图像  (零频移到中心)
	int cx = plane0.cols / 2;
	int cy = plane0.rows / 2;
	cv::Mat part1_r(plane0, cv::Rect(0, 0, cx, cy));  // 元素坐标表示为(cx, cy)
	cv::Mat part2_r(plane0, cv::Rect(cx, 0, cx, cy));
	cv::Mat part3_r(plane0, cv::Rect(0, cy, cx, cy));
	cv::Mat part4_r(plane0, cv::Rect(cx, cy, cx, cy));

	cv::Mat temp;
	part1_r.copyTo(temp);  //左上与右下交换位置(实部)
	part4_r.copyTo(part1_r);
	temp.copyTo(part4_r);

	part2_r.copyTo(temp);  //右上与左下交换位置(实部)
	part3_r.copyTo(part2_r);
	temp.copyTo(part3_r);

	cv::Mat part1_i(plane1, cv::Rect(0, 0, cx, cy));  //元素坐标(cx,cy)
	cv::Mat part2_i(plane1, cv::Rect(cx, 0, cx, cy));
	cv::Mat part3_i(plane1, cv::Rect(0, cy, cx, cy));
	cv::Mat part4_i(plane1, cv::Rect(cx, cy, cx, cy));

	part1_i.copyTo(temp);  //左上与右下交换位置(虚部)
	part4_i.copyTo(part1_i);
	temp.copyTo(part4_i);

	part2_i.copyTo(temp);  //右上与左下交换位置(虚部)
	part3_i.copyTo(part2_i);
	temp.copyTo(part3_i);
}

测试效果

图1 某点实部
图2 某点虚部
图3 该点幅值

       从图像中对应的数值来看,同计算公式一致,当需要对两个数组进行平方和开根号操作时,也可以直接调用该函数~

       如果文章帮助到你了,可以点个赞让我知道,我会很快乐~加油!

以上是关于OpenCV-计算二维矢量幅值cv::magnitude的主要内容,如果未能解决你的问题,请参考以下文章

opencv::meanStdDev 带有矢量<vector<double>>

OpenCV图像处理篇之边缘检測算子

matlab画矢量图?

将opencv Mat创建为二维网格

Opencv图像读取,显示,保存,类型转换

使用Python,Opencv进行二维直方图的计算及绘制