Почему метод cvFindContours () неправильно определяет контуры в javacv?

Я ответил на множество вопросов в 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;
}

Я использую это изображение для обнаружения прямоугольников и квадратов.

введите описание изображения здесь

Мне нужно определить следующий результат

введите описание изображения здесь

и

введите описание изображения здесь

Но когда я запускаю приведенный выше код, он обнаруживает только следующие прямоугольники. Но я не знаю причины этого. Кто-нибудь может объяснить причину этого.

Это результат, который я получил.

введите описание изображения здесь

Пожалуйста, будьте достаточно любезны, чтобы объяснить проблему в приведенном выше коде и дать некоторые предложения по обнаружению этих квадратов и прямоугольников.


person Gum Slashy    schedule 18.07.2012    source источник
comment
Я не сразу вижу проблему с вашим кодом, но может быть просто один из ваших критериев слишком жесткий. Например, вы проверяете, составляет ли максимальное количество сегментов в приближении 4, но уверены ли вы, что артефактов никогда не бывает, поэтому их пять? Не зная точно, как работает приближение opencv, определенные алгоритмы приближения будут генерировать ложные сегменты, когда они засеваются непосредственно перед изгибом. Кроме того, всегда ли площадь внутри контуров превышает 1000, что вы проверяете?   -  person dvhamme    schedule 01.08.2012
comment
Это помогает распечатать промежуточные шаги (например, после хитрости, после порога и т. Д.) Вашего алгоритма, чтобы увидеть, что происходит, и опубликовать их здесь для получения помощи.   -  person Rui Marques    schedule 01.10.2012


Ответы (1)


Учитывая изображение маски (двоичное изображение, подобное вашему второму рисунку), cvFindContours () дает вам контуры (несколько списков точек).
посмотрите на эту ссылку: http://dasl.mem.drexel.edu/~noahKuntz/openCVTut7.html

person Adam Woo    schedule 06.11.2012