虽然Canny.之类的边缘检测算法可以根据像素间的差异检测出轮廓边界的像素,但是它并没有将轮廓作为一个整体进行处理。下一步是要将这些边缘像素合成轮廓。本文记录 OpenCV 中的轮廓查找的相关操作。
cv2.findContours()
从二维图像中计算轮廓。它处理的图像可以是从 cv2.Canny()
函数得到的有边缘像素的图像,或是从cv2.threshold()
及cv2.adaptiveThreshold()
函数得到的图像,这时边缘是正负区域之间的边界。cv2.findContours()
非常重要。找出二值图中的轮廓。 官方文档
cv2.findContours(
image, # uint8 单通道图像,非零值即为前景,0为背景
mode, # 轮廓检索模式
method[, # 轮廓近似法
contours[, # 检测到的轮廓。每个轮廓都存储为点向量
hierarchy[, # 可选输出向量, 包含有关图像拓扑的信息。它具有与轮廓数一样多的元素
offset]]] # 每个轮廓点移动的可选偏移量。
如果从图像 ROI 中提取轮廓,然后应该在整个图像上下文中对其进行分析,可以使用该参数。
) ->
contours,
hierarchy
method:ContourApproximationModes
取值 含义 cv2.CHAIN_APPROX_NONE 存储了所有的轮廓点。也就是说,等高线的任意2个后续点(x1,y1)和(x2,y2)将是水平、垂直或对角线邻居,即 max (abs (x1-x2),abs (y2-y1)) = 1。 cv2.CHAIN_APPROX_SIMPLE 压缩水平、垂直和对角线段,只留下它们的端点。例如,一个直立的矩形轮廓用 4 个点进行编码。 cv2.CHAIN_APPROX_TC89_L1 运用了 Teh-Chin 连锁近似演算法的一种 cv2.CHAIN_APPROX_TC89_KCOS 运用了 Teh-Chin 连锁近似演算法的一种
mode:RetrievalModes
img = 255 - mt.cv_rgb_imread('conc.png', gray=True)
contours, hierarchy = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
contours = mt.get_list_from_list(contours, lambda x: np.squeeze(x))
points = np.vstack(contours)
res = np.zeros_like(img)
res[points[:, 1], points[:, 0]] = 255
mt.PIS(img, res)
获得一列轮廓后,一个最常用的功能是在屏幕上绘制检测到的轮廓。绘制轮廓可以用cv2.drawContours()
函数完成。
绘制等高线轮廓或填充等高线。 官方文档
cv2.drawContours(
image, # 目标画布图像
contours, # 轮廓
contourIdx, # 参数表示要绘制的轮廓。如果为负值,则绘制所有轮廓。
color[, # 颜色
thickness[, # 宽度
lineType[, # 线型
hierarchy[, # 有关层次结构的可选信息。仅当您只想绘制一些轮廓时才需要它(请参阅 maxLevel )。
maxLevel[, # 绘制轮廓的最大级别。
如果为 0,则仅绘制指定的轮廓。如果为 1,则函数绘制轮廓和所有嵌套轮廓。
如果为 2,则函数绘制轮廓、所有嵌套轮廓、所有嵌套到嵌套的轮廓,依此类推。仅当存在可用层次结构时才考虑此参数。
offset]]]]]
) -> image
img = 255 - mt.cv_rgb_imread('conc.png', gray=True)
contours, hierarchy = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
res = np.zeros_like(img)
cv2.drawContours(res, contours, 2, [200], -1)
PIS(img, res)
cv2.findContours()
函数首先为每条轮廓分配一个独立的标准模板库向量, 而图像中可能存在上百、甚至上千条轮廓。之后当你想填充一块由一条或多条轮廓包围的非凸区域时,cv2.drawContours()
也很慢,而且需要收集所有包围该区域的小线段并排序。最后,收集一块连通区域的基本信息(例如一块区域或一个包围框)需要更多、更耗时的函数调用。
计算布尔图像的连接组件标记图像 官方文档
cv2.connectedComponents(
image[, # 要标记的 8 位单通道图像
labels[, # 输出的目标图像
connectivity[, # 8 或 4 分别用于 8 路或 4 路连接
ltype]]] # 输出类型
) ->
retval, # 连通域个数(包含背景 0)
labels
# 选择指定算法计算连通域
cv2.connectedComponentsWithAlgorithm(
image, # 要标记的 8 位单通道图像
connectivity, # 8 或 4 分别用于 8 路或 4 路连接
ltype, # 输出图像标签类型。目前支持 CV_32S 和 CV_16U
ccltype[, # 连通算法类型
labels] # 输出的目标图像
) ->
retval, # 连通域个数(包含背景 0)
labels
cv2.CCL_DEFAULT
,cv2.CCL_WU
,cv2.CCL_GRANA
,cv2.CCL_BOLELLI
,cv2.CCL_SAUF
,cv2.CCL_BBDT
,cv2.CCL_SPAGHETTI
img = 255 - mt.cv_rgb_imread('conc.png', gray=True)
retval, labels = cv2.connectedComponents(img)
PIS(labels)
img = 255 - mt.cv_rgb_imread('conc.png', gray=True)
retval, labels = cv2.connectedComponentsWithAlgorithm(img, 8, cv2.CV_32S, cv2.CCL_WU)
PIS(labels)