这个题目来自2023年全国大学生电子设计竞赛E题,涉及机器视觉与嵌入式系统的协同工作。作为参加过三届电赛的老队员,我理解这类题目对新手最大的挑战在于:如何准确理解题意要求,并将抽象描述转化为可执行的技术方案。
激光原点定位和黑色胶带识别是本题视觉部分的两大核心任务。根据我的实战经验,竞赛题目中的每个字词都经过精心设计,我们需要像解数学题一样"咬文嚼字":
激光原点定义:题目描述为"激光第一次打在屏幕上的点",这意味着需要捕捉激光从无到有的瞬间状态。在实际操作中,这与持续跟踪激光光斑是两种不同的技术路线。
胶带识别要求:题目明确提到"识别内外八个顶点",这直接决定了后续坐标传输的数据结构。如果只需识别单边,题目会表述为"识别一侧边框"。
树莓派+OV5647摄像头的组合是性价比之选。实测中需注意:
关键参数建议:分辨率设为1280×720,帧率不低于30fps,曝光模式手动调节
采用背景差分法是最可靠的方案,具体步骤:
python复制import cv2
import numpy as np
# 初始化背景模型
background = None
while True:
ret, frame = cap.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
if background is None:
background = gray.copy()
continue
# 计算差异
diff = cv2.absdiff(background, gray)
_, threshold = cv2.threshold(diff, 30, 255, cv2.THRESH_BINARY)
# 检测激光点
contours, _ = cv2.findContours(threshold, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for cnt in contours:
if cv2.contourArea(cnt) > 10: # 面积阈值过滤噪声
(x, y), radius = cv2.minEnclosingCircle(cnt)
if radius < 15: # 半径阈值确认激光点
return (int(x), int(y)) # 返回原点坐标
环境光干扰处理:建议在暗室环境操作,或在镜头前加装650nm窄带滤光片
采样策略优化:连续检测到3帧稳定光斑才判定为有效原点,避免误触发
坐标校准技巧:在屏幕四角粘贴标记物,建立像素坐标到实际坐标的转换矩阵
题目要求"识别内外八个顶点"意味着需要完整重建胶带边框的几何形状。只识别单边会导致:
推荐采用多边形逼近法:
python复制# 预处理
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (5,5), 0)
_, thresh = cv2.threshold(blur, 60, 255, cv2.THRESH_BINARY_INV)
# 轮廓检测
contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
for cnt in contours:
epsilon = 0.02 * cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, epsilon, True)
if len(approx) == 8: # 确认是八边形
points = sorted([tuple(p[0]) for p in approx], key=lambda x: (x[1], x[0]))
# 按特定顺序排列顶点
inner = points[:4] # 内框四个顶点
outer = points[4:] # 外框四个顶点
break
STM32通信建议采用以下JSON格式:
json复制{
"origin": {"x": 120, "y": 80},
"inner": [
{"x": 100, "y": 100},
{"x": 200, "y": 100},
{"x": 200, "y": 200},
{"x": 100, "y": 200}
],
"outer": [
{"x": 90, "y": 90},
{"x": 210, "y": 90},
{"x": 210, "y": 210},
{"x": 90, "y": 210}
]
}
通信优化建议:使用UART协议时,波特率建议设为115200,每个数据包添加CRC校验
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 无法检测到光斑 | 阈值设置过高 | 逐步降低threshold值 |
| 误检多个点 | 环境反光 | 加装偏振片 |
| 坐标抖动严重 | 摄像头震动 | 加固机械结构 |
顶点数量不对:
顶点顺序混乱:
通信丢包:
经过三天三夜的调试,我总结出几个提升精度的秘诀:
动态阈值法:根据环境光强度自动调整二值化阈值
python复制avg_brightness = np.mean(gray)
threshold = avg_brightness * 0.7 # 经验系数
亚像素级定位:将检测到的坐标精度提升到0.1像素级
python复制criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.01)
cv2.cornerSubPix(gray, np.float32(points), (5,5), (-1,-1), criteria)
运动预测算法:基于历史坐标预测下一帧位置,减少搜索范围
这套方案在实测中可以达到:
最后提醒:竞赛中一定要预留2小时进行整体联调,视觉与控制系统的时钟同步问题往往是最后一刻的"杀手"。建议在STM32端实现数据缓存机制,避免因临时遮挡导致系统失控。