OPENCV C++(九)鼠标响应+dft+idft

鼠标响应回调函数(固定格式)

cpp 复制代码
void on_mouse(int EVENT, int x, int y, int flags, void* userdata)
{

	Mat hh;
	hh = *(Mat*)userdata;
	Point p(x, y);
	switch (EVENT)
	{
	case EVENT_LBUTTONDOWN:
	{
		points.x = x;
		points.y = y;
		mousePoints.push_back(points);
		circle(hh, points, 4, cvScalar(255, 255, 255), -1);
		imshow("mouseCallback", hh);
	}
	break;
	}

}

这个鼠标响应函数 就是鼠标左键按下后,会标记一个点,画一个白色点,并将这个点存储到points当中

鼠标响应函数

cpp 复制代码
setMouseCallback("mouseCallback", on_mouse, &selectMat);

mousecallback就是窗口名称,后面是图像,中间是函数名

选取多边形roi区域函数(结合鼠标响应)

cpp 复制代码
int selectPolygon(cv::Mat srcMat, cv::Mat& dstMat)
{

	vector<vector<Point>> contours;
	cv::Mat selectMat;

	cv::Mat m = cv::Mat::zeros(srcMat.size(), CV_32F);

	m = 1;

	if (!srcMat.empty()) {
		srcMat.copyTo(selectMat);
		srcMat.copyTo(dstMat);
	}
	else {
		std::cout << "failed to read image!:" << std::endl;
		return -1;
	}

	namedWindow("mouseCallback");
	imshow("mouseCallback", selectMat);
	setMouseCallback("mouseCallback", on_mouse, &selectMat);
	waitKey(0);
	destroyAllWindows();
	//计算roi
	contours.push_back(mousePoints);
	if (contours[0].size() < 3) {
		std::cout << "failed to read image!:" << std::endl;
		return -1;
	}

	drawContours(m, contours, 0, Scalar(0), -1);

	m.copyTo(dstMat);

	return 0;
}

建立一个全白色的mat,用鼠标响应选取白色点连接构成roi,然后通过drawcontous把roi在全白色mat里面画出,选中区域为黑色,没有选中区域为白色。

也可以将其改成选中的区域为白色 没有选中为黑色 只需要将

m=0;scalar(255,255,255)即可

查看一张图片的幅度频谱(输入灰度)

预处理

cpp 复制代码
Mat padMat;
	//当图像的尺寸是2,3,5的整数倍时,离散傅里叶变换的计算速度最快。	
	//获得输入图像的最佳变换尺寸
	int m = getOptimalDFTSize(srcMat.rows);
	int n = getOptimalDFTSize(srcMat.cols);
cpp 复制代码
copyMakeBorder(srcMat, padMat, 0, m - srcMat.rows, 0, n - srcMat.cols, BORDER_CONSTANT, Scalar::all(0));
//对边界进行填充,刚才得到的m,n

//把灰度图像放在左上角,在右边和下边扩展图像,扩展部分填充为0;

cpp 复制代码
//定义一个数组,存储频域转换成float类型的对象,再存储一个和它一样大小空间的对象来存储复数部分
	Mat planes[] = { Mat_<float>(padMat), Mat::zeros(padMat.size(), CV_32F) };
cpp 复制代码
Mat complexMat;
merge(planes, 2, complexMat);
//将2个单通道的图像合成一幅多通道图像,将实部和虚部组合成一个

正片开始,进行傅里叶变换

cpp 复制代码
dft(complexMat, complexMat);
//输入输出图像
cpp 复制代码
split(complexMat, planes);
//求相位,保存在planes[0]
magnitude(planes[0], planes[1], planes[0]);
//0代表实部,1代表虚部 保存在0中 相位

为了显示方便,而作后续处理

cpp 复制代码
Mat magMat = planes[0];
magMat += Scalar::all(1);
log(magMat, magMat);
//值都很大,取个对数显示出来

把四个角(高频)移到中间来

cpp 复制代码
//确保对称
	magMat = magMat(Rect(0, 0, magMat.cols & -2, magMat.rows & -2));
	int cx = magMat.cols / 2;
	int cy = magMat.rows / 2;
	//将图像移相
	/*
	0 | 1         3 | 2
	-------  ===> -------
	2 | 3         1 | 0
	*/
	Mat q0(magMat, Rect(0, 0, cx, cy));
	Mat q1(magMat, Rect(cx, 0, cx, cy));
	Mat q2(magMat, Rect(0, cy, cx, cy));
	Mat q3(magMat, Rect(cx, cy, cx, cy));
	Mat tmp;
	q0.copyTo(tmp);
	q3.copyTo(q0);
	tmp.copyTo(q3);
	q1.copyTo(tmp);
	q2.copyTo(q1);
	tmp.copyTo(q2);

