【问题标题】:Why cvFindContours() method doesn't detect Contours correctly in javacv?为什么 cvFindContours() 方法不能在 javacv 中正确检测轮廓?
【发布时间】:2012-07-17 12:58:49
【问题描述】:

我在 StackOverflow 中解决了很多问题,并且能够开发小程序来正确检测正方形和矩形。这是我的示例代码

public static CvSeq findSquares(final IplImage src, CvMemStorage storage) {
    CvSeq squares = new CvContour();
    squares = cvCreateSeq(0, sizeof(CvContour.class), sizeof(CvSeq.class), storage);
    IplImage pyr = null, timg = null, gray = null, tgray;
    timg = cvCloneImage(src);
    CvSize sz = cvSize(src.width(), src.height());
    tgray = cvCreateImage(sz, src.depth(), 1);
    gray = cvCreateImage(sz, src.depth(), 1);
    // cvCvtColor(gray, src, 1);
    pyr = cvCreateImage(cvSize(sz.width() / 2, sz.height() / 2), src.depth(), src.nChannels());
    // down-scale and upscale the image to filter out the noise
    // cvPyrDown(timg, pyr, CV_GAUSSIAN_5x5);
    // cvPyrUp(pyr, timg, CV_GAUSSIAN_5x5);
    // cvSaveImage("ha.jpg",timg);
    CvSeq contours = new CvContour();
    // request closing of the application when the image window is closed
    // show image on window
    // find squares in every color plane of the image
    for (int c = 0; c < 3; c++) {
        IplImage channels[] = { cvCreateImage(sz, 8, 1), cvCreateImage(sz, 8, 1), cvCreateImage(sz, 8, 1) };
        channels[c] = cvCreateImage(sz, 8, 1);
        if (src.nChannels() > 1) {
            cvSplit(timg, channels[0], channels[1], channels[2], null);
        } else {
            tgray = cvCloneImage(timg);
        }
        tgray = channels[c];
        // // try several threshold levels
        for (int l = 0; l < N; l++) {
            // hack: use Canny instead of zero threshold level.
            // Canny helps to catch squares with gradient shading
            if (l == 0) {
                // apply Canny. Take the upper threshold from slider
                // and set the lower to 0 (which forces edges merging)
                cvCanny(tgray, gray, 0, thresh, 5);
                // dilate canny output to remove potential
                // // holes between edge segments
                cvDilate(gray, gray, null, 1);
            } else {
                // apply threshold if l!=0:
                cvThreshold(tgray, gray, (l + 1) * 255 / N, 255,
                        CV_THRESH_BINARY);
            }
            // find contours and store them all as a list
            cvFindContours(gray, storage, contours, sizeof(CvContour.class), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
            CvSeq approx;
            // test each contour
            while (contours != null && !contours.isNull()) {
                if (contours.elem_size() > 0) {
                    approx = cvApproxPoly(contours, Loader.sizeof(CvContour.class), storage, CV_POLY_APPROX_DP, cvContourPerimeter(contours) * 0.02, 0);
                    if (approx.total() == 4 && Math.abs(cvContourArea(approx, CV_WHOLE_SEQ, 0)) > 1000 && cvCheckContourConvexity(approx) != 0) {
                        double maxCosine = 0;
                        for (int j = 2; j < 5; j++) {
                            // find the maximum cosine of the angle between
                            // joint edges
                            double cosine = Math.abs(angle(
                                            new CvPoint(cvGetSeqElem(
                                                    approx, j % 4)),
                                            new CvPoint(cvGetSeqElem(
                                                    approx, j - 2)),
                                            new CvPoint(cvGetSeqElem(
                                                    approx, j - 1))));
                            maxCosine = Math.max(maxCosine, cosine);
                        }
                        if (maxCosine < 0.2) {
                            CvRect x = cvBoundingRect(approx, l);
                            if ((x.width() * x.height()) < 50000) {
                                System.out.println("Width : " + x.width()
                                        + " Height : " + x.height());
                                cvSeqPush(squares, approx);
                            }
                        }
                    }
                }
                contours = contours.h_next();
            }
            contours = new CvContour();
        }
    }
    return squares;
}

我使用这张图片来检测矩形和正方形

我需要识别以下输出

但是当我运行上面的代码时,它只检测到以下矩形。但我不知道这是什么原因。请有人解释一下原因。

这是我得到的输出。

请在上面的代码中解释问题并给出一些建议来检测这个正方形和矩形。

【问题讨论】:

  • 我没有立即发现您的代码有问题,但可能只是您的标准之一过于苛刻。例如,您测试近似值中的最大段数是否为 4,但您确定没有伪影所以有 5 个吗?在不确切知道 opencv 逼近是如何工作的情况下,某些逼近算法在弯道前播种时会生成虚假段。另外,等高线内的区域是否总是大于 1000,您要测试它吗?
  • 它有助于打印算法的中间步骤(例如,canny 之后、阈值之后等)以查看发生了什么,并将它们发布在这里以寻求帮助。

标签: java opencv javacv


【解决方案1】:

给定一个蒙版图像(二进制图像,如您的第二个图),cvFindContours() 为您提供轮廓(几个点列表)。
看这个链接:http://dasl.mem.drexel.edu/~noahKuntz/openCVTut7.html

【讨论】:

    猜你喜欢
    • 2012-07-08
    • 1970-01-01
    • 2022-11-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-23
    • 2012-03-09
    • 2011-08-27
    • 2019-12-31
    相关资源
    最近更新 更多