如何优化Python中扑翼机器人的Blob检测并补全轨迹数据缺口?
扑翼机器人圆形标记轨迹补全方案
问题背景
我有一台扑翼机器人,机翼上绘制了若干圆形标记用于追踪。机翼运动时,部分帧中的圆形标记会出现模糊或呈椭圆形的情况。我的目标是生成一个字典,键为圆形标记的唯一ID,值为各帧对应的(x,y)坐标列表,格式如下:
result = { 1: [(x11,y11),(x12,y12),...,(x1n,y1n)], 2: [(x21,y21),(x22,y22),...,(x2n,y2n)], ..., k: [(xk1,yk1),(xk2,yk2),...,(xkn,ykn)] }
目前使用cv2.SimpleBlobDetector_create进行检测,该方法能在每帧中识别出部分圆形标记,并通过计算与前一帧所有圆形标记的欧氏距离进行匹配。但由于并非所有圆形标记在每帧中都能被检测到,导致轨迹数据存在缺口,需要补全这些数据缺口。
当前实现代码:
def blob_trajectory(camera_dirname: str, crop_params_filename='crop_params.pkl', first_image_name='Img000001.jpg', photos_sub_dirname='photos', cropped_dirname='cropped', **kwargs): params = cv2.SimpleBlobDetector_Params() params.minThreshold = kwargs["min_thres"] params.maxThreshold = kwargs["max_thres"] params.filterByCircularity = 1 params.minCircularity = kwargs["min_circ"] params.maxCircularity = kwargs["max_circ"] params.filterByConvexity = 1 params.minInertiaRatio = kwargs["min_conv"] params.maxInertiaRatio = kwargs["max_conv"] params.filterByArea = 1 params.minArea = kwargs["min_area"] # number of pixels params.maxArea = kwargs["max_area"] detector = cv2.SimpleBlobDetector_create(params) images_path = os.path.join(camera_dirname, photos_sub_dirname) cropped_path = os.path.join(camera_dirname, cropped_dirname) frame0 = cv2.imread(os.path.join(cropped_path, 'frame_0000.png'), cv2.COLOR_BGR2GRAY) prev_blobs = detector.detect(frame0) blob_trajectories = {} for image_name in os.listdir(images_path)[1:]: frame = cv2.imread(os.path.join(cropped_path, image_name), cv2.COLOR_BGR2GRAY) curr_blobs = detector.detect(frame) for i, kp in enumerate(prev_blobs): kp.class_id = i distances = np.zeros((len(prev_blobs), len(curr_blobs))) for i, kp1 in enumerate(prev_blobs): for j, kp2 in enumerate(curr_blobs): distances[i, j] = np.linalg.norm(np.array(kp1.pt) - np.array(kp2.pt)) row_ind, col_ind = scipy.optimize.linear_sum_assignment(distances) for i, j in zip(row_ind, col_ind): if distances[i, j] < 10: curr_blobs[i].class_id = prev_blobs[j].class_id for kp in prev_blobs: blob_id = kp.class_id if blob_id not in blob_trajectories: blob_trajectories[blob_id] = [] blob_trajectories[blob_id].append(kp.pt) im_with_blobs = cv2.drawKeypoints(frame, curr_blobs, np.array([]), (255, 0, 0), cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) plt.imshow(im_with_blobs) plt.show() prev_blobs = curr_blobs return blob_trajectories
轨迹缺口补全方案
1. 统一轨迹帧长度
首先确定视频总帧数,给每个标记的轨迹初始化一个长度为总帧数的列表,缺失位置先用None或特定占位符填充,确保所有轨迹的帧序列与实际视频帧一一对应。
2. 基于运动模型的补全方法
扑翼机器人的机翼运动具有周期性规律,针对不同缺失场景选择适配的补全方式:
- 线性插值:适用于短帧缺失(1-2帧),如果标记在帧t-1和t+1有有效坐标,直接通过两点线性计算帧t的(x,y)值。
- 多项式拟合:对连续多帧的有效坐标进行2次或3次多项式拟合,用拟合曲线预测缺失帧的坐标,适合中等长度的缺失。
- 周期函数建模:提取机翼运动周期,用正弦/余弦函数拟合标记的轨迹曲线,利用周期重复性补全长时间缺失的帧,这是最适配扑翼运动的方法。
3. 优化检测逻辑减少缺口
从源头降低缺口产生的概率:
- 调整Blob检测参数:降低
minCircularity和minInertiaRatio的阈值,允许一定椭圆度的标记通过检测;扩大阈值范围,覆盖不同模糊程度的标记。 - 帧预处理:对模糊帧做高斯降噪或边缘增强,提升标记的对比度和清晰度,帮助检测器识别。
4. 改进匹配逻辑避免ID混乱
当前匹配仅依赖前一帧,容易出现标记消失重现后分配新ID的问题:
- 维护所有历史轨迹:检测到新Blob时,不仅与前一帧Blob匹配,还要和所有已存在轨迹的最后已知坐标计算距离,关联到最匹配的ID。
- 设置消失容忍机制:如果某个标记连续N帧未被检测到,暂时保留其ID,后续帧中若出现符合预测位置的Blob,重新关联该ID。
5. 补全代码示例(核心实现)
以下是基于线性插值的补全函数,可集成到现有代码中:
import numpy as np from scipy.interpolate import interp1d def fill_trajectory_gaps(trajectories, total_frames): filled_trajectories = {} for blob_id, coords in trajectories.items(): # 整理已记录的帧索引和对应坐标 frame_indices = [] x_coords = [] y_coords = [] # 注意:需根据实际帧序号对应关系调整,此处假设原代码从第0帧开始记录 for idx, (x, y) in enumerate(coords): frame_indices.append(idx) x_coords.append(x) y_coords.append(y) # 创建线性插值函数,支持外推(处理首尾帧缺失的情况) x_interp = interp1d(frame_indices, x_coords, kind='linear', fill_value="extrapolate") y_interp = interp1d(frame_indices, y_coords, kind='linear', fill_value="extrapolate") # 生成所有帧的完整坐标 filled_coords = [] for frame_idx in range(total_frames): x = float(x_interp(frame_idx)) y = float(y_interp(frame_idx)) filled_coords.append((x, y)) filled_trajectories[blob_id] = filled_coords return filled_trajectories
验证建议
补全后可可视化轨迹,检查补全点是否符合机翼运动的周期性规律,若出现异常点,可调整拟合模型的参数或增加运动约束。
内容的提问来源于stack exchange,提问作者Hadar
相关产品推荐
相关产品推荐

