Advanced square detection (with connected region)

前端 未结 3 1951
感动是毒
感动是毒 2021-01-31 12:23

if the squares has connected region in image, how can I detect them.

I have tested the method mentioned in OpenCV C++/Obj-C: Advanced square detection

It did no

3条回答
  •  萌比男神i
    2021-01-31 13:16

    You have three problems:

    1. The rectangles are not very strict rectangles (the edges are often somewhat curved)
    2. There are a lot of them.
    3. They are often connected.

    It seems that all your rects are essentially the same size(?), and do not greatly overlap, but the pre-processing has connected them.

    For this situation the approach I would try is:

    1. dilate your image a few times (as also suggested by @krzych) - this will remove the connections, but result in slightly smaller rects.
    2. Use scipy to label and find_objects - You now know the position and slice for every remaining blob in the image.
    3. Use minAreaRect to find the center, orientation, width and height of each rectangle.

    You can use step 3. to test whether the blob is a valid rectangle or not, by its area, dimension ratio or proximity to the edge..

    This is quite a nice approach, as we assume each blob is a rectangle, so minAreaRect will find the parameters for our minimum enclosing rectangle. Further we could test each blob using something like humoments if absolutely neccessary.

    Here is what I was suggesting in action, boundary collision matches shown in red.

    enter image description here

    Code:

    import numpy as np
    import cv2
    from cv2 import cv
    import scipy
    from scipy import ndimage
    
    im_col = cv2.imread('jdjAf.jpg')
    im = cv2.imread('jdjAf.jpg',cv2.CV_LOAD_IMAGE_GRAYSCALE)
    
    im = np.where(im>100,0,255).astype(np.uint8)
    im = cv2.erode(im, None,iterations=8)
    im_label, num = ndimage.label(im)
    for label in xrange(1, num+1):
        points = np.array(np.where(im_label==label)[::-1]).T.reshape(-1,1,2).copy()
        rect = cv2.minAreaRect(points)
        lines = np.array(cv2.cv.BoxPoints(rect)).astype(np.int)
        if any([np.any(lines[:,0]<=0), np.any(lines[:,0]>=im.shape[1]-1), np.any(lines[:,1]<=0), np.any(lines[:,1]>=im.shape[0]-1)]):
            cv2.drawContours(im_col,[lines],0,(0,0,255),1)
        else:
            cv2.drawContours(im_col,[lines],0,(255,0,0),1)
    
    cv2.imshow('im',im_col)
    cv2.imwrite('rects.png',im_col)
    cv2.waitKey()
    

    I think the Watershed and distanceTransform approach demonstrated by @mmgp is clearly superior for segmenting the image, but this simple approach can be effective depending upon your needs.

提交回复
热议问题