技术文档机器人与设备调试视觉系统Openmvopenmv,帮我详细解释一下这个代码,每一行和每一个函数添加注释。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 import sensor # 导入传感器模块,用于摄像头初始化和图像采集 import time # 导入时间模块,用于延时和FPS计算 import math # 导入数学模块,用于数学计算 from machine import UART # 从machine模块导入UART,用于串口通信 # 初始化UART串口通信,UART(1)表示使用UART1,波特率115200 uart = UART(1, 115200) # 传感器初始化和配置 sensor.reset() # 重置并初始化摄像头传感器 sensor.set_pixformat(sensor.GRAYSCALE) # 设置像素格式为灰度 sensor.set_framesize(sensor.VGA) # 设置帧大小为VGA (640x480) sensor.set_windowing((140, 200)) # 设置窗口裁剪区域为宽140,高200 sensor.skip_frames(time=2000) # 跳过前2000毫秒的帧,让自动曝光和自动增益稳定 # 创建时钟对象,用于计算并跟踪FPS clock = time.clock() # Tracks FPS. # 图像中心坐标(基于窗口大小) CENTER_X = 140 / 2 CENTER_Y = 200 // 2 # 实际场景中,窗口对应的真实物理尺寸(单位:毫米) FRAME_WIDTH_MM = 175 FRAME_HIGHT_MM = 266 # 不同测距标定参数(示例) # DISTANCE_MM_1 = 1100 # FRAME_WIDTH_PIXEL_1 = 104 DISTANCE_MM_2 = 1400 # 第二组标定:相机到A4纸的距离(毫米) # FRAME_WIDTH_PIXEL_2 = 80 FRAME_HEIGHT_PIXEL_2 = 111 # 第二组标定:A4纸在图像中高度对应的像素值 # DISTANCE_MM_3 = 1800 # FRAME_WIDTH_PIXEL_3 = 64 def find_center_min_blob(blobs): """ 在候选blob列表中找到最靠近图像中心且面积最小的blob :param blobs: blob对象列表 :return: 最优的blob对象或None """ blob = None # 初始化结果为None min_area = 100000 # 设定一个较大的初始最小面积阈值 for b in blobs: # 过滤:只保留中心偏移总和小于50像素的blob if abs(b.cx() - CENTER_X) + abs(b.cy() - CENTER_Y) > 50: print("nonononoonon1") continue # 如果当前blob面积大于min_area,则跳过 if b.area() > min_area: continue # 更新最优blob和最小面积 blob = b min_area = b.area() return blob def find_center_max_blob(blobs): """ 在候选blob列表中找到最靠近图像中心且面积最大的blob :param blobs: blob对象列表 :return: 最优的blob对象或None """ blob = None # 初始化结果为None max_area = 0 # 初始化最大面积阈值为0 for b in blobs: # 过滤:只保留中心偏移总和小于50像素的blob if abs(b.cx() - CENTER_X) + abs(b.cy() - CENTER_Y) > 50: continue # 如果当前blob面积小于max_area,则跳过 if b.area() < max_area: continue # 更新最优blob和最大面积 blob = b max_area = b.area() return blob # 主循环,不断获取图像并处理 while True: clock.tick() # 更新FPS计时 img = sensor.snapshot() # 捕获一帧图像 # 寻找标定框(高亮区域):灰度值范围150-256 frames = img.find_blobs([(150, 256)]) # 在标定框中找到最中心且面积最小的blob frame_blob = find_center_min_blob(frames) if not frame_blob: print("NO FRAME") # 若未检测到标定框,跳过本帧 continue # 根据标定参数计算与A4纸的距离(毫米) distance = DISTANCE_MM_2 * FRAME_HEIGHT_PIXEL_2 / frame_blob.h() # 定义A4纸内部ROI区域,缩小边缘5像素以排除框线 frame_roi = ( frame_blob.x() + 5, frame_blob.y() + 5, frame_blob.w() - 10, frame_blob.h() - 10 ) # 检查ROI尺寸有效性 if frame_roi[2] <= 0 or frame_roi[3] <= 0: print("ROI ERROR") continue print(frame_roi) # 在ROI内寻找目标物(灰度0-80) objs = img.find_blobs([(0, 80)], roi=frame_roi) # 选取最中心且面积最小的目标blob obj_blob = find_center_min_blob(objs) if not obj_blob: print("NO OBJS") # 若未检测到目标物,跳过本帧 continue # 打印检测到的角点列表,用于后续三角形去重 print(obj_blob.corners()) corners = [] # 去除过近的重复角点 for i in range(len(obj_blob.corners())): flag = 0 for j in range(i + 1, len(obj_blob.corners())): # 计算两点距离,小于15像素认为重复 if math.sqrt((obj_blob.corners()[i][0] - obj_blob.corners()[j][0])**2 + (obj_blob.corners()[i][1] - obj_blob.corners()[j][1])**2) < 15: flag = 1 if flag == 0: corners.append(obj_blob.corners()[i]) print(corners) # 根据density(填充比)判断形状,并计算物体边长或直径(毫米) if 0.9 < obj_blob.density(): # 高填充比,近似正方形 print("正方形") # 另一种计算方法:周长映射 obj_w_mm = math.sqrt((obj_blob.pixels()) / frame_blob.h()**2 * FRAME_HIGHT_MM**2) elif 0.6 < obj_blob.density(): # 中等填充比,近似圆形 print("圆形") obj_w_mm = obj_blob.h() / frame_blob.h() * FRAME_HIGHT_MM elif 0.4 < obj_blob.density(): # 低填充比,可能三角形或正方形 if len(corners) == 4: # 四个角点,仍视为正方形 print("正方形") obj_w_mm = math.sqrt((obj_blob.pixels()) / frame_blob.h()**2 * FRAME_HIGHT_MM**2) else: # 三角形:基于像素面积映射,并考虑等边三角形公式 print("三角形") obj_w_mm = math.sqrt((obj_blob.pixels() + 5) / frame_blob.h()**2 * FRAME_HIGHT_MM**2 * 4 / math.sqrt(3)) else: # 填充比过低,无法识别形状 print("无法识别到形状") obj_w_mm = 0 # 在图像上绘制结果文字和检测框 img.draw_string(10, 10, "length:" + str(obj_w_mm) + "mm") # 显示物体尺寸 img.draw_string(10, 20, "distance:" + str(distance) + "mm") # 显示距离 # 通过UART串口输出结果到外部设备(单位:cm) uart.write(f"D:{distance/10}cm,X:{obj_w_mm/10}cm\r\n".encode()) # 绘制检测到的A4纸框和目标物的外接矩形 img.draw_rectangle(frame_blob.rect()) img.draw_rectangle(obj_blob.rect()) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 \documentclass{article} \usepackage{tikz} \usetikzlibrary{shapes.geometric, arrows.meta, positioning} \tikzset{ startstop/.style={rectangle, rounded corners, minimum width=3cm, minimum height=1cm,text centered, draw=black, fill=white}, process/.style={rectangle, minimum width=3cm, minimum height=1cm, text centered, draw=black, fill=white}, decision/.style={diamond, minimum width=3cm, minimum height=1cm, text centered, draw=black, fill=white}, arrow/.style={thick,->,>=stealth}, io/.style={trapezium, trapezium left angle=70, trapezium right angle=110, minimum width=3cm, minimum height=1cm, text centered, draw=black, fill=white} } \begin{document} \begin{tikzpicture}[node distance=2cm] \node (start) [startstop] {系统上电}; \node (init) [process, below of=start] {各模块初始化}; \node (rtc) [process, below of=init] {主控配置RTC唤醒}; \node (decide) [decision, below of=rtc, yshift=-1cm] {系统待机?}; \node (sleep) [process, right of=decide, xshift=3cm] {主控进入STOP模式}; \node (cam_sleep) [process, right of=sleep, xshift=3cm] {摄像头休眠}; \node (lcd_off) [process, right of=cam_sleep, xshift=3cm] {LCD关闭背光}; \node (ina_off) [process, right of=lcd_off, xshift=3cm] {INA226关断模式}; \node (wait) [io, right of=ina_off, xshift=3cm] {等待唤醒}; \node (measure) [process, below of=decide, yshift=-1cm] {执行测量任务}; \node (cam_work) [process, right of=measure, xshift=3cm] {摄像头工作:降帧率/分辨率}; \node (ina_sample) [process, right of=cam_work, xshift=3cm] {INA226间隔采样}; \node (data_process) [process, right of=ina_sample, xshift=3cm] {数据处理}; \node (lcd_show) [process, right of=data_process, xshift=3cm] {LCD显示数据}; \node (lcd_dim) [io, right of=lcd_show, xshift=3cm] {降低LCD亮度}; \draw [arrow] (start) -- (init); \draw [arrow] (init) -- (rtc); \draw [arrow] (rtc) -- (decide); \draw [arrow] (decide) -- node[anchor=south] {是} (sleep); \draw [arrow] (sleep) -- (cam_sleep); \draw [arrow] (cam_sleep) -- (lcd_off); \draw [arrow] (lcd_off) -- (ina_off); \draw [arrow] (ina_off) -- (wait); \draw [arrow] (wait) |- node[anchor=north] {RTC定时/按键} (decide); \draw [arrow] (decide) -- node[anchor=east] {否} (measure); \draw [arrow] (measure) -- (cam_work); \draw [arrow] (cam_work) -- (ina_sample); \draw [arrow] (ina_sample) -- (data_process); \draw [arrow] (data_process) -- (lcd_show); \draw [arrow] (lcd_show) -- (lcd_dim); \draw [arrow] (lcd_dim) |- (decide); \end{tikzpicture} \end{document}OpenclawRc Vision