如何使用OpenCV从Canny边缘检测中获取准确的(x,y)坐标?
看起来你在从透视变换后的图像提取Canny边缘坐标时遇到了偏差问题,结合你给出的代码片段,我发现几个核心问题,咱们一步步来解决:
1. 透视变换的输出图像类型完全错了
你创建的finalMat是CV_32FC2类型(2通道浮点型),但这个类型是用来存储坐标映射数据的,不是用来存储RGB图像的!warpPerspective处理彩色图像时,输出必须和输入的通道数、数据类型匹配(比如输入是8位3通道的RGB图,输出也得是同类型)。用CV_32FC2存储图像会导致像素数据混乱,后续Canny检测自然没法得到准确的边缘,更别说坐标了。
修正方法很简单,把finalMat的类型改成和输入rgbMat一致:
finalMat = Mat.zeros((int) maxHeight, (int) maxWidth, rgbMat.type());
或者直接指定8位3通道类型:
finalMat = Mat.zeros((int) maxHeight, (int) maxWidth, CvType.CV_8UC3);
2. 搞清楚边缘检测和透视变换的顺序
你得先明确自己的需求:
- 是想先检测原图像的边缘,再把这些边缘坐标变换到透视后的空间?
- 还是先把图像做透视变换,再在矫正后的图像上检测边缘?
如果是后者(更常见的场景),正确的流程应该是这样:
// 先完成正确的透视变换 Mat finalMat = Mat.zeros((int) maxHeight, (int) maxWidth, rgbMat.type()); Imgproc.warpPerspective(rgbMat, finalMat, transformMatrix, finalMat.size()); // 把彩色图转成灰度图(Canny只接受单通道灰度图) Mat grayMat = new Mat(); Imgproc.cvtColor(finalMat, grayMat, Imgproc.COLOR_BGR2GRAY); // 执行Canny边缘检测(阈值可以根据你的实际场景调整) Mat cannyMat = new Mat(); Imgproc.Canny(grayMat, cannyMat, 50, 150); // 提取边缘坐标(这里用轮廓检测来获取所有边缘点) List<MatOfPoint> contours = new ArrayList<>(); Imgproc.findContours(cannyMat, contours, new Mat(), Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE); // 遍历每个轮廓,输出所有边缘点的(x,y) for (MatOfPoint contour : contours) { Point[] points = contour.toArray(); for (Point p : points) { Log.d("EdgeCoordinate", "x: " + p.x + ", y: " + p.y); } }
如果是前者(先检测原图像边缘再变换坐标),那你需要先对原图像做Canny,然后用Core.perspectiveTransform函数把每个边缘点的坐标通过transformMatrix转换到目标空间。
3. 检查透视变换矩阵的正确性
最后别忘了最基础的一步:确认srcMat和dstMat里的点是一一对应的!比如你选的原图像四个点(左上、右上、右下、左下)必须和目标图像的四个点顺序完全一致。如果点的顺序错了,透视变换后的图像会严重扭曲,边缘坐标肯定不准。
你可以先把透视变换后的finalMat显示出来,确认图像是否正确矫正,再进行后续的边缘检测操作。
内容的提问来源于stack exchange,提问作者Darshan
相关产品推荐
相关产品推荐

