Python OpenCV connectedComponents实现用户点选帧间连通域特征
跨帧连通域交互追踪实现方案
已完成基础能力
当前已实现前一帧(记为图像1)随机连通域的选取、掩码生成与展示功能,对应代码如下:
segall_prev = cv2.imread(str(Path(seg_seg_output_path, prev_filename)), 0); segall_prev = np.uint8(segall_prev) ret, thresh = cv2.threshold(segall_prev, 127, 255, 0) numLabels, labelImage, stats, centroids = cv2.connectedComponentsWithStats(thresh, 8) # 选取前一帧分割结果的随机连通域 random_prev_seg = random.randint(0, np.amax(labelImage)) i = np.unique(labelImage)[random_prev_seg] pixels = np.argwhere(labelImage == random_prev_seg) labelMask = np.zeros(thresh.shape, dtype="uint8") labelMask[labelImage == i] = 1 numPixels = cv2.countNonZero(labelMask) # 仅展示前一帧选中的连通域 fig_segall_prev = plt.figure() fig_segall_prev_ = plt.imshow(labelMask) plt.title(prev_filename + ' prev_seg')
运行上述代码可以输出图像1中随机选中的单个连通域掩码。
需求与原有代码问题
核心需求
确定前一帧目标特征后,支持用户在当前帧(记为图像2)点击选中目标对应的连通域,实现跨帧目标追踪;后续需要支持选中连通域单独存图、位置映射到对应彩色图像使用。
原有交互逻辑缺陷
初始编写的图像2交互代码存在以下问题:
- 无法正确识别点击位置对应的连通域:坐标与连通域标签矩阵的索引对应关系错误,且仅固定判断标签为1的连通域,无法适配任意点击位置
- 未实现选中连通域的结构化存储,不支持后续存图、映射彩色图的扩展需求
初始交互代码如下:
# 显示分割图像并绑定点击事件 seg_ret, seg_thresh = cv2.threshold(segall, 127, 255, 0) seg_numLabels, seg_labelImage, seg_stats, seg_centroids = cv2.connectedComponentsWithStats(seg_thresh, 8) mutable_object = {} def onclick(event): # 捕获点击像素位置 X_coordinate = int(event.xdata) Y_coordinate = int(event.ydata) mutable_object['click'] = X_coordinate print('x= ' + str(X_coordinate)) print('y= ' + str(Y_coordinate)) # 对比点击位置与特征位置 x = np.where(seg_labelImage == 1) #print(x[0]) if X_coordinate in x[0] and Y_coordinate in x[1]: print('yes') fig_segall = plt.figure() cid = fig_segall.canvas.mpl_connect('button_press_event', onclick) fig_segall_ = plt.imshow(seg_labelImage) plt.title(filename + ' seg')
调试通过的实现方案
核心修正逻辑:
- matplotlib返回的
event.xdata为图像列坐标(水平方向)、event.ydata为图像行坐标(垂直方向),直接通过标签矩阵的行列索引即可拿到点击位置的连通域标签:标签值为0代表背景,大于0为有效连通域 - 直接通过标签值快速生成选中连通域的掩码,无需遍历全图像素判断
- 用字典结构化存储选中的连通域特征,方便后续扩展
可直接运行的代码如下:
seg_numLabels, seg_labelImage, seg_stats, seg_centroids = cv2.connectedComponentsWithStats(seg_thresh, 8) selected_features = {} def onclick(event): # 捕获点击像素坐标 X_coordinate = int(event.xdata) Y_coordinate = int(event.ydata) print(f'{X_coordinate=}, {Y_coordinate=}') obj_at_click = seg_labelImage[Y_coordinate, X_coordinate] # 读取点击位置的连通域标签,0为背景,其余值为对应连通域编号 if obj_at_click != 0: # 点击位置不是背景 # 提取选中连通域 selected_feature = (seg_labelImage == obj_at_click) selected_features[filename] = selected_feature print(f'Saved feature number {obj_at_click}') else: print('Background clicked') # 显示分割图像并绑定点击事件 fig_segall = plt.figure() fig_segall.canvas.mpl_connect('button_press_event', onclick) plt.imshow(segall) plt.title(filename + ' seg')
后续扩展参考
- 单独保存选中连通域掩码:获取到
obj_at_click后,生成可存储的二值掩码selected_mask = (seg_labelImage == obj_at_click).astype(np.uint8)*255,调用cv2.imwrite即可保存为本地图像 - 映射到彩色原图:将生成的
selected_mask作为遮罩,调用cv2.bitwise_and和原始彩色图像做运算,即可提取彩色原图上的对应目标区域 - 点击后实时高亮:可在
onclick函数内添加绘图刷新逻辑,将选中的连通域掩码以半透明效果叠加显示在原图上,提升交互体验
内容的提问来源于stack exchange,提问作者Connor
相关产品推荐
相关产品推荐

