OpenCV - Finding contour end points?

限于喜欢 提交于 2019-12-01 11:42:45

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);

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;
    }

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 :)

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