当前位置: 首页 > news >正文

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

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

 

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当中

鼠标响应函数

setMouseCallback("mouseCallback", on_mouse, &selectMat);

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

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

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();//计算roicontours.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)即可

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

预处理

Mat padMat;//当图像的尺寸是2,3,5的整数倍时,离散傅里叶变换的计算速度最快。	//获得输入图像的最佳变换尺寸int m = getOptimalDFTSize(srcMat.rows);int n = getOptimalDFTSize(srcMat.cols);

 

copyMakeBorder(srcMat, padMat, 0, m - srcMat.rows, 0, n - srcMat.cols, BORDER_CONSTANT, Scalar::all(0));
//对边界进行填充,刚才得到的m,n

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

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

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

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

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

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

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

//确保对称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之间可以显示出来

normalize(magMat, magMat, 0, 1, NORM_MINMAX);magMat = magMat * 255;magMat.copyTo(dstMat);return 0;

这样就得到了频谱

求相位谱

phase(planes[0], planes[1], ph);//相位谱ph

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

前面的一样直到

mag = mag / 255;

 先倒回去

鼠标响应

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

倒过来干 ifft

//前述步骤反着来一遍,目的是为了逆变换回原图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);//对应前述+1polarToCart(mag, ph, planes[0], planes[1]);//由幅度谱mag和相位谱ph恢复实部planes[0]和虚部planes[1]merge(planes, 2, complexImg);//将实部虚部合并

正片开始 idtf

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出的图像又是正常的 为什么?

http://www.lryc.cn/news/116579.html

相关文章:

  • python编程求出介于这两个数 之间的所有质数并打印输出。显示格式为“*数是质数
  • 基于Selenium模块实现无界面模式 执行JS脚本
  • 【LangChain学习】基于PDF文档构建问答知识库(二)创建项目
  • 【Kubernetes】Kubernetes之kubectl详解
  • 【torch.nn.PixelShuffle】和 【torch.nn.UnpixelShuffle】
  • Rocky9 KVM网桥的配置
  • 爬虫013_函数的定义_调用_参数_返回值_局部变量_全局变量---python工作笔记032
  • 将.doc文档的默认打开方式从WPS修改为word office打开方式的具体方法(以win 10 操作系统为例)
  • 如何搭建个人的GPT网页服务
  • [QCM6125][Android13] 默认关闭SELinux权限
  • 【jvm】jvm发展历程
  • Dubbo3.0 Demo
  • 源码分析——ConcurrentHashMap源码+底层数据结构分析
  • R语言中的函数25:paste,paste0
  • (八)穿越多媒体奇境:探索Streamlit的图像、音频与视频魔法
  • CAD练习——绘制房子平面图
  • spring 面试题
  • Springboot项目集成Durid数据源和P6Spy以及dbType not support问题
  • 安卓如何卸载应用
  • 【云原生|Kubernetes】14-DaemonSet资源控制器详解
  • 基于 Guava Retry 在Spring封装一个重试功能
  • 适用HarmonyOS 3.1版本及以上的应用及服务开发工具 DevEco Studio 3.1.1 Release 安装
  • [信号与系统系列] 正弦振幅调制之差拍信号
  • vb+SQL航空公司管理系统设计与实现
  • python爬取网页视频
  • 数据挖掘具体步骤
  • react class与hooks区别
  • Python爬虫思维:异常处理与日志记录
  • (十六)大数据实战——安装使用mysql版的hive服务
  • 【信号生成器】从 Excel 数据文件创建 Simulink 信号生成器块研究(Simulink)