Search code examples
opencvedgesoutline

OpenCV: How to remove the unwanted parts in an image


I am trying to get the outline of the blue area in an image and then calculate the length and area, as shown in the picture (I have many similar images with the same resolution but different size of the blue areas). enter image description here

Here is the code I am using:

import cv2
import numpy as np

# read image as grayscale
img = cv2.imread('VF2.jpg', cv2.IMREAD_GRAYSCALE)

# threshold to binary
thresh = cv2.threshold(img, 210, 255, cv2.THRESH_BINARY)[1]  # the 2nd parameter should be changed.

# apply morphology
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
morph = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)

# find contours - write black over all small contours
letter = morph.copy()
cntrs = cv2.findContours(morph, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)  
# cntrs = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)  

cntrs = cntrs[0] if len(cntrs) == 2 else cntrs[1]
# cntrs = cntrs[0]

for c in cntrs:
    area = cv2.contourArea(c)
    print(area)
    if area < 100:
        cv2.drawContours(letter,[c],0,(0,0,0),-1)

# do canny edge detection
edges = cv2.Canny(letter, 200, 200) # the result for edges is good.
length = cv2.arcLength(cntrs[0], False)  # not closed curves
print('length = ',length)  # both length and area need calibration


area = cv2.contourArea(cntrs[0])
print('area = ',area)

# Outputs
print(np.squeeze(cntrs[0]), '\n')                    # Contour
print('Contour points:', cntrs[0].shape[0], '\n')
print('arcLength:', cv2.arcLength(cntrs[0], True))  # closed curves

# write results
# cv2.imwrite("K_thresh.png", thresh)    

# show results
# cv2.imshow("K_thresh", thresh)
# cv2.imshow("K_morph", morph)
cv2.imshow("K_letter", letter)
cv2.imshow("K_edges", edges)
cv2.waitKey(0)
cv2.destroyAllWindows()

I used the above code and obtained the outline but with some additional parts, as highlighted in the following image. Can any one help to delete the additional parts and make the outline closed? Thanks a lot.

enter image description here


Solution

  • Change the size of your kernel to (4, 4) and perform erosion instead of open, here:

    import cv2
    import numpy as np
    
    img = cv2.imread("images/flower.jpg", cv2.IMREAD_GRAYSCALE)
    scale_percent = 60 # percent of original size
    width = int(img.shape[1] * scale_percent / 100)
    height = int(img.shape[0] * scale_percent / 100)
    dim = (width, height)
      
    # resize image
    resized = cv2.resize(img, dim, interpolation = cv2.INTER_AREA)
    
    # threshold to binary
    thresh = cv2.threshold(resized, 210, 255, cv2.THRESH_BINARY_INV)[1]  # the 2nd parameter should be changed.
    
    # apply morphology
    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (4,4))
    morph = cv2.morphologyEx(thresh, cv2.MORPH_ERODE, kernel, 1)
    
    letter = morph.copy()
    cntrs = cv2.findContours(morph, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)  
    # cntrs = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)  
    
    cntrs = cntrs[0] if len(cntrs) == 2 else cntrs[1]
    # cntrs = cntrs[0]
    
    for c in cntrs:
        area = cv2.contourArea(c)
        print(area)
        if area < 100:
            cv2.drawContours(letter,[c],0,(0,0,0),-1)
    
    
    # do canny edge detection
    edges = cv2.Canny(letter, 200, 200) # the result for edges is good.
    length = cv2.arcLength(cntrs[0], False)  # not closed curves
    print('length = ',length)  # both length and area need calibration
    
    area = cv2.contourArea(cntrs[0])
    print('area = ',area)
    
    # Outputs
    print(np.squeeze(cntrs[0]), '\n')                    # Contour
    print('Contour points:', cntrs[0].shape[0], '\n')
    print('arcLength:', cv2.arcLength(cntrs[0], True))  # closed curves
    
    # write results
    # cv2.imwrite("K_thresh.png", thresh)    
    
    # show results
    # cv2.imshow("K_thresh", thresh)
    # cv2.imshow("K_morph", morph)
    cv2.imshow("K_letter", letter)
    cv2.imshow("K_edges", edges)
    cv2.waitKey(0)
    cv2.destroyAllWindows()