You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenCV Java版Hough Guil检测器参数调优与精准检测求助

Java版OpenCV GeneralizedHoughGuil检测器参数调优与精准检测问题

我正在使用Java版OpenCV调优GeneralizedHoughGuil检测器,但官方教程对多数参数缺乏详细说明,导致难以实现精准检测。以下是我的检测器实现代码:

public class TemplateHoughGuilDetector {
    public static PositionVector runHoughGuilDetection(Mat template, Mat blurred) {
        var houghDetector = Imgproc.createGeneralizedHoughGuil();
        houghDetector.setLevels(1500);
        houghDetector.setScaleThresh(200);
        houghDetector.setPosThresh(200);
        houghDetector.setAngleThresh(1000);
        houghDetector.setDp(15);
        houghDetector.setMinDist(.1);
        houghDetector.setAngleStep(.1);
        houghDetector.setAngleEpsilon(1);
        houghDetector.setMinAngle(0);
        houghDetector.setMaxAngle(360);
        houghDetector.setMinScale(.99);
        houghDetector.setMaxScale(1.01);
        houghDetector.setScaleStep(.01);
        houghDetector.setXi(90.0);


        PositionVector bestVoted = mostLikelyHoughDetectionWithScaleTolerance(template, blurred, houghDetector);
        return bestVoted;
    }

    private static PositionVector mostLikelyHoughDetectionWithScaleTolerance(Mat template, Mat blurred, GeneralizedHough houghDetector) {
        houghDetector.setTemplate(template);
        var positions = new Mat();
        var votes = new Mat();

        houghDetector.detect(blurred, positions, votes);

        var positionVectors = new ArrayList<PositionVector>();
        for(int i = 0; i < positions.width(); i++) {
            var posData = positions.get(0, i);
            var voteData = votes.get(0, i);
            positionVectors.add(new PositionVector(posData[0], posData[1], posData[2], posData[3], voteData[0], voteData[1], voteData[2]));
        }

        final double maxPosVote = positionVectors.stream().map(PositionVector::posVotes).max(Double::compareTo).orElse(1.0);
        final double maxRotVote = positionVectors.stream().map(PositionVector::rotVotes).max(Double::compareTo).orElse(1.0);
        final double maxScaleVote = positionVectors.stream().map(PositionVector::scaleVotes).max(Double::compareTo).orElse(1.0);
        var bestScore = positionVectors.stream().map(v -> v.voteMagSqr(maxPosVote, maxRotVote, maxScaleVote)).max(Double::compareTo);

        MatOfPoint bestVoted = null;
        var output = new Mat();
        Imgproc.cvtColor(blurred, output, Imgproc.COLOR_GRAY2BGR);

        var contours = new ArrayList<MatOfPoint>();
        for (PositionVector v:positionVectors) {
            var rect = new RotatedRect(new Point(v.x(), v.y()), new Size(499, 499), v.rotation());
            var points = new Point[4];
            rect.points(points);
            final var contour = new MatOfPoint(points);

            if(v.voteMagSqr(maxPosVote, maxRotVote, maxScaleVote) == bestScore.get()) {
                bestVoted = contour;
            }

            contours.add(contour);
        }

        var drawMe = ContourOntoImage.createImageWithContours(output, contours, new Scalar(0, 0, 255), 1);
        if(bestVoted != null) {
            drawMe = ContourOntoImage.createImageWithContours(drawMe, List.of(bestVoted), new Scalar(255.0, 0.0, 255.0), 2);
        }
        Imgcodecs.imwrite("test_contours.png", drawMe);

        return positionVectors.stream().filter(pv -> pv.voteMagSqr(maxPosVote, maxRotVote, maxScaleVote) == bestScore.get()).findFirst().orElse(null);
    }

}

测试代码

@Test
public void perfectSquareRotNotScaledGuil() {
    loadLocally();
    Mat template = makeRectangularGrayBigTemplate();

    Mat blurred = makeRotatedBlurredRectangularGrayImage();

    PositionVector bestVoted = TemplateHoughGuilDetector.runHoughGuilDetection(template, blurred);

    var loc = new Point(bestVoted.x(), bestVoted.y());
    var rot = bestVoted.rotation();
    var scale = bestVoted.scale();

    assertThat(loc, is(closeToPoint(new Point(500, 500)).toWithin(1e-7)));
    assertThat(rot, is(closeTo(5.0, 1.0)));
    assertThat(scale, is(equalTo(1.0)));
}

private static Mat makeRotatedBlurredRectangularGrayImage() {
    Mat image = makeRotatedRectangularGrayImage();
    var blurred = new Mat();
    Imgproc.blur(image, blurred, new Size(3,3));
    return blurred;
}

private static Mat makeRectangularGrayBigTemplate() {
    var template = new Mat(501, 501, CvType.CV_8UC1, new Scalar(255));
    Imgproc.rectangle(template, new Point(1, 1), new Point(499, 499), new Scalar(0), Imgproc.FILLED);
    return template;
}

private static Mat makeRotatedRectangularGrayImage() {
    var image = new Mat(1000, 1000, CvType.CV_8UC1, new Scalar(255));
    var rectangle = new RotatedRect(new Point(500, 500), new Size(499.0, 499.0), 5);
    var vertices = new Point[4];
    rectangle.points(vertices);
    var matOfPoints = new MatOfPoint(vertices);
    Imgproc.fillConvexPoly(image, matOfPoints, new Scalar(0));
    return image;
}

测试结果

测试后得到检测结果图:![包含异常归一化分数轮廓的检测结果图]
模板图:![模板图]

参数测试总结

  • Levels参数未产生明显影响
  • 调整阈值会增加无效检测,但仍无法得到精准结果
  • DP参数能影响无效检测数量,但未找到官方说明
  • MinDist参数会提升位置检测密度,符合预期
  • AngleStep、AngleEpsilon参数无法得到正确角度
  • MinAngle、MaxAngle、MinScale、MaxScale、ScaleStep参数含义明确
  • 修改Xi参数至10.0或45.0时无法检测到目标,对该参数的具体含义存在疑问

求助内容

  1. 如何调整参数使测试用例得到准确的位置与角度?
  2. 获取GeneralizedHoughGuil检测器各参数的详细说明。

实际需求补充

我的实际需求是基于DXF模板检测带镂空面板类物体(如图:![工作台上的零件]),DXF模板如图:![DXF模板图]。目前已能通过轮廓检测实现,但需不依赖轮廓,基于镂空部分完成精准检测。

内容的提问来源于stack exchange,提问作者vextorspace

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 18:05:05