基于OpenCV的Python图像处理:物体掉落检测代码求助
没问题,我来帮你搞定这个基于OpenCV的柠檬掉落检测功能!针对柠檬赛跑的场景,咱们可以通过跟踪柠檬位置与预设参考区域(勺子范围)的关系来精准判断掉落事件。下面是具体的实现思路和可运行代码:
核心思路
本质就是:先定义勺子的有效区域(柠檬应该待着的地方),然后实时检测柠檬的位置,如果柠檬的中心坐标超出这个区域,就判定为掉落。考虑到柠檬的颜色特征,用HSV颜色空间的颜色识别来定位柠檬是最直接高效的方案。
具体实现步骤
- 第一步:获取视频流(支持摄像头实时采集或本地视频文件)
- 第二步:手动框选勺子的参考区域(运行代码后,用鼠标拖拽框选勺子所在区域即可)
- 第三步:对每一帧图像进行预处理,提取柠檬的黄色区域
- 第四步:通过轮廓检测定位柠檬的中心坐标,判断是否在勺子区域内
- 第五步:一旦检测到柠檬超出区域,立即触发掉落提示
完整代码示例
import cv2 import numpy as np # 全局变量:存储勺子的参考区域坐标 spoon_region = None drawing = False ix, iy = -1, -1 # 鼠标回调函数:用于框选勺子区域 def select_region(event, x, y, flags, param): global ix, iy, drawing, spoon_region if event == cv2.EVENT_LBUTTONDOWN: drawing = True ix, iy = x, y elif event == cv2.EVENT_MOUSEMOVE: if drawing: img_copy = param.copy() cv2.rectangle(img_copy, (ix, iy), (x, y), (0, 255, 0), 2) cv2.imshow('Select Spoon Region', img_copy) elif event == cv2.EVENT_LBUTTONUP: drawing = False spoon_region = (min(ix, x), min(iy, y), abs(x - ix), abs(y - iy)) cv2.destroyWindow('Select Spoon Region') def main(): # 初始化视频捕获:0为摄像头,也可以换成视频文件路径比如'lemon_race.mp4' cap = cv2.VideoCapture(0) if not cap.isOpened(): print("无法打开视频流!") return # 读取第一帧用于框选勺子区域 ret, frame = cap.read() if not ret: print("无法读取视频帧!") return cv2.imshow('Select Spoon Region', frame) cv2.setMouseCallback('Select Spoon Region', select_region, frame) cv2.waitKey(0) if spoon_region is None: print("未选择勺子区域,程序退出!") return # 定义柠檬的HSV颜色范围(可根据实际场景调整) lower_yellow = np.array([20, 100, 100]) upper_yellow = np.array([30, 255, 255]) # 用于防抖的计数变量:连续n帧不在区域内才判定掉落 drop_count = 0 drop_threshold = 3 while cap.isOpened(): ret, frame = cap.read() if not ret: break # 转换到HSV颜色空间,提取黄色区域 hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) mask = cv2.inRange(hsv, lower_yellow, upper_yellow) # 形态学操作去除噪声 kernel = np.ones((5,5), np.uint8) mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel) mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel) # 查找轮廓,定位柠檬 contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) lemon_detected = False lemon_center = None for cnt in contours: area = cv2.contourArea(cnt) # 过滤小轮廓,避免误判噪声 if area > 500: lemon_detected = True # 计算柠檬的中心坐标 M = cv2.moments(cnt) cx = int(M['m10']/M['m00']) cy = int(M['m01']/M['m00']) lemon_center = (cx, cy) # 在帧上绘制柠檬的中心和轮廓 cv2.drawContours(frame, [cnt], -1, (0, 0, 255), 2) cv2.circle(frame, (cx, cy), 5, (255, 0, 0), -1) break # 绘制勺子的参考区域 sx, sy, sw, sh = spoon_region cv2.rectangle(frame, (sx, sy), (sx+sw, sy+sh), (0, 255, 0), 2) # 判断柠檬是否掉落 if lemon_detected: cx, cy = lemon_center # 检查柠檬中心是否在勺子区域内 if not (sx < cx < sx+sw and sy < cy < sy+sh): drop_count += 1 if drop_count >= drop_threshold: cv2.putText(frame, "LEMON DROPPED!", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2) else: drop_count = 0 else: # 如果连续多帧没检测到柠檬,也判定为掉落(可选逻辑) drop_count += 1 if drop_count >= drop_threshold*2: cv2.putText(frame, "LEMON DROPPED!", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2) cv2.imshow('Lemon Drop Detection', frame) # 按q键退出 if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows() if __name__ == "__main__": main()
优化建议
- 颜色范围调整:如果实际场景中黄色干扰多,可以用
cv2.createTrackbar创建滑块来实时调整HSV的上下限,找到最适合的参数。 - 背景减除:如果场景中有移动的背景(比如人的手),可以用
cv2.createBackgroundSubtractorMOG2来去除背景,只保留运动物体,提升检测稳定性。 - 轮廓跟踪:对于快速移动的柠檬,可以用
cv2.TrackerCSRT_create()这类跟踪器,比逐帧检测轮廓更流畅。 - 防抖机制:代码里已经加了简单的计数防抖,你可以根据实际帧率调整
drop_threshold的值,避免因偶尔的帧模糊导致误判。
内容的提问来源于stack exchange,提问作者Kartikey Arora




