OpenCV - Finding contour end points?

此生再无相见时 提交于 2019-12-19 11:24:23

问题


I'm looking for a way to get the end points of a thin contour extracted from a Canny edge detection. I was wondering is this is possible with some built-in way. I would plan on walking through the contour to find the two points with the largest distance from each other (moving only along the contour), but it would be much easier if a way already exists. I see that cvarcLength exists to get the perimeter of a contour, so it's possible there would be a built-in way to achieve this. Is it are the points within a contour ordered in such a way that some information can be known about the end points? Any other ideas? Thank you much!


回答1:


I was looking for the same function, I see HoughLinesP has end points since lines are used not contours. I am using findContours however so I found it was helpful to order the points in the contours like this below and than take the first and last points as the start and end points.

struct contoursCmpY {
    bool operator()(const Point &a,const Point &b) const {
        if (a.y == b.y)
            return a.x < b.x;

        return a.y < b.y;
    }
} contoursCmpY_;

vector<Point> cont;
cont.push_back(Point(194,72));
cont.push_back(Point(253,14));
cont.push_back(Point(293,76));
cont.push_back(Point(245,125));

std::sort(cont.begin(),cont.end(), contoursCmpY_);

int size = cont.size();
printf("start Point x=%d,y=%d end Point x=%d,y=%d", cont[0].x, cont[0].y, cont[size].x, cont[size].y);



回答2:


As you say, you can always step through the contour points.

The following finds the two points, ptLeft and ptRight, with the greatest separation along x, but could be modified as needed.

    CvPoint ptLeft = cvPoint(image->width, image->height);
    CvPoint ptRight = cvPoint(0, 0);
    CvSlice slice = cvSlice(0, CV_WHOLE_SEQ_END_INDEX);
    CvSeqReader reader;
    cvStartReadSeq(contour, &reader, 0);
    cvSetSeqReaderPos(&reader, slice.start_index);
    int count = cvSliceLength(slice, contour);
    for(int i = 0; i < count; i++)
    {
        reader.prev_elem = reader.ptr;
        CV_NEXT_SEQ_ELEM(contour->elem_size, reader);

        CvPoint* pt = (CvPoint*)reader.ptr;
        if( pt->x < ptLeft.x )
            ptLeft = *pt;
        if( pt->x > ptRight.x )
            ptRight = *pt;
    }



回答3:


The solution based on neighbor distances check didn't work for me (Python + opencv 3.0.0-beta), because all contours I get seem to be folded on themselves. What would appear as "open" contours at first glance on an image are actually "closed" contours collapsed on themselves.

So I had to resort to look for "u-turns" in each contour's sequence, an example in Python:

import numpy as np

def draw_closing_lines(img, contours):
    for cont in contours:
        v1 = (np.roll(cont, -2, axis=0) - cont)
        v2 = (np.roll(cont, 2, axis=0) - cont)
        dotprod = np.sum(v1 * v2, axis=2)
        norm1 = np.sqrt(np.sum(v1 ** 2, axis=2))
        norm2 = np.sqrt(np.sum(v2 ** 2, axis=2))
        cosinus = (dotprod / norm1) / norm2
        indexes = np.where(0.95 < cosinus)[0]
        if len(indexes) == 1:
            # only one u-turn found, mark in yellow
            cv2.circle(img, tuple(cont[indexes[0], 0]), 3, (0, 255, 255))
        elif len(indexes) == 2:
            # two u-turns found, draw the closing line
            cv2.line(img, tuple(tuple(cont[indexes[0], 0])), tuple(cont[indexes[1], 0]), (0, 0, 255))
        else:
            # too many u-turns, mark in red
            for i in indexes:
                cv2.circle(img, tuple(cont[i, 0]), 3, (0, 0, 255))

Not completely robust against polluting cusps and quite time-consuming, but that's a start. I'd be interested in other ideas, naturally :)



来源:https://stackoverflow.com/questions/19734282/opencv-finding-contour-end-points

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!