一、什么是连通域

连通域(Connected Components)是指图像中像素值相同且彼此连通的一组像素集合。

在工业视觉中,连通域分析通常用于将目标从背景中分离,并统计目标数量、面积、位置等关键信息。

典型处理流程

原图
 ↓
灰度化
 ↓
二值化
 ↓
Connected Components
 ↓
面积过滤
 ↓
目标分析

工业应用场景

  • OCR 字符分割
  • 胶滴检测
  • 异物检测
  • Connector Pin 数量统计

二、四邻域与八邻域

连通性的定义决定了像素如何被归为同一区域。

四邻域(4-Connectivity)

仅包含上下左右四个方向的连接。

  X
X O X
  X

八邻域(8-Connectivity)

包含上下左右及四个对角线方向的连接。

X X X
X O X
X X X

OpenCV 参数设置

# 4邻域连接
connectivity = 4

# 8邻域连接(工业视觉推荐)
connectivity = 8

建议:在大多数工业视觉场景中,推荐使用 connectivity=8 以避免目标被错误分割。


三、connectedComponents() 基础用法

函数原型

num_labels, labels = cv2.connectedComponents(
    image,
    connectivity=8
)

参数说明

参数说明
image8位单通道二值图像
connectivity连通性定义,4 或 8

返回值详解

  1. num_labels:连通域总数量(包含背景)。
    • 例如:背景 + 2个目标 = num_labels = 3
  2. labels:标签图(Label Map)。
    • 背景像素值为 0
    • 其他目标依次编号 1, 2, 3...
标签图示例:
0 0 0 0
0 1 1 0
0 2 2 0

四、案例:统计目标数量

import cv2

# 1. 读取图像
img = cv2.imread("binary.png", 0)

# 2. 二值化
_, binary = cv2.threshold(
    img,
    0,
    255,
    cv2.THRESH_BINARY + cv2.THRESH_OTSU
)

# 3. 连通域分析
num_labels, labels = cv2.connectedComponents(binary)

# 4. 输出结果(减去背景)
print("目标数量:", num_labels - 1)

五、connectedComponentsWithStats() 进阶用法

相比基础函数,该函数额外返回每个连通域的统计信息和质心坐标。

函数原型

num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(
    binary,
    connectivity=8
)

stats 统计矩阵

每一行对应一个连通域(索引0为背景),包含以下属性:

属性常量说明
LEFTcv2.CC_STAT_LEFT边界框左上角 X 坐标
TOPcv2.CC_STAT_TOP边界框左上角 Y 坐标
WIDTHcv2.CC_STAT_WIDTH边界框宽度
HEIGHTcv2.CC_STAT_HEIGHT边界框高度
AREAcv2.CC_STAT_AREA连通域像素面积

读取示例:

x = stats[i, cv2.CC_STAT_LEFT]
y = stats[i, cv2.CC_STAT_TOP]
w = stats[i, cv2.CC_STAT_WIDTH]
h = stats[i, cv2.CC_STAT_HEIGHT]
area = stats[i, cv2.CC_STAT_AREA]

centroids 质心矩阵

返回每个连通域的几何中心 (cx, cy)

cx, cy = centroids[i]

六、完整案例:目标检测与标注

import cv2

# 1. 预处理
img = cv2.imread("binary.png", 0)
_, binary = cv2.threshold(
    img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU
)

# 2. 连通域分析
num, labels, stats, centers = cv2.connectedComponentsWithStats(binary)

# 3. 创建彩色画布
color = cv2.cvtColor(binary, cv2.COLOR_GRAY2BGR)

# 4. 遍历并过滤目标
for i in range(1, num):  # 从1开始,跳过背景
    area = stats[i, cv2.CC_STAT_AREA]

    # 面积过滤:忽略小噪点
    if area < 200:
        continue

    # 获取边界框
    x = stats[i, cv2.CC_STAT_LEFT]
    y = stats[i, cv2.CC_STAT_TOP]
    w = stats[i, cv2.CC_STAT_WIDTH]
    h = stats[i, cv2.CC_STAT_HEIGHT]

    # 绘制矩形框
    cv2.rectangle(color, (x, y), (x + w, y + h), (0, 255, 0), 2)

    # 标注面积
    cv2.putText(
        color, str(area), (x, y - 5),
        cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2
    )

cv2.imshow("Result", color)
cv2.waitKey()

七、Blob 分析与过滤策略

连通域在机器视觉中常被称为 Blob(斑点)。常见的过滤维度包括:

  • 面积 (Area):去除噪点或过大背景块。
  • 宽高 (Width/Height):限制目标尺寸范围。
  • 长宽比 (Aspect Ratio):筛选特定形状目标。
  • 圆度 (Circularity):区分圆形与非圆形目标。

长宽比过滤示例:

ratio = w / h
if ratio < 0.5 or ratio > 2:
    continue  # 跳过不符合比例的目标

八、工业视觉实战案例

1. 缺件检测

通过统计有效连通域数量判断是否缺件:

if num_labels - 1 < 10:
    print("报警:存在缺件")

2. OCR 字符分割

提取字符区域并送入识别引擎:

roi = image[y:y+h, x:x+w]
# cv2.imshow("Char", roi)
# result = ocr_engine.recognize(roi)

3. Connector Pin 统计

pin_count = num_labels - 1
if pin_count != expected_count:
    trigger_alarm()

九、Connected Components vs findContours

特性连通域 (Connected Components)轮廓 (findContours)
统计数量★★★★★ (极快)★★★★ (较快)
面积过滤★★★★★ (内置)★★★★★ (需计算)
边界分析★★ (仅矩形框)★★★★★ (任意形状)
形状分析★★ (基础)★★★★★ (拟合/矩)
执行速度★★★★★★★★★

选型建议

  • 仅需计数、面积过滤、位置定位 → 优先使用 连通域
  • 需要形状拟合、轮廓点提取、复杂几何分析 → 使用 findContours

十、常见问题排查

Q1: 为什么检测到的目标数量异常多?

原因:图像噪声过多,导致微小噪点被识别为独立连通域。

解决方案:在连通域分析前增加形态学开运算:

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
binary = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel)

Q2: 为什么面积统计不正确?

  • 检查二值化阈值是否准确。
  • 检查目标是否发生粘连(可尝试形态学腐蚀或距离变换分水岭)。
  • 确认 connectivity 参数是否符合预期。

十一、总结

OpenCV 连通域分析是工业视觉中最基础且高效的工具,适用于目标计数、Blob 分析、字符分割等任务。

核心 API:

  • cv2.connectedComponents():轻量级计数。
  • cv2.connectedComponentsWithStats():带统计信息的完整分析。

最佳实践:

工业项目中通常采用 形态学预处理 + 连通域分析 + 几何/面积过滤 的组合策略,可快速、稳定地完成大量目标检测任务。

更多推荐