OpenCV Java 实现票据、纸张的四边形边缘检测与提取、摆正 (3)

终于到最后一步了,最后一步的关键就是Perspective Transform。新建一个Mat,将其四个顶点与原图片刚刚检测出的长方形的四个顶点进行透视变换,就能得到最后的结果啦。透视变换的数学原理可以看这里,介绍的比较详细。

// 对多个点按顺时针排序 private static void sortCorners(List<Point> corners) { if (corners.size() == 0) return; Point p1 = corners.get(0); int index = 0; for (int i = 1; i < corners.size(); i++) { Point point = corners.get(i); if (p1.x > point.x) { p1 = point; index = i; } } corners.set(index, corners.get(0)); corners.set(0, p1); Point lp = corners.get(0); for (int i = 1; i < corners.size(); i++) { for (int j = i + 1; j < corners.size(); j++) { Point point1 = corners.get(i); Point point2 = corners.get(j); if ((point1.y-lp.y*1.0)/(point1.x-lp.x)>(point2.y-lp.y*1.0)/(point2.x-lp.x)) { Point temp = point1.clone(); corners.set(i, corners.get(j)); corners.set(j, temp); } } } } // 对顶点顺时针排序 sortCorners(corners); // 计算目标图像的尺寸 Point p0 = corners.get(0); Point p1 = corners.get(1); Point p2 = corners.get(2); Point p3 = corners.get(3); double space0 = getSpacePointToPoint(p0, p1); double space1 = getSpacePointToPoint(p1, p2); double space2 = getSpacePointToPoint(p2, p3); double space3 = getSpacePointToPoint(p3, p0); double imgWidth = space1 > space3 ? space1 : space3; double imgHeight = space0 > space2 ? space0 : space2; // 如果提取出的图片宽小于高,则旋转90度 if (imgWidth < imgHeight) { double temp = imgWidth; imgWidth = imgHeight; imgHeight = temp; Point tempPoint = p0.clone(); p0 = p1.clone(); p1 = p2.clone(); p2 = p3.clone(); p3 = tempPoint.clone(); } Mat quad = Mat.zeros((int)imgHeight * 2, (int)imgWidth * 2, CvType.CV_8UC3); MatOfPoint2f cornerMat = new MatOfPoint2f(p0, p1, p2, p3); MatOfPoint2f quadMat = new MatOfPoint2f(new Point(imgWidth*0.4, imgHeight*1.6), new Point(imgWidth*0.4, imgHeight*0.4), new Point(imgWidth*1.6, imgHeight*0.4), new Point(imgWidth*1.6, imgHeight*1.6)); // 提取图像 Mat transmtx = Imgproc.getPerspectiveTransform(cornerMat, quadMat); Imgproc.warpPerspective(result, quad, transmtx, quad.size()); return quad;

OpenCV Java 实现票据、纸张的四边形边缘检测与提取、摆正

以上就是我算法的全部步骤了。实现、调参下来感觉这个算法普适性并不强,读者可能需要对我的代码加以修改才能满足具体的业务需求,我的代码是在网上其他博主的实现(C++,参考链接)基础上加以修改,权当抛砖引玉,有任何意见与建议可以在评论区和我交流。
另外,网上见到有些实现没有采用多边形拟合,而是使用Hough变换来实现该功能,然而自己实现下来效果并不好,如果有人有这方面经验的话还希望不吝赐教。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwfxgg.html