Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Contouring a binary mask with OpenCV / Python

With Python and OpenCV I am detecting contours of a binary mask:

import numpy as np
import cv2
import matplotlib.pyplot as plt

mask = np.zeros(20000, dtype=np.uint8).reshape(100, 200)
mask[5:-5,5:-5] = 255
mask[10:70,40:80] = 0
plt.subplot(121)
plt.imshow(mask, cmap='Greys_r', interpolation='none')

_, contours, hierarchy = cv2.findContours(mask.copy(), 
                                          cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE,
                                          offset=(0, 0))

Resulting in an expected behaviour :

plt.subplot(122)
cv2.drawContours(mask, contours, -1, (127, 127, 127), 2)
plt.imshow(mask, cmap='Greys_r',  interpolation='none')
plt.show()

Simple opencv contouring

However, I cannot seem to understand the result of a full activated mask :

mask = np.ones(20000, dtype=np.uint8).reshape(100, 200)
mask *=255
_, contours, hierarchy = cv2.findContours(mask.copy(),
                                            cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE,
                                            offset=(0, 0))

print contours[0]

Which produces:

(1   1), (1  98), (198 98), (198 1)

instead of (0 0), (0 99), (199, 99), (199, 0)

Why is opencv findcontours behaving like that, with an offset of 1?

like image 683
mxdbld Avatar asked Jun 04 '26 03:06

mxdbld


1 Answers

Until OpenCV 3.1 findContours has this wierd behaviour on borders, also stated in the documentation:

Source image is modified by this function. Also, the function does not take into account 1-pixel border of the image (it's filled with 0's and used for neighbor analysis in the algorithm), therefore the contours touching the image border will be clipped.

This has been corrected in OpenCV 3.2, which also doesn't modify the source image:

Since opencv 3.2 source image is not modified by this function.


As a workaround for previous releases, you can use copyMakeBorder to create a black (0) border of 1 pixel, and use findContours with an offset of (-1,-1):

border = cv2.copyMakeBorder(mask, 1, 1, 1, 1, cv2.BORDER_CONSTANT, value=0 )
_, contours, hierarchy = cv2.findContours(border, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE, offset=(-1, -1))
like image 120
Miki Avatar answered Jun 06 '26 17:06

Miki



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!