You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优化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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 11:49:57