机器人巡线
1.实验目的
基于 CanMV 开发平台,构建一个使用摄像头识别“黑色轨迹线”的基础图像识别系统。通过灰度图像分割、图像区域加权、多 ROI 追踪策略,我们可以实时计算图像中黑线的位置,并输出角度信息,便于用于智能小车路径控制等应用。
2.实验原理
3.代码解析
定义感兴趣区域
ROIS = [
(0, 200, 320, 40, 0.7), # 这部分是图像中的区域(ROI)
(0, 100, 320, 40, 0.3),
(0, 0, 320, 40, 0.1)
]
ROIS
:定义了三个感兴趣区域(ROI)。每个区域由五个元素表示 (x, y, w, h, weight)
,分别为:
(x, y)
:ROI 区域的左上角坐标。(w, h)
:ROI 区域的宽度和高度。weight
:每个区域的权重值,越靠近底部的区域给的权重越大,这意味着底部的图像对最终计算影响更大。
摄像头初始化
sensor = Sensor(width=1280, height=960)
sensor.set_framesize(width=DETECT_WIDTH, height=DETECT_HEIGHT)
sensor.set_pixformat(Sensor.GRAYSCALE) # 设置为灰度图模式
sensor = Sensor(width=1280, height=960)
:创建一个摄像头对象,并设置其分辨率为 1280x960 像素。
sensor.reset()
:初始化摄像头。
sensor.set_framesize(width=DETECT_WIDTH, height=DETECT_HEIGHT)
:设置摄像头输出的图像分辨率为 320x240。
sensor.set_pixformat(Sensor.GRAYSCALE)
:设置图像的像素格式为灰度图。
初始化显示屏
Display.init(Display.ST7701, to_ide=True) # 初始化 LCD 显示屏,并设置为 800x480
Display.init(Display.ST7701, to_ide=True)
:初始化显示屏,并将其设置为 ST7701
类型显示屏,分辨率为 800x480。
初始化媒体资源管理器
MediaManager.init() # 初始化媒体管理器,管理资源
sensor.run() # 启动摄像头,开始采集图像
MediaManager.init()
:初始化媒体资源管理器,准备好管理图像等资源。
sensor.run()
:启动摄像头采集图像,开始实时捕获。
检测连同区域
for r in ROIS:
blobs = img.find_blobs(GRAYSCALE_THRESHOLD, roi=r[0:4], merge=True) # r[0:4] 是上面定义的roi元组.
for r in ROIS:
:遍历所有 ROI 区域。
blobs = img.find_blobs(GRAYSCALE_THRESHOLD, roi=r[0:4], merge=True)
:在每个 ROI 区域内,检测符合灰度阈值的 blob(连通区域)。如果找到了符合条件的区域,它们会被存储在 blobs
列表中。
if blobs:
largest_blob = max(blobs, key=lambda b: b.pixels()) # 找到面积最大的 blob
img.draw_rectangle(largest_blob.rect()) # 在图像上绘制矩形框
img.draw_cross(largest_blob.cx(), largest_blob.cy()) # 在图像上绘制十字线(中心点)
centroid_sum += largest_blob.cx() * r[4] # 累加加权中心位置
if blobs:
:如果找到了符合条件的 blob。
largest_blob = max(blobs, key=lambda b: b.pixels())
:找到最大面积的 blob。
img.draw_rectangle(largest_blob.rect())
:绘制出最大 blob 的矩形框。
img.draw_cross(largest_blob.cx(), largest_blob.cy())
:绘制出最大 blob 的中心点。
centroid_sum += largest_blob.cx() \* r[4]
:将最大的 blob 的 X 坐标乘以该 ROI 区域的权重并累加,用于后续计算。
计算线条中心位置
center_pos = (centroid_sum / weight_sum) # 计算加权中心位置
计算所有 ROI 区域加权后的线条中心位置。
计算线条的偏转角度
deflection_angle = -math.atan((center_pos - 160) / 120)
deflection_angle = -math.atan((center_pos - 160) / 120)
:计算线条中心的偏离角度。通过反正切函数计算偏差,并通过 (center_pos - 160)
计算与中心位置的偏离。
160
是图像的中点。120
是半个图像高度,用于计算角度。
弧度转度数
deflection_angle = math.degrees(deflection_angle) # 转换成角度
将偏转角度从弧度转换为度数。