avereux
avereux

Reputation: 607

Redraw contours to original image after erosion

I have a function that erodes certain contours more or less depending on their area size. However, once they are cropped they lose the proper coordinate data that corresponds to the original image.

How can I redraw my eroded_contours to the original image while maintaining their original position? Or is there a better approach to using custom erosion based on contour area size?

edged = cv2.Canny(original_image.copy(), 50, 200)
contours, hierarchy = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

def show_each_contour(original_image):
    for i,c in enumerate(contours):
        area = cv2.contourArea(c)
        if area > 0:
            rect = cv2.boundingRect(c)
            x,y,w,h = rect
            start_row, start_col = int(x), int(y)
            end_row, end_col = int(x+x+w), int(y+y+h)

            cv2.rectangle(original_image, (x,y), (x+w,y+h), (0,0,255), 2)
            cropped = original_image[y:y+h, x:x+w]

            if area < 2000:
                kernel = np.ones((5,5), np.uint8)
                numberOfIterations = area / 200
            else:
                kernel = np.ones((5,5), np.uint8)
                numberOfIterations = 7

            eroded_contours = cv2.erode(cropped.copy(), kernel, iterations = int(numberOfIterations))

        #This won't work correctly because the coordinates are different now
        #cv2.drawContours(original_image, eroded_contours , -1, (0,255,255), 3)

Upvotes: 1

Views: 824

Answers (1)

Elouarn Laine
Elouarn Laine

Reputation: 1695

If I understood correctly what you are asking, you were pretty close to your goal.

Here is what I came up with (using Python 3.6 & OpenCV 3.2) :

edged = cv2.Canny(input_img.copy(), 50, 200)
_, contours, hierarchy = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # note that this function returns 3 values

def show_each_contour(original_image):
    margin = 2 # you can set the margin to 0 to better understand its effect
    for i,c in enumerate(contours):
        area = cv2.contourArea(c)
        if area > 0:
            rect = cv2.boundingRect(c)
            x,y,w,h = rect

            cv2.rectangle(original_image, (x-margin,y-margin), (x+w+margin,y+h+margin), (0,0,255), 2)
            cropped = original_image[y-margin:y+h+margin, x-margin:x+w+margin]

            if area < 2000:
                kernel = np.ones((5,5), np.uint8)
                numberOfIterations = area / 200
            else:
                kernel = np.ones((5,5), np.uint8)
                numberOfIterations = 7

            eroded_shape = cv2.erode(cropped.copy(), kernel, iterations = int(numberOfIterations))
            original_image[y-margin:y+h+margin, x-margin:x+w+margin] = eroded_shape # we copy the eroded_shape back into the original_image

I didn't change much of your code besides the last line where I copy the eroded shape into the right location of the original image.

Result

input and output images Input image on the left side, and the output on the right side.

Hope this helps and please tell me if this is not what you were looking for.

Upvotes: 2

Related Questions