要一个中间变量temp不然会损失图像,保证对称是怕/2除不整,//修剪频谱,如果图像的行或者列是奇数的话,那其频谱是不对称的,因此要修剪

将图像归一化到0-255 也就是0-1之间可以显示出来

cpp 复制代码
normalize(magMat, magMat, 0, 1, NORM_MINMAX);
	magMat = magMat * 255;
	magMat.copyTo(dstMat);

	return 0;

这样就得到了频谱

求相位谱

cpp 复制代码
phase(planes[0], planes[1], ph);//相位谱ph

用鼠标响应处理频谱,再ifft转换回来

前面的一样直到

cpp 复制代码
mag = mag / 255;

先倒回去

鼠标响应

cpp 复制代码
cv::Mat mask;
Mat proceMag;

selectPolygon(mag,mask);

mag= mag.mul(mask);
proceMag = mag * 255;
imwrite("处理后频谱.jpg", proceMag);

倒过来干 ifft

cpp 复制代码
//前述步骤反着来一遍,目的是为了逆变换回原图
	Mat q00(mag, Rect(0, 0, cx, cy));   	
	Mat q10(mag, Rect(cx, 0, cx, cy));  
	Mat q20(mag, Rect(0, cy, cx, cy));  
	Mat q30(mag, Rect(cx, cy, cx, cy)); 
	
	//交换象限
	q00.copyTo(tmp);
	q30.copyTo(q00);
	tmp.copyTo(q30);
	q10.copyTo(tmp);
	q20.copyTo(q10);
	tmp.copyTo(q20);

	mag = mag * maxVal;//将归一化的矩阵还原 
	exp(mag, mag);//对应于前述去对数
	mag = mag - Scalar::all(1);//对应前述+1
	polarToCart(mag, ph, planes[0], planes[1]);//由幅度谱mag和相位谱ph恢复实部planes[0]和虚部planes[1]
	merge(planes, 2, complexImg);//将实部虚部合并

正片开始 idtf

cpp 复制代码
Mat ifft(Size(src.cols, src.rows), CV_8UC1);
	//傅里叶逆变换
	idft(complexImg, ifft, DFT_REAL_OUTPUT);
	normalize(ifft, ifft, 0, 1, CV_MINMAX);

	Rect rect(0, 0, src.cols, src.rows);
	dst = ifft(rect);
	dst = dst * 255;

	cv::Mat dspMat;
	dst.convertTo(dspMat, CV_8UC1);
	imshow("dst", dspMat);
	imshow("src", src);
	waitKey(0);

	return 0;

注意这里有个转换 idft类型要转换成8UC1才能展示

这里有个疑问 mag不×255才能显示出图像 ×了反而显示出全白

但是imwirte出的图像又是正常的 为什么?

相关推荐
千天夜2 分钟前
激活函数解析:神经网络背后的“驱动力”
人工智能·深度学习·神经网络
大数据面试宝典4 分钟前
用AI来写SQL:让ChatGPT成为你的数据库助手
数据库·人工智能·chatgpt
封步宇AIGC9 分钟前
量化交易系统开发-实时行情自动化交易-3.4.1.2.A股交易数据
人工智能·python·机器学习·数据挖掘
m0_5236742110 分钟前
技术前沿:从强化学习到Prompt Engineering,业务流程管理的创新之路
人工智能·深度学习·目标检测·机器学习·语言模型·自然语言处理·数据挖掘
Prejudices13 分钟前
C++如何调用Python脚本
开发语言·c++·python
单音GG16 分钟前
推荐一个基于协程的C++(lua)游戏服务器
服务器·c++·游戏·lua
HappyAcmen20 分钟前
IDEA部署AI代写插件
java·人工智能·intellij-idea
qing_04060332 分钟前
C++——多态
开发语言·c++·多态
孙同学_32 分钟前
【C++】—掌握STL vector 类:“Vector简介:动态数组的高效应用”
开发语言·c++
噜噜噜噜鲁先森41 分钟前
看懂本文,入门神经网络Neural Network
人工智能