鼠标响应回调函数(固定格式)
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出的图像又是正常的 为什么?