查找OpenCV轮廓的区域

时间:2015-04-17 13:42:40

标签: python opencv image-processing

在最近的一组图像中,我的OpenCV代码停止找到正确的轮廓区域。这似乎发生在轮廓未关闭时。我试图确保轮廓关闭无济于事。

编辑:问题在于轮廓中存在间隙。

背景 我在一个通道中有一系列胶囊图像,我想测量形状的区域以及瞬间的质心。

问题: 当轮廓没有关闭时,时刻是错误的。

编辑:当我有间隙时,轮廓不是整个形状,因此不正确的区域。

我做了什么:

  • 阅读图片 - > img = cv2.imread(fileName,0)
  • 应用Canny过滤器 - > edges = cv2.Canny(img,lowerThreshold,lowerThreshold * 2)
  • 查找轮廓 - > contours,hierarchy = cv2.findContours(edges,cv2.cv.CV_RETR_LIST,cv2.cv.CV_CHAIN_APPROX_NONE)
  • 找到最长轮廓
  • 确保轮廓关闭
  • 寻找时刻 - > cv2.moments(CNT)

可以找到包含测试图像的工作示例here

关于关闭轮廓有一个question,但这些建议都没有奏效。使用cv2.approxPolyDP不会更改结果,但应返回闭合轮廓。将轮廓的第一个点添加为最后一个,以使其关闭,也无法解决问题。

下面是轮廓绘制的图像示例。这里,区域被确定为85,而在几乎相同的图像中,它是8660,这应该是它应该是的。 http://www.negative-probability.co.uk/docs/ImageWContour_0.png

任何建议都会得到满足。

代码:

img =cv2.imread(fileName,0)
edges = cv2.Canny(img,lowerThreshold,lowerThreshold*2)
contours, hierarchy = cv2.findContours(edges,cv2.cv.CV_RETR_LIST,cv2.cv.CV_CHAIN_APPROX_NONE) #cv2.cv.CV_CHAIN_APPROX_NONE or cv2.cv.CV_CHAIN_APPROX_SIMPLE

#Select longest contour as this should be the capsule
lengthC=0
ID=-1
idCounter=-1
for x in contours:
    idCounter=idCounter+1 
    if len(x) > lengthC:
        lengthC=len(x)
        ID=idCounter

if ID != -1:
    cnt = contours[ID]
    cntFull=cnt.copy()

    #approximate the contour, where epsilon is the distance to 
    #the original contour
    cnt = cv2.approxPolyDP(cnt, epsilon=1, closed=True)

    #add the first point as the last point, to ensure it is closed
    lenCnt=len(cnt)
    cnt= np.append(cnt, [[cnt[0][0][0], cnt[0][0][1]]]) 
    cnt=np.reshape(cnt, (lenCnt+1,1, 2))

    lenCntFull=len(cntFull)
    cntFull= np.append(cntFull, [[cntFull[0][0][0], cntFull[0][0][1]]]) 
    cntFull=np.reshape(cntFull, (lenCntFull+1,1, 2))

    #find the moments
    M = cv2.moments(cnt)
    MFull = cv2.moments(cntFull)
    print('Area = %.2f \t Area of full contour= %.2f' %(M['m00'], MFull['m00']))

3 个答案:

答案 0 :(得分:1)

我的问题是,正如@HugoRune指出的那样,计数器中存在空白。解决方案是缩小差距。

我发现很难找到一种缩小间隙的通用方法,所以我迭代地改变Canny滤波器的阈值并执行morphological closing直到找到闭合的轮廓。

对于那些遇到同样问题的人来说,如何关闭轮廓有几个很好的答案,例如thisthis

答案 1 :(得分:1)

在处理了类似的问题之后,另一种解决方案(并且可以说更简单,开销更少)是使用形态学开放功能,其执行侵蚀,然后进行扩张。如果您首先将其转换为二进制图像,请执行打开操作,并执行Canny检测,这应该执行相同的操作,但不必迭代过滤器。您唯一需要做的就是使用内核大小几次来确定合适的大小而不会丢失太多细节。我发现这是确保轮廓关闭的一种相当强大的方法。

Morphological operations documentation

答案 2 :(得分:0)

另一种方法是使用轮廓点查找区域。在这里以前通过cvFindContours()找到了nContours。我在这里使用了MFC CArray。您也可以使用std :: vector。

////////////////////////////////////////////

CvSeq* MasterContour = NULL;
if (nContours > 1)
{
    // Find the biggest contour
    for (int i = 0; i < nContours; i++)
    {
        CvRect rect = cvBoundingRect(m_contour, 1);
        if (rect.width > rectMax.width)
            MasterContour = m_contour;
        if (m_contour->h_next != 0)
            m_contour = m_contour->h_next;
        else
            break;
    }
}
else
    MasterContour = m_contour;

arOuterContourPoints.RemoveAll();
CArray<CPoint, CPoint> arOuterTrackerPoints;
for (int i = 0; i < MasterContour->total; i++)
{       
    CvPoint *pPt; 
    pPt = (CvPoint *)cvGetSeqElem(MasterContour, i);
    arOuterContourPoints.Add(CPoint(pPt->x, pPt->y));
}
int nOuterArea = 0;
for (int i = 0; i < arOuterContourPoints.GetSize(); i++)
{
    if (i == (arOuterContourPoints.GetSize() - 1))
        nOuterArea += (arOuterContourPoints[i].x * arOuterContourPoints[0].y - arOuterContourPoints[0].x * arOuterContourPoints[i].y);
    else
        nOuterArea += (arOuterContourPoints[i].x * arOuterContourPoints[i+1].y - m_arOuterContourPoints[i+1].x * m_arOuterContourPoints[i].y);
}
nOuterAreaPix = abs(nOuterArea / 2.0);

///////////////////////////////////////////////// ////////////