Home > OS >  opencv: how to merge near contours to get the one big outest contour?
opencv: how to merge near contours to get the one big outest contour?

Time:12-04

I am trying to digitize the kid's drawing into SVG or transparent png file format so that they can be used in Scratch. The white paper should be replaced by transparent background and all the drawing part should be preserved.

My plan is to get the outest contour of the drawing and generate a mask, then use the mask to get the drawing part without paper background.

The problem is the drawing may not consecutive which means there may have some small holes leading to break the entire drawing contour to many many small contours.

Now I want to concatenate the near outest contours to form a big outest contour for masking.

The original drawing and the processed result is attached.

enter image description here

Code:

from __future__ import print_function
import cv2 as cv
import numpy as np
import argparse
import random as rng
rng.seed(12345)
def thresh_callback(val):
    threshold = val
    # Detect edges using Canny
    canny_output = cv.Canny(src_gray, threshold, threshold * 2)
    # Find contours
    contours, hierarchy = cv.findContours(canny_output, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
    # Draw contours
    drawing = np.zeros((canny_output.shape[0], canny_output.shape[1], 3), dtype=np.uint8)
    for i in range(len(contours)):
        color = (rng.randint(0,256), rng.randint(0,256), rng.randint(0,256))
        cv.drawContours(drawing, contours, i, color, 2, cv.LINE_8, hierarchy, 0)
    # Show in a window
    cv.imshow('Contours', drawing)
# Load source image
parser = argparse.ArgumentParser(description='Code for Finding contours in your image tutorial.')
parser.add_argument('--input', help='Path to input image.', default='IMG_4446.jpg')
args = parser.parse_args()
src = cv.imread(cv.samples.findFile(args.input))
if src is None:
    print('Could not open or find the image:', args.input)
    exit(0)
# Convert image to gray and blur it
src_gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
src_gray = cv.blur(src_gray, (3,3))
# Create Window
source_window = 'Source'
cv.namedWindow(source_window)
cv.imshow(source_window, src)
max_thresh = 255
thresh = 100 # initial threshold
cv.createTrackbar('Canny Thresh:', source_window, thresh, max_thresh, thresh_callback)
thresh_callback(thresh)
cv.waitKey()

CodePudding user response:

import cv2, numpy as np

# Read Image
img = cv2.imread('/home/stephen/Desktop/test_img.png')
img  =cv2.resize(img, (750,1000))

test img

# Find the gray image
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # Gray
gray = cv2.blur(gray, (2,2))
cv2.imwrite('/home/stephen/Desktop/gray.png',gray)

gray

# Find the canny image
canny = cv2.Canny(gray, 30, 150) # Canny

# Find contours
contours, _ = cv2.findContours(canny,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

# Draw contours on canny (this connects the contours)
cv2.drawContours(canny, contours, -1, 255, 6)
cv2.imwrite('/home/stephen/Desktop/contours.png',canny)

contours

# Get mask for floodfill
h, w = canny.shape[:2]
mask = np.zeros((h 2, w 2), np.uint8)

mask

# Floodfill from point (0, 0)
cv2.floodFill(canny, mask, (0,0), 123)
cv2.imwrite('/home/stephen/Desktop/floodfill.png',canny)

floodfill

# Exclude everying but the floodfill region
canny = cv2.inRange(canny, 122, 124)
cv2.imwrite('/home/stephen/Desktop/inrange.png',canny)

INRANGE

  • Related