基于OpenCV实现仔猪跨线计数以配合体重测算的方案优化问询
仔猪进出区域计数准确率优化需求
背景说明
我需要统计进出指定区域的仔猪数量,项目中该区域下方设有称重设备可采集动物总重量:最终目标是获取单头仔猪体重,当区域内仔猪数为0时可得到秤台自重,后续可结合进入区域的仔猪总数量换算单头仔猪的平均体重。
体重相关的历史数据统计为后续规划功能,当前核心需求是解决仔猪计数环节的准确率问题。
测试场景说明
现有测试视频中,00:40到02:00为仔猪入场阶段,03:54之后仔猪开始频繁进出该区域,该状态持续至视频结束。
现有方案与问题
我已通过代码实现了入场阶段的仔猪计数:定义了极小的感兴趣区域(ROI),通过颜色阈值过滤仔猪目标,该方案在仔猪活跃度较低的入场阶段运行正常,但当仔猪开始频繁活动、反复进出区域时计数准确度大幅下降。
目前暂无进一步的优化思路,恳请各位提供可行的技术建议。
现有实现代码
import cv2 FULL_VIDEO_PATH = "完整视频的存储路径" MAX_COLOR = (225, 215, 219) MIN_COLOR = (158, 141, 148) def get_centroid(x, y, w, h): x1 = int(w / 2) y1 = int(h / 2) cx = x + x1 cy = y + y1 return cx, cy def filter_mask(frame): # 复制待过滤的感兴趣区域(ROI) ROI = (frame[80:310, 615:620]).copy() kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3)) # 在产生噪声的结构上绘制绿色矩形进行遮挡 thicker_line_filtered = cv2.rectangle(ROI, (400, 135), (0, 165), (20, 200, 20), -1) closing = cv2.morphologyEx(thicker_line_filtered, cv2.MORPH_CLOSE, kernel) opening = cv2.morphologyEx(closing, cv2.MORPH_OPEN, kernel) dilation = cv2.dilate(opening, kernel, iterations=2) # 根据颜色阈值过滤图像 segmented_line = cv2.inRange(dilation, MIN_COLOR, MAX_COLOR) # 调整分割结果尺寸仅用于展示 copy = cv2.resize(segmented_line, (200, 400)) cv2.imshow('ROI', copy) return segmented_line def count_pigs(): cap = cv2.VideoCapture(FULL_VIDEO_PATH) ret, frame = cap.read() total_pigs = 0 frames_not_seen = 0 last_center = 0 is_position_ok = False is_size_ok = False total_size = 0 already_counted = False while ret: # 计数窗口区间 count_window_interval = (615, 0, 620, 400) # 过滤帧得到前景掩码 fg_mask = filter_mask(frame) # 在帧上绘制计数触发线 frame_with_line = cv2.line(frame, count_window_interval[0:2], count_window_interval[2:4],(0,0,255), 1) contours, _ = cv2.findContours(fg_mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # 未检测到轮廓时增加计数 if len(contours) == 0: frames_not_seen += 1 # 若5帧内未检测到轮廓,重置上一个中心坐标为0,确保新目标出现时可正常计算位置差 if frames_not_seen > 5: last_center = 0 for c in contours: frames_not_seen = 0 # 获取轮廓外接矩形坐标 (x, y, w, h) = cv2.boundingRect(c) # 计算外接矩形的中心点 centroid = get_centroid(x, y, w, h) # 计算轮廓矩用于获取轮廓面积 moments = cv2.moments(c) # 获取轮廓面积 size = moments['m00'] # 累计当前仔猪的轮廓面积,直到完成计数 if not already_counted: total_size += size # 若当前中心与上一个目标中心的差值超过80,判定为新仔猪进入计数区,位置校验通过,重置计数状态避免噪声干扰 if abs(last_center - centroid[1]) > 80: is_position_ok = True already_counted = False # 通过面积阈值校验轮廓是否符合仔猪特征,阈值为实验测定值 if 1300 < total_size < 5500: is_size_ok = True # 所有校验条件满足时完成仔猪计数,重置所有状态位 if is_position_ok and is_size_ok and not already_counted: is_position_ok = False is_size_ok = False already_counted = True total_size = 0 total_pigs += 1 last_center = centroid[1] frame_with_line = cv2.putText(frame_with_line, f'仔猪数量: {total_pigs}', (100, 370) , cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0,0,0), 2) cv2.imshow('帧画面', frame_with_line) cv2.moveWindow('ROI', 1130, 0) cv2.moveWindow('帧画面', 0, 0) k = cv2.waitKey(15) & 0xff if k == 27: break elif k == 32: cv2.waitKey() & 0xff ret, frame = cap.read() cv2.destroyAllWindows() cap.release() if __name__ == '__main__': count_pigs()
内容的提问来源于stack exchange,提问作者Arthur Rodolfo
相关产品推荐
相关产品推荐

