使用 OpenCV / Python 绘制二元掩码轮廓

Contouring a binary mask with OpenCV / Python

使用 Python 和 OpenCV 我正在检测二进制掩码的轮廓:

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))

导致预期行为:

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

但是,我似乎无法理解完全激活掩码的结果:

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]

产生:

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

而不是(0 0), (0 99), (199, 99), (199, 0)

为什么 opencv findcontours 的行为是这样的,偏移量为 1?

直到 OpenCV 3.1 findContoursthis 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.

这有 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.


作为以前版本的解决方法,您可以使用 copyMakeBorder 创建 1 像素的黑色 (0) 边框,​​并使用偏移量 (-1,-1)findContours

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))