在图像分析场景中,常需检测自定义路径上最亮 / 最暗像素的交界点(如手绘直线、曲线边缘)。本文结合「鼠标交互绘制路径」+「路径像素遍历」+「亮暗交界检测」,实现指定路径的精准边缘定位,新手可直接复用完整流程。
核心代码实现
python
import cv2 as cv
import numpy as np
# 全局变量:存储路径坐标、图像等关键数据
x1, y1 = -1, -1 # 鼠标按下初始坐标
path_y = [] # 路径y坐标列表
path_x = [] # 路径x坐标列表
binary_bg = None # 背景二值化图
src = None # 原始图像
# 鼠标回调函数:绘制路径+提取路径像素坐标
def on_mouse_action(event, x, y, flags, param):
global x1, y1, path_y, path_x, binary_bg, src, outimage
if event == cv.EVENT_LBUTTONDOWN:
# 左键按下:记录初始坐标
x1, y1 = x, y
print(f"左键点击:({x1}, {y1})")
elif event == cv.EVENT_MOUSEMOVE and flags == cv.EVENT_FLAG_LBUTTON:
# 左键拖拽:实时绘制路径(可选,增强交互性)
cv.line(outimage, (x1, y1), (x, y), (255, 0, 0), 2)
x1, y1 = x, y
elif event == cv.EVENT_LBUTTONUP:
# 左键松开:绘制最终路径 + 提取路径像素坐标
print(f"鼠标松开:终点({x}, {y})")
cv.line(outimage, (x1, y1), (x, y), (255, 0, 0), 2)
cv.line(src, (x1, y1), (x, y), (255, 0, 0), 2)
# 1. 路径区域二值化(提取手绘路径像素)
out_gray = cv.cvtColor(outimage, cv.COLOR_BGR2GRAY)
ret, binary_path = cv.threshold(out_gray, 20, 255, cv.THRESH_BINARY)
# 2. 遍历图像,提取路径上的所有像素坐标
path_y.clear() # 清空历史坐标,避免累积
path_x.clear()
for i in range(src.shape[0]):
for j in range(src.shape[1]):
if binary_path[i, j] == 255: # 路径像素(白色)
path_y.append(i)
path_x.append(j)
print(f"提取到路径像素数量:{len(path_x)}")
# ===================== 主程序 =====================
if __name__ == "__main__":
# 1. 读取图像并初始化
src = cv.imread("./image/15.bmp")
if src is None:
print("图像读取失败,请检查路径!")
exit()
# 初始化路径画布(纯黑,用于绘制手绘路径)
outimage = np.zeros_like(src)
# 背景图像二值化(用于检测亮暗交界)
src_gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
ret, binary_bg = cv.threshold(src_gray, 20, 255, cv.THRESH_BINARY)
# 2. 创建窗口并绑定鼠标回调
cv.namedWindow('src', cv.WINDOW_NORMAL)
cv.resizeWindow('src', 600, 600)
cv.setMouseCallback('src', on_mouse_action)
# 3. 主循环:实时检测路径上的亮暗交界点
while True:
# 显示图像
cv.imshow('src', src)
cv.imshow('path_canvas', outimage)
# 检测路径上的亮暗交界点(路径像素数≥2才执行)
if len(path_x) >= 2:
for v in range(len(path_x)-1):
# 获取路径上相邻两个像素的坐标
y_curr, x_curr = path_y[v], path_x[v]
y_next, x_next = path_y[v+1], path_x[v+1]
# 计算像素值差值(255=白→黑交界,-255=黑→白交界)
pix_diff = binary_bg[y_curr, x_curr] - binary_bg[y_next, x_next]
# 检测到亮暗交界,用绿色实心圆标注
if pix_diff == 255:
cv.circle(src, (x_curr, y_curr), 5, (0, 255, 0), -1)
# 按q退出程序
if cv.waitKeyEx(1) == ord('q'):
break
cv.destroyAllWindows()
关键知识点解析
1. 核心流程拆解
表格
| 步骤 | 核心操作 | 作用说明 |
|---|---|---|
| 鼠标交互 | cv.setMouseCallback() |
捕获左键按下 / 拖拽 / 松开事件,绘制自定义路径 |
| 路径提取 | 二值化 + 像素遍历 | 将手绘路径转为白色像素,提取所有路径像素坐标 |
| 交界检测 | 相邻像素差值计算 | binary_bg[y,x] - binary_bg[y+1,x+1] == 255 判定白→黑交界 |
| 可视化标注 | cv.circle() |
绿色实心圆标注交界点,直观展示检测结果 |
2. 原代码核心修复与优化
- 全局变量管理 :规范定义全局变量,清空历史路径坐标(
path_y.clear()),避免多次绘制路径导致坐标累积; - 索引越界防护 :新增
len(path_x)>=2判断,避免路径像素不足时遍历报错; - 数据结构简化 :移除冗余的
None列表,直接用空列表存储路径坐标,提升效率; - 变量初始化 :
binarys改为np.zeros_like(src),适配图像维度,避免通道数错误; - 鼠标事件修正 :
flags == cv.EVENT_LBUTTONDOWN改为cv.EVENT_FLAG_LBUTTON(正确的左键按住标志位)。
3. 核心参数说明
- 二值化阈值 20:适配手绘路径的蓝色线条(值 > 20 判定为路径像素),可根据路径颜色调整;
- 交界判定值 255:二值化后像素值只有 0(黑)/255(白),差值 255 表示当前像素白、下一个像素黑;
- 实心圆标注 :
cv.circle(..., -1)填充圆形,交界点更醒目,便于视觉识别。
4. 适用场景
- 工业视觉:检测零件指定路径上的明暗边缘、缺陷位置;
- 图像分析:定位自定义线条上的亮度突变点(如光谱图、波形图边缘);
- 交互标注:手动绘制路径后,自动检测路径上的关键边缘点。
总结
- 指定路径亮暗交界检测的核心是「鼠标绘制路径→提取路径像素→相邻像素差值计算」;
- 需重点处理全局变量清空 和索引越界防护,避免多次交互导致的数据错误;
- 二值化阈值和交界判定值是核心参数,需根据图像亮度、路径颜色适配调整。