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

基于YOLOv8 Nano的鱼类胚胎游动起止帧精准检测方案问询

精准检测鱼类胚胎游动起止帧的需求与优化方案

背景与问题

已训练YOLOv8 Nano模型检测培养皿中单枚游动鱼类胚胎,模型mAP50=0.994性能优异。目标是开发软件,输入视频后提取胚胎游动阶段帧的指标(x/y坐标、游动距离、速度等),但当前硬编码算法因数据噪声(静止时bounding box中心随机偏移,噪声速度达10-20mm/s,而胚胎最小游动速度约10mm/s),无法精准检测游动结束帧,起止帧预测误差远超2-3帧的要求。

已尝试用简单指数平滑降噪:

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)

初始起止帧检测函数表现不佳:

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

优化方案

1. 替换平滑算法:滑动窗口中位数过滤噪声

指数平滑对突变数据适应性弱,滑动窗口中位数能有效过滤随机噪声,同时保留真实的速度突变(游动开始/结束):

from scipy.ndimage import median_filter

def sliding_window_median(data, window_size=5):
    """用滑动窗口中位数平滑速度数据,窗口大小根据帧率调整(如30fps选5-7帧)"""
    return median_filter(data, size=window_size)

2. 状态机式起止帧检测

用静止→启动→游动→停止的状态机逻辑,替代简单阈值判断,结合连续帧状态变化确保精度:

def find_swim_start_end(df, velocity_col):
    # 参数可根据实际数据微调
    start_threshold = 12  # 略高于噪声上限(10-20mm/s)
    stop_threshold = 8     # 略低于最小游动速度(10mm/s)
    start_consecutive = 3  # 连续3帧达标才判定启动
    stop_consecutive = 3   # 连续3帧达标才判定停止
    
    state = "idle"
    start_count = 0
    stop_count = 0
    start_row = -1
    end_row = -1
    
    for idx, row in df.iterrows():
        vel = row[velocity_col]
        
        if state == "idle":
            if vel >= start_threshold:
                start_count += 1
                if start_count >= start_consecutive:
                    start_row = idx - start_consecutive + 1  # 取首次触发的帧
                    state = "swimming"
                    start_count = 0
            else:
                start_count = 0
        
        elif state == "swimming":
            if vel < stop_threshold:
                stop_count += 1
                if stop_count >= stop_consecutive:
                    end_row = idx - stop_consecutive  # 取首次回落的帧
                    state = "stopped"
                    break
            else:
                stop_count = 0
    
    # 处理视频结束时胚胎仍在游动的情况
    if state == "swimming" and end_row == -1:
        end_row = len(df) - 1
    
    return start_row, end_row

3. 结合坐标轨迹的二阶导数(加速度)辅助判断

除速度外,利用坐标的二阶导数(加速度)检测游动的起始/结束:

  • 游动启动时,加速度会出现明显峰值(静止→运动的突变)
  • 游动停止时,加速度回落至噪声水平

先对x/y坐标做平滑,再计算加速度,结合速度阈值交叉验证,进一步提升准确率。

4. 自适应阈值调整

根据视频前N帧(胚胎静止阶段)的噪声分布,动态计算阈值,适配不同视频的噪声差异:

def get_adaptive_thresholds(df, velocity_col, idle_frames=50):
    """从视频前N帧(静止期)计算自适应阈值"""
    idle_velocities = df[velocity_col][:idle_frames].values
    noise_mean = idle_velocities.mean()
    noise_std = idle_velocities.std()
    
    # 启动阈值:噪声均值+3倍标准差(覆盖99.7%的噪声,避免误判)
    start_threshold = noise_mean + 3 * noise_std
    # 停止阈值:噪声均值+1倍标准差(及时检测真实停止)
    stop_threshold = noise_mean + 1 * noise_std
    
    return start_threshold, stop_threshold

内容的提问来源于stack exchange,提问作者Laconad

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 13:22:34