我的这个答案基于我之前给出的答案:在Python中查找二进制图像中两个轮廓之间边界的所有像素 https://stackoverflow.com/a/75928327
基本上:
- apply
findContours
- 有选择地构建新的轮廓集
我们有边界,就是那些封闭的白线。每个边界都有一个外轮廓(“轮廓”)和内轮廓(“内联”)。
两个边界之间的空间我称之为“流明”。它由外边界的内线和内边界的轮廓界定。
轮廓层次:
- 级别 0:轮廓边界 1
- 级别 1:内联边界 1 = 流明 0 轮廓
- 级别 2:轮廓边界 2 = 内嵌流明 0
- 级别 3:内联边界 2 = 内腔 1 轮廓
- 级别 4:轮廓边界 3 = 内腔 1 内联
- 级别 5:内联边界 3 = 内腔 2 轮廓
- 级别 6:轮廓边界 4 = 内腔 2 内联
- ...
您想要填充交替的亮度 (0, 2, 4, ...)。这需要轮廓 1+2、5+6、9+10...
如果您想用某些东西填充所有发光体,只需选择正确的发光体并给它们合适的颜色即可。
contours, hierarchy = cv.findContours(im, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
hierarchy = hierarchy.squeeze(0) # vector<Vec4i> -> row vector of Vec4i, so (1,N,4), weird shape
ncontours = len(contours)
# extend hierarchy to include nesting level
(NEXT, PREV, CHILD, PARENT, LEVEL) = range(5)
# first four are defined by OpenCV in the docs of `findContours`
# fifth is my own addition
hierarchy = np.hstack((
hierarchy[:,:4],
np.full((ncontours, 1), -1, dtype=np.int32) # level
))
def get_level(i):
if hierarchy[i, LEVEL] != -1:
return hierarchy[i, LEVEL]
else:
level = 0 if (hierarchy[i, PARENT] == -1) else 1 + get_level(hierarchy[i, PARENT])
hierarchy[i, LEVEL] = level
return level
for i in range(ncontours):
hierarchy[i, LEVEL] = get_level(i)
#predicate to decide which contours to keep
def do_include(index, mod=2, offset=0):
level = hierarchy[index, LEVEL]
# level: 1+2, 5+6, 9+10, ...
# lumen: 0, 2, 4, ...
lumen = (level-1) // 2
if lumen < 0: return False # outermost contour, not the outline of any lumen (is inline of background)
return lumen % mod == offset
even_lumina = [ contours[i] for i in range(len(contours)) if do_include(i, 2, 0) ]
odd_lumina = [ contours[i] for i in range(len(contours)) if do_include(i, 2, 1) ]
composite = cv.cvtColor(im, cv.COLOR_GRAY2BGR)
cv.drawContours(image=composite, contours=even_lumina, contourIdx=-1, color=(0,0,255), thickness=cv.FILLED)
cv.drawContours(image=composite, contours=odd_lumina, contourIdx=-1, color=(255,0,0), thickness=cv.FILLED)
composite[im > 0] = 255 # overlay boundaries for neatness