Search code examples
opencvimage-processingobject-detectioncontour

How to divide image into two parts without crossing any object using openCV?


I am using an object detection machine learning model (only 1 object). It working well in case there are a few objects in image. But, if my image has more than 300 objects, it can't recognize anything. So, I want to divide it into two parts or four parts without crossing any object.

I used threshold otsu and get this threshold otsu image. Actually I want to divide my image by this line expect image. I think my model will work well if make predictions in each part of image.

I tried to use findContour, and find contourArea bigger than a half image area, draw it into new image, get remain part and draw into another image. But most of contour area can't reach 1/10 image area. It is not a good solution.

I thought about how to detect a line touch two boundaries (top and bottom), how can I do it?

Any suggestion is appreciate. Thanks so much.


Solution

  • Since your region of interests are separated already, you can use connectedComponents to get the bounding boxes of these regions. My approach is below.

    img = cv2.imread('circles.png',0)
    img = img[20:,20:] # remove the connecting lines on the top and the left sides
    
    _, img = cv2.threshold(img,0,1,cv2.THRESH_BINARY)
    
    labels,stats= cv2.connectedComponentsWithStats(img,connectivity=8)[1:3]
    
    plt.imshow(labels,'tab10')
    plt.show()
    

    labels

    As you can see, two regions of interests have different labels. All we need to do is to get the bounding boxes of these regions. But first, we have to get the indices of the regions. For this, we can use the size of the areas, because after the background (blue), they have the largest areas.

    areas = stats[1:,cv2.CC_STAT_AREA] # the first index is always for the background, we do not need that, so remove the background index
    
    roi_indices = np.flip(np.argsort(areas))[0:2] # this will give you the indices of two largest labels in the image, which are your ROIs 
    
    # Coordinates of bounding boxes
    left = stats[1:,cv2.CC_STAT_LEFT] 
    top = stats[1:,cv2.CC_STAT_TOP] 
    width = stats[1:,cv2.CC_STAT_WIDTH] 
    height = stats[1:,cv2.CC_STAT_HEIGHT] 
    
    
    for i in range(2):
        roi_ind = roi_indices[i]
        roi = labels==roi_ind+1
    
        roi_top = top[roi_ind]
        roi_bottom = roi_top+height[roi_ind]
        roi_left = left[roi_ind]
        roi_right = roi_left+width[roi_ind]
    
    
        roi = roi[roi_top:roi_bottom,roi_left:roi_right]
        plt.imshow(roi,'gray')
        plt.show()
    

    roi_0 roi_1

    For your information, my method is only valid for 2 regions. In order to split into 4 regions, you would need some other approach.