设计基于距离/速度/加速度的运动开始/停止检测器

问题描述 投票:0回答:1

我训练了 yolov8 nano 来检测培养皿中游泳的鱼胚胎。在任何给定时间,培养皿中只有 1 个胚胎,因此这是一项相当简单的任务,并且模型表现良好 (mAP50=0.994)。我项目的最终目标是拥有一款以视频作为输入的软件,并让它仅针对视频中的帧输出指标(每帧的 x,y 坐标、游泳距离、游泳速度等)胚胎游泳的地方。例如,视频可能有 200 帧,大约第 40 帧胚胎尚未游动,然后 140 帧游动,然后 20 帧不游动(鱼已停止)。因此,对于这个视频,我希望有一个函数,可以从包含视频中所有帧信息的 csv 文件中仅提取 140 个相关帧。

使用硬编码算法来做到这一点的主要问题是数据有噪声,使得胚胎游泳模式的结束难以检测。例如,每帧的最小速度(假定胚胎可以游动最小 1 个像素)通常约为 10 毫米/秒。然而,即使鱼静止不动,模型预测的随机变化也会使边界框的中心移动几个像素,因此噪声约为 10-20mm/s。因此,我对速度列应用了简单的指数平滑来尝试减少噪音:

def simple_exponential_smoothing(data, alpha):
    """
    Apply simple exponential smoothing to the data.

    Parameters:
    data (array-like): The input time series data.
    alpha (float): The smoothing factor (0 < alpha <= 1).

    Returns:
    np.ndarray: The smoothed time series data.
    """
    result = [data[0]]  # First value is same as series
    for n in range(1, len(data)):
        result.append(alpha * data[n] + (1 - alpha) * result[n-1])
    return np.array(result)

我最初的方法是使用 csv 文件(包含一个视频的预测,每一帧一个),并在其上运行“检测器”函数。我尝试使用以下函数来提取开始帧和结束帧,以便我可以将数据修剪为仅相关帧以进行进一步计算:

def find_start_end_rows(df, velocity_column, filtered_velocity_column, frame_rate):
        """
        Find the start and end row indices based on a more refined approach.

        Parameters:
        df (pd.DataFrame): The dataframe to analyze.
        velocity_column (str): The name of the velocity column to search.
        filtered_velocity_column (str): The name of the filtered velocity column.

        Returns:
        tuple: A tuple containing the start row index and the end row index.
        """
        start_row = None
        end_row = None
        velocity_threshold = 20  # Minimum velocity to start swim
        filtered_velocity_threshold = 10  # Minimum filtered velocity to consider movement
        consistent_low_velocity_frames = 5  # Number of consecutive low-velocity frames to detect the end

        # Find the start row
        for i in range(len(df)):
            if df.loc[i, velocity_column] >= velocity_threshold:
                start_row = i - 1
                break

        # If start_row is still None, it means no value >= 20 was found
        if start_row is None:
            return (-1,-1)  # -1 indicates the function failed

        # Find the end row by checking for consistent low velocities after the start row
        low_velocity_count = 0
        for i in range(start_row + 2, len(df)):
            if df.loc[i, filtered_velocity_column] < filtered_velocity_threshold:
                low_velocity_count += 1
                if low_velocity_count >= consistent_low_velocity_frames:
                    end_row = i - consistent_low_velocity_frames
                    break
            else:
                low_velocity_count = 0

        # If end_row is still None, it means no consistent low-velocity frames were found
        if end_row is None:
            end_row = len(df) - 1

        return start_row, end_row

然而,正如我们在下图中看到的,这个函数的表现并不是很好。该图演示了使用此函数的开始帧预测和结束帧预测中的错误(将函数的输出与这些视频中的真实开始/结束帧进行比较)。对于该项目至关重要的是,我们在预测开始/结束帧时看到的可变性最多为 2-3 帧。

显示 find_start_end_frames 错误的图

什么方法最适合检测视频中的开始/结束帧?如果能够通过算法解决这个问题,而不必为此任务训练整个其他机器学习模型,那就太好了,但我对人们认为可行的任何解决方案持开放态度。

python-3.x algorithm machine-learning yolov8 motion-detection
1个回答
0
投票

您可能只需要对位置数据应用更复杂的过滤,以抑制噪声并使真实运动脱颖而出。

噪声可能均匀地分布在各个频率上,但“帧间差异”操作是一种高通操作,会加剧高频噪声。 鱼游动的频率应该相当低,因此具有适当截止频率的良好低通滤波器应该可以很好地隔离它。

您可以做的另一件真正有帮助的事情是提高帧速率。 这会将噪声传播到更广泛的频率范围,从而减少与真实数据重叠的噪声,并且更容易滤除。

对您的位置数据进行 FFT 或频谱图,以查看当前频率分布是什么样的,这样您就知道要过滤掉什么,然后您可以使用这个这样的工具来设计 IIR 滤波器。

您应该对前向和后向数据应用诸如 2 度巴特沃斯低通之类的东西,这样就不会出现时移。

© www.soinside.com 2019 - 2024. All rights reserved.