from maix import image, app, time # 橘黄色乒乓球的颜色阈值配置(HSV色域) thresholds = [ [73, 93, 7, 27, 13, 33], [40, 65, 30, 60, 40, 70], [39, 59, 41, 61, 48, 68], ] # 新增:丢失目标的阈值配置(可根据实际帧率调整,建议5-10帧) LOST_FRAME_THRESHOLD = 10 # 连续x帧没识别到才判定为真正丢失 SEND_INTERVAL = 5 # 控制指令发送间隔(避免高频发送,单位:ms) def select_largest_blob(blobs): """ 筛选并选取最大的有效blob(替换原融合逻辑) 1. 筛除宽/高小于10px的小blob(过滤噪声) 2. 从剩余blob中选取面积最大的单个blob :param blobs: 识别到的所有blob列表 :return: 最大blob的矩形参数 (x, y, width, height) 和中心点 (cx, cy);未识别到则返回None, None """ if not blobs: return None, (-1,-1) # 步骤1:过滤掉宽/高小于10px的无效blob valid_blobs = [] for b in blobs: x, y, w, h = b[0], b[1], b[2], b[3] if w >= 10 and h >= 10: # 筛除边距(宽/高)小于10px的blob valid_blobs.append(b) # 过滤后无有效blob,返回None if not valid_blobs: return None, (-1,-1) # 步骤2:选取面积(w*h)最大的blob largest_blob = max(valid_blobs, key=lambda b: b[2] * b[3]) # 提取最大blob的矩形参数和中心点 x, y, w, h = largest_blob[0], largest_blob[1], largest_blob[2], largest_blob[3] cx = x + w // 2 cy = y + h // 2 return (x, y, w, h), (cx, cy) def calculate_deviation_ball(center, image_center): """ 优化:仅计算偏移量,不直接发送指令(将指令发送逻辑移到主循环统一处理) :return: (deviation_x, deviation_y) 或 None(无有效目标) """ center_x, center_y = center if center_x == -1 and center_y == -1 : return None # 无有效目标 # 计算x/y方向的偏移偏差(目标中心 - 图像中心) deviation_x = center_x - image_center[0] deviation_y = center_y - image_center[1] # 仅当偏移超过阈值时返回有效偏移,否则返回None(避免微小抖动) if abs(deviation_x) > 10 or abs(deviation_y) > 10 : return (deviation_x, deviation_y) else: return None def trace_ball_main(resources): detector = resources["detector"] cam = resources["cam"] disp = resources["disp"] serial_dev = resources["serial_dev"] img_width = resources["img_width"] img_height = resources["img_height"] image_center = resources["image_center"] # 新增:状态变量初始化 last_valid_deviation = None # 记录最后一次有效偏移量 lost_frames = 0 # 丢失帧数计数 last_send_time = 0 # 最后一次发送指令的时间(防高频) while not app.need_exit(): current_time = time.ticks_ms() img = cam.read().flip(image.FlipDir.Y) # 识别色块(像素阈值设为10,过滤小噪声) blobs = img.find_blobs(thresholds, pixels_threshold=10) # 筛选并选取最大的有效blob largest_rect, target_center = select_largest_blob(blobs) # 计算当前帧的偏移量 current_deviation = calculate_deviation_ball(target_center, image_center) # -------------------------- 核心优化逻辑 -------------------------- if current_deviation is not None: # 1. 识别到有效目标:重置丢失计数,更新最后一次有效偏移 lost_frames = 0 last_valid_deviation = current_deviation # 控制发送频率,避免串口堵塞 if current_time - last_send_time >= SEND_INTERVAL: dx, dy = current_deviation cmd = f"DX:{dx},DY:{dy};" serial_dev.write_str(cmd) print(f"识别到目标: {cmd}") last_send_time = current_time else: # 2. 未识别到目标:累计丢失帧数 lost_frames += 1 if lost_frames < LOST_FRAME_THRESHOLD and last_valid_deviation is not None: # 2.1 丢失帧数未达阈值:继续发送最后一次有效偏移 if current_time - last_send_time >= SEND_INTERVAL: dx, dy = last_valid_deviation cmd = f"DX:{dx},DY:{dy};" serial_dev.write_str(cmd) print(f"短暂丢失,沿用最后偏移: {cmd} (丢失帧数: {lost_frames})") last_send_time = current_time else: # 2.2 丢失帧数达阈值:发送9999,重置最后有效偏移 if current_time - last_send_time >= SEND_INTERVAL: cmd = f"DX:9999,DY:9999;" serial_dev.write_str(cmd) print(f"目标丢失超过阈值: {cmd} (丢失帧数: {lost_frames})") last_valid_deviation = None last_send_time = current_time # ----------------------------------------------------------------- # 绘制识别结果 if largest_rect: x, y, w, h = largest_rect img.draw_rect(x, y, w, h, image.COLOR_GREEN, 2) cx, cy = target_center img.draw_circle(cx, cy, 3, image.COLOR_RED, -1) disp.show(img) time.sleep_ms(1)