如何用OpenCV Android版排除被遮挡的多边形?
排除被遮挡多边形的实用方案
结合你当前的OpenCV Android处理流程,这里提供几个针对性的过滤方法,帮你剔除被遮挡的无效多边形:
1. 轮廓面积与凸包面积比例筛选
被遮挡的多边形,实际轮廓面积会远小于其凸包面积。通过计算两者的比例,设定阈值(比如0.8~0.9,可根据场景调整)过滤异常轮廓:
// 计算当前轮廓面积 double contourArea = Imgproc.contourArea(contour); // 生成凸包 MatOfInt hull = new MatOfInt(); Imgproc.convexHull(contour, hull); // 转换凸包为点集合 List<Point> hullPoints = new ArrayList<>(); for (int idx : hull.toList()) { hullPoints.add(contour.toList().get(idx)); } double hullArea = Imgproc.contourArea(new MatOfPoint(hullPoints)); // 比例判定 double areaRatio = contourArea / hullArea; if (areaRatio < 0.8) { // 判定为被遮挡,跳过该轮廓 continue; }
2. 利用轮廓层级检测内部孔洞
被遮挡的多边形往往会在轮廓内部形成孔洞,可通过findContours的层级参数判断是否存在子轮廓(孔洞):
// 查找轮廓时同时获取层级信息 List<MatOfPoint> contours = new ArrayList<>(); Mat hierarchy = new Mat(); Imgproc.findContours(binaryImg, contours, hierarchy, Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE); // 遍历轮廓时检查子轮廓 for (int i = 0; i < contours.size(); i++) { // hierarchy第2列代表当前轮廓的子轮廓索引,不为-1表示存在孔洞 int childIdx = (int) hierarchy.get(0, i)[2]; if (childIdx != -1) { continue; } }
3. 多边形逼近后的周长匹配验证
完整多边形经approxPolyDP逼近后,顶点数应严格匹配目标类型,且逼近轮廓的周长应与原轮廓周长接近:
MatOfPoint2f contour2f = new MatOfPoint2f(contour.toArray()); MatOfPoint2f approx = new MatOfPoint2f(); // 执行多边形逼近 double epsilon = 0.04 * Imgproc.arcLength(contour2f, true); Imgproc.approxPolyDP(contour2f, approx, epsilon, true); // 检查顶点数+周长比例 double approxPerimeter = Imgproc.arcLength(approx, true); double originalPerimeter = Imgproc.arcLength(contour2f, true); double perimeterRatio = approxPerimeter / originalPerimeter; // 以四边形为例:顶点数需为4,周长比例需接近1(比如>0.9) if (approx.toList().size() != 4 || perimeterRatio < 0.9) { continue; }
4. 凸性检查(仅适用于目标为凸多边形场景)
如果你的竞赛目标都是凸多边形,可直接用isContourConvex()判断,被遮挡的轮廓大概率会变成非凸:
if (!Imgproc.isContourConvex(contour)) { continue; }
建议先组合测试「面积比例筛选+层级孔洞检测」,这两个方法对大多数遮挡场景通用,再根据你竞赛的具体多边形类型调整参数。
内容的提问来源于stack exchange,提问作者Jinsn
相关产品推荐
相关产品推荐

