Janusz
Janusz

Reputation: 183

Is it possible to use OpenCV contour in python in a way that corners are not cut off?

I am using the OpenCV contour function in python. For example on an image like this:

enter image description here

contours, _ = cv2.findContours(img_expanded_padded, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

enter image description here It works well except that it cuts off the corners on the inside of the contour as seen above. Are there any options that would leave this corner in?

Travelling along the contours and filling them in manually will be too computationally expensive. The above is only an example. This will be performed many times on images 5400x5400 or more...

I can find the edges with the code below, and have filled corners as a result but then I need to extract these as contours again.

# FIND ALL HORIZONTAL AND VERTICAL EDGES AND COMBINE THEM
edges_expanded_x = np.absolute(cv2.Sobel(img_expanded_padded,cv2.CV_64F, 1, 0, ksize=3))
edges_expanded_y = np.absolute(cv2.Sobel(img_expanded_padded,cv2.CV_64F, 0, 1, ksize=3))
edges_expanded = np.logical_or(edges_expanded_x, edges_expanded_y)

# GET RID OF DOUBLE EDGE THAT RESULTS FROM SOBEL FILTER
edges_expanded = np.multiply(img_expanded_padded,edges_expanded)

Are there any OpenCV settings or functions I can use to accomplish this?

EDIT: I should clarify, that my goal is to have a single pixel continous contour. I need the contours and not an array of the entire image including the contours.

EDIT: The above images are zoomed into my test image. The actual pixels are as shown by the red grids in the images below.

enter image description here

enter image description here

Upvotes: 1

Views: 1322

Answers (1)

Vardan Agarwal
Vardan Agarwal

Reputation: 2181

There is no need to use cv2.Sobel you can simply draw contours with cv2.drawContours on a black background. The black background can be drawn with the help of np.zeros.

img = cv2.imread('contouring.png',0)
contours, _ = cv2.findContours(img, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
bgr = np.zeros((img.shape[0], img.shape[1]), dtype= 'uint8')
cv2.drawContours(bgr, contours, -1, (255,255,255), 1)

thin egdes

If you want the contour lines to be thick then you use cv2.dilate for that. Then to prevent the cutting of corners cv2.bitwise_and can be used along with cv2.bitwise_not as shown below

bgr = cv2.dilate(bgr, np.ones((31, 31), np.uint8), iterations=1)
bgr = cv2.bitwise_and(bgr, cv2.bitwise_not(img))

This gives contours which are 15 pixels thick. thick edges

EDIT- The first image of thin contours is still cutting corners. To obtain single pixel contours which do not corners we can use a kernel size of 3*3.

img = cv2.imread('contouring.png',0)
contours, _ = cv2.findContours(img, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
bgr = np.zeros((img.shape[0], img.shape[1]), dtype= 'uint8')
cv2.drawContours(bgr, contours, -1, (255,255,255), 1)
bgr = cv2.dilate(bgr, np.ones((3, 3), np.uint8), iterations=1)
bgr = cv2.bitwise_and(bgr, cv2.bitwise_not(img))

This gives us RESULT

I have checked it by using cv2.bitwise_and between bgr and img and I obtain a black image indicating that no white pixels are cutting corners.

Upvotes: 1

Related Questions