适合四边形(Tetragon)到blob

时间:2016-12-14 08:32:12

标签: opencv image-processing computer-vision model-fitting

在应用不同的过滤和分割技术后,我最终得到了这样的图像:

enter image description here

我可以访问一些轮廓检测函数,这些函数返回该对象边缘上的点列表,或者返回一个拟合多边形(虽然有很多边,但远远超过4)。 我想要一种方法来将四边形贴合到那个形状上,因为我知道这是一个应该是四边形的鞋盒的正面。由于透视图,并行性不守恒,所以我现在没有约束,只需要包含这个框的四个线段。

到目前为止我所能找到的只是矩形拟合,它并没有真正返回我需要的结果,因为它迫使拟合的四边形为矩形。

如果我可以访问相机与鞋盒的相对角度并知道鞋盒与相机之间的距离,我可以生成一个Homography矩阵并扭曲图像,使鞋盒再次显示为矩形,但是现在我无法访问此类信息,并希望以纯粹的愿景为基础。

解决此类问题的任何已知方法?

1 个答案:

答案 0 :(得分:11)

我建议采取以下步骤:

  1. threshold()图片
  2. dilate() the image - 这将删除分割顶部和底部的黑线以及下部较暗的文物
  3. findContours()使用设置仅检索外部轮廓(RETR_EXTERNAL)并简化输出(CHAIN_APPROX_SIMPLE
  4. 进一步处理轮廓
  5. 第1步:阈值

    # threshold image
    ret,thresh = cv2.threshold(img,127,255,0)
    cv2.imshow('threshold ',thresh)
    

    threshold

    第2步:扩张

    # dilate thresholded image - merges top/bottom 
    kernel = np.ones((3,3), np.uint8)
    dilated = cv2.dilate(thresh, kernel, iterations=3)
    cv2.imshow('threshold dilated',dilated)
    

    dilate

    第3步:找到轮廓

    # find contours
    contours, hierarchy = cv2.findContours(dilated,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
    cv2.drawContours(img, contours, 0, (255,255,255), 3)
    print "contours:",len(contours)
    print "largest contour has ",len(contours[0]),"points"
    

    contours

    请注意,首先放大,然后使用简单的外部轮廓让你塑造你之后,但它仍然相当复杂(包含279个点)

    从这一点开始,你可以进一步process the contour features。 有几个选项,例如:

    a:获得最低分。区域矩形

    # minAreaRect
    rect = cv2.minAreaRect(contours[0])
    box = cv2.cv.BoxPoints(rect)
    box = np.int0(box)
    cv2.drawContours(img,[box],0,(255,255,255),3)
    

    minAreaRect

    可能有用,但不完全符合您的需要。

    b:凸包

    # convexHull
    hull = cv2.convexHull(contours[0])
    cv2.drawContours(img, [hull], 0, (255,255,255), 3)
    print "convex hull has ",len(hull),"points"
    

    convexHull

    更好,但你还有22分要处理,而且它可能不紧张

    c:简化轮廓

    # simplify contours
    
    epsilon = 0.1*cv2.arcLength(contours[0],True)
    approx = cv2.approxPolyDP(contours[0],epsilon,True)
    cv2.drawContours(img, [approx], 0, (255,255,255), 3)
    print "simplified contour has",len(approx),"points"
    

    aproxPolyDP

    这可能是你之后的事情:仅仅4分。 如果您需要更多积分,可以使用epsilon值。

    请记住,现在你有一个四边形,但是图片却变平了:没有关于透视/三维旋转的信息。

    完整的OpenCV Python代码清单(根据需要注释/取消注释,使用引用来适应c ++ / java /等):

    import numpy as np
    import cv2
    
    img = cv2.imread('XwzWQ.png',0)
    
    # threshold image
    ret,thresh = cv2.threshold(img,127,255,0)
    cv2.imshow('threshold ',thresh)
    
    # dilate thresholded image - merges top/bottom 
    kernel = np.ones((3,3), np.uint8)
    dilated = cv2.dilate(thresh, kernel, iterations=3)
    cv2.imshow('threshold dilated',dilated)
    
    # find contours
    contours, hierarchy = cv2.findContours(dilated,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
    # cv2.drawContours(img, contours, 0, (255,255,255), 3)
    print "contours:",len(contours)
    print "largest contour has ",len(contours[0]),"points"
    
    # minAreaRect
    # rect = cv2.minAreaRect(contours[0])
    # box = cv2.cv.BoxPoints(rect)
    # box = np.int0(box)
    # cv2.drawContours(img,[box],0,(255,255,255),3)
    
    # convexHull
    # hull = cv2.convexHull(contours[0])
    # cv2.drawContours(img, [hull], 0, (255,255,255), 3)
    # print "convex hull has ",len(hull),"points"
    
    # simplify contours
    epsilon = 0.1*cv2.arcLength(contours[0],True)
    approx = cv2.approxPolyDP(contours[0],epsilon,True)
    cv2.drawContours(img, [approx], 0, (255,255,255), 3)
    print "simplified contour has",len(approx),"points"
    
    
    # display output 
    cv2.imshow('image',img)
    
    cv2.waitKey(0)
    cv2.destroyAllWindows()