2

我正在寻找一种方法来获取从 Canny 边缘检测中提取的细轮廓的端点。我想知道这是否可以通过某种内置方式实现。我计划穿过轮廓找到彼此距离最大的两个点(仅沿轮廓移动),但如果已经存在方法会容易得多。我看到存在 cvarcLength 以获得轮廓的周长,因此可能会有一种内置的方法来实现这一点。轮廓内的点是否以这样的方式排序,可以知道关于端点的一些信息?还有其他想法吗?非常感谢!

4

3 回答 3

1

我一直在寻找相同的功能,我看到HoughLinesP有端点,因为使用的是线条而不是轮廓。但是我正在使用 findContours,所以我发现像下面这样对轮廓中的点进行排序而不是将第一个和最后一个点作为起点和终点是有帮助的。

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);
于 2013-11-24T20:32:32.933 回答
0

正如你所说,你总是可以通过轮廓点。

下面找到两个点ptLeftptRight,沿 x 的间距最大,但可以根据需要进行修改。

    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;
    }
于 2014-07-30T19:51:06.300 回答
0

基于邻居距离检查的解决方案对我不起作用(Python + opencv 3.0.0-beta),因为我得到的所有轮廓似乎都折叠在自己身上。乍一看在图像上看起来像“开放”轮廓的东西实际上是折叠在自身上的“闭合”轮廓。

因此,我不得不求助于在每个轮廓的序列中寻找“u 形转弯”,这是 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))

不能完全抵抗污染尖端并且相当耗时,但这是一个开始。我自然会对其他想法感兴趣:)

于 2014-12-14T12:48:20.943 回答