☰
MATLAB小鼠步态分析全流程:采集、追踪、参数计算与质控
2026/10/28 14:49:08 网站建设 项目流程

1. 先把链路想清楚:小鼠步态分析的方案拆解与选型

小鼠步态分析这件事,表面上就是“拍个视频、量几个距离”,但真正跑过完整项目的人都知道,从一只小鼠在跑道上走一趟,到最终能进统计模型的一张参数表,中间隔着采集、标定、提取、清洗、计算、质控六道关口。任何一道关口出问题,后面算出来的步长、支撑相占比、对称性指数都会变成看起来很像样、实际上没法用的数字。这篇内容我想把整套基于 MATLAB 的小鼠步态分析流程从头到尾拆一遍,讲清楚每个参数为什么这么取、每个算法为什么这么写、哪些地方最容易翻车。

适合读这篇的人大概分三类:刚接手动物行为学实验、需要自己搭一套分析管线的研究生;手里已经有一堆视频、但被追踪抖动和参数异常折磨过的实验人员;以及想用 MATLAB 把零散脚本整理成可复现工具链的工程岗。基础要求不高,会写最基础的 MATLAB 脚本、知道imread和plot怎么用就够,剩下的细节我在文中都会补。

1.1 从行为视频到数字指标,中间到底隔了几层

我习惯把这套流程拆成三层来看。最底层是像素层:原始视频、标定图像、背景帧,这一层要解决的是“画面能不能稳定地区分出动物身体和跑道”。中间层是几何层:关键点坐标、爪印轮廓、质心轨迹,单位是像素,这一层要解决的是“每一帧里每只脚在哪”。最上层是物理层:毫米、毫秒、百分比,步长、步宽、支撑相时长、占空比、对称性指数都在这一层。

很多人做不下去,问题往往出在跨层的时候没有做严格换算。比如提取层用的是像素坐标,但跑道存在透视变形,画面边缘的像素当量和中心差了百分之十几,直接把中心标定的比例套到全图,算出来的步宽系统性地偏大或者偏小。再比如时间维度上,视频帧率是 100 fps,每一帧代表 10 ms,支撑相只有 120 ms 的情况下,量化误差就有 ±8% 左右,这个误差在组间比较时完全可能盖过真实的生物学差异。

所以我在动手写代码之前,会先在纸上把三件事定死:像素当量是多少毫米每像素、时间分辨率是多少毫秒每帧、判定着地的判据是什么。这三个量定了,后面的代码才有意义;定不下来,写多少行都是白搭。

1.2 三条技术路线的取舍:墨迹足印、侧视标记点、俯视无标记

市面上能走的路基本就三条,各有各的适用场景,我在不同项目里都用过。

墨迹足印法是最老也最稳的一条。让小鼠爪底沾上无毒颜料或者墨水,走过一条铺了吸水纸的跑道,纸上留下连续的爪印,扫描或者拍照之后用 MATLAB 做二值化、连通域分析,直接量爪印面积、步长、步宽、同源指数。它的优势是精度高、成本低、不依赖高速相机,一只动物几分钟就能出结果;劣势也很明显——只能拿到静态的空间参数,拿不到时间参数,支撑相时长、摆动速度这些全都测不了,而且涂抹均匀度、纸张吸水性、动物愿不愿意走,都会影响数据质量。

侧视加标记点是另一条经典路线,在髋、膝、踝、足尖贴反光标记点,用高速相机侧向拍摄,靠标记点提取关节轨迹,能算关节角度、摆动相轨迹、协调性。代价是标记点容易掉、贴点位置有主观性、动物适应期长,而且侧视只能看到一侧肢体,左右对比需要翻转或者双侧同步拍摄。

俯视无标记是这几年最主流的选择,从正下方透过透明跑道拍摄,用开源姿态估计框架或者传统图像处理直接提取四只爪的位置,时空参数一把抓。它的门槛在软件侧:模型泛化、遮挡处理、抖动清洗都要自己扛。我目前的默认方案就是这一条,配合 MATLAB 做后处理和参数计算,因为它能一次性拿到完整的时空参数集,对神经损伤模型、疼痛模型、运动功能评分的区分度都更好。

选型上没有绝对的对错,看你的科学问题。只关心空间步态特征、样本量大、预算紧,墨迹法性价比最高;关心关节运动学,侧视标记点绕不开;关心支撑相占比、步态节律、左右协调,那就得走俯视视频这条路。

1.3 为什么把计算层放在 MATLAB 里

提取层用什么工具都行,但计算层我坚持放在 MATLAB,理由有三个,都是实际踩出来的。

第一是矩阵化处理天然适配轨迹数据。一批动物、每个动物多个 trial、每个 trial 几万帧、每帧几个关键点,这种数据结构本质上就是三维数组,MATLAB 里一次索引就能切片,算速度、做滤波、求峰值都是向量化操作,比在别的语言里写循环清爽得多。

第二是参数计算的“可解释性”要求高。步态参数不是黑箱输出,每一个数都要能回溯到公式和原始帧。MATLAB 里我可以把每个参数写成一个独立函数,输入是轨迹矩阵和标定系数,输出是标量和中间过程,出问题的时候直接断点进去看第 237 帧到底发生了什么,这个调试体验对做科研的人来说太重要了。

第三是统计和可视化的闭环。算完参数直接fitlme做混合效应模型、直接画带误差带的步态周期图,不用在几个工具之间倒数据,减少了格式转换引入的错误。

我通常的目录组织是这样的:raw_video放原始视频,calib放标定图,track放提取层的坐标输出(csv 或者 mat),analysis放 MATLAB 的计算脚本和结果,figures放图。每个 trial 一个独立文件,命名里带日期、动物编号、trial 号,这个习惯后面会救命。

1.4 全流程时间预算与人员分工

给一个我实际项目的粗略时间账,方便你评估投入。硬件搭建和标定,第一次做大概两三天,主要是调光照和跑道角度;动物适应训练,每只每天十分钟,连续三到五天;正式采集,每只动物三到五个有效 trial,每个 trial 五到十秒有效行走,加上抓取和清理,单只动物十五分钟左右;提取层如果是现成模型,批处理一小时能跑几十个视频,如果要自己训模型,那就得按周算;计算层脚本第一次写完调试大概两三天,之后复用几乎零成本。

人员上,采集和标定建议固定一个人做,因为手感和判断标准会直接影响数据一致性;计算层的脚本要有人从头到尾负责,别出现“这个函数是谁写的、参数什么意思没人知道”的局面。

2. 采集端:决定最终精度上限的几个硬参数

我一直觉得,小鼠步态分析里 80% 的返工都源于采集阶段没有把参数想清楚。算法再花哨,也补不回丢掉的帧和糊掉的爪尖。这一章把几个关键硬件参数掰开讲,包括怎么算、为什么这么取。

2.1 帧率、快门与曝光:步态周期的时间分辨率

小鼠正常行走的步态周期大约 0.3 到 0.5 秒,支撑相占 55% 到 70%,也就是 100 到 200 毫秒。要可靠地切分支撑相和摆动相,一个支撑相里至少要采到 8 到 10 帧,低于这个数,起止点就只能靠猜。

按最短支撑相 100 ms、目标 10 帧算,帧率下限是 100 fps。但这是下限,不是推荐值。实际的着地时刻落在两帧之间,量化误差是 ±1 帧,100 fps 下就是 ±10 ms,对 100 ms 的支撑相意味着 ±10% 的相对误差。我一般会推到200 到 250 fps,把量化误差压到 ±4% 到 ±5%,同时给后续的亚帧插值留出余地。

快门速度要跟帧率一起算。小鼠行走速度按 250 mm/s 估,如果快门是 1/500 s,单帧内移动 0.5 mm,爪尖直径也就 1 到 2 mm,模糊量已经吃掉轮廓边缘了。我通常把快门设在1/1000 s 以上,单帧位移控制在 0.25 mm 以内。快门一快,进光量就掉,这时候别急着加增益——增益带来的噪声会直接污染阈值分割——而是要加光源。

还有一个容易被忽略的点:曝光时间要小于帧间隔。有些相机自动曝光会把曝光拉到接近帧周期,实际有效帧率就掉了。手动模式下把曝光锁死在 1 到 3 ms,帧率才稳。

2.2 分辨率与视野:像素当量怎么算才够用

像素当量就是每个像素代表多少毫米,直接决定你能分辨多小的差异。计算方法很简单:

像素当量 k = 视野实际宽度 L / 图像水平像素数 N

举个例子,跑道宽度 80 mm,为了留出边距,视野按 120 mm 取,相机水平分辨率 1280 px,那么 k = 120 / 1280 ≈ 0.094 mm/px。

这个精度够不够?看你要测什么。小鼠后肢步宽大约 15 到 25 mm,0.094 mm/px 下对应 160 到 265 个像素,测 1 mm 的组间差异相当于 10 个像素,完全够。但如果要测爪印面积或者足趾张开度这种小尺度特征,就得再往上提,我一般要求k ≤ 0.05 mm/px,对应 120 mm 视野下至少 2400 px 的水平分辨率。

选相机的时候还有一个坑:标称分辨率不等于有效分辨率。某些相机有 binning 或者裁切模式,实际输出可能比标称低。买之前要确认全分辨率下的帧率能不能达到 200 fps,很多相机是分辨率一降、帧率才上去,那就得在“大视野低帧率”和“小视野高帧率”之间做取舍。我的做法是视野只包住跑道有效区域,把分辨率全砸在有用的地方。

2.3 光照与跑道:把“看得清”变成“分得开”

俯视方案里最有性价比的改进往往不是换相机,而是改光照。目标是让爪和跑道背景之间形成稳定的高对比,而不是“看起来挺亮”。

用底部背光是最省事的方案:透明跑道下面放一块漫射的 LED 平板,爪挡住光形成暗轮廓,背景是均匀亮场。这种方式抗环境光干扰强,阈值分割极其稳定,我基本都是这么做的。如果跑道是不透明的,就用俯视方向的环形光或者条形光斜照,但要注意反光——小鼠爪底和跑道表面都可能产生镜面反射,亮斑被阈值切成碎片,连通域就散了。解决办法是加偏振片或者用漫射板,把光源变成大面积柔光。

频闪是另一个隐蔽的杀手。市电驱动的 LED 在某些相机快门下会出现亮度周期性波动,肉眼看不出,但逐帧看背景灰度会跳。检测方法很简单:拍一段空跑道,算每一帧的平均灰度,画出来看有没有周期性波动。有波动就换直流驱动的光源,或者在相机端开启抗闪烁模式。

跑道本身也有讲究。长度至少 40 到 50 cm 让动物能走出一段稳定步态,宽度 60 到 80 mm 足够,太宽动物会转身。两侧加挡板限制横向移动,但挡板不能遮挡俯视视野。跑道表面要防滑又不能太粗糙,太滑动物打滑,步态参数全乱;太粗糙会磨损爪底。

2.4 标定与透视校正:别让边缘像素骗了你

标定这一步,我见过太多人直接跳过,或者随便放把尺子量一下了事。问题在于:只要相机不是严格垂直、镜头有畸变,画面不同位置的像素当量就不一样,边缘区域可能差 5% 到 15%。这个误差会直接进到步长和步宽里,而且它是系统性的,不会被平均掉。

稳妥的做法是拍一张棋盘格标定板,放在跑道平面高度上,用 MATLAB 的detectCheckerboardPoints和estimateCameraParameters求内参和畸变系数,再做undistortImage。如果嫌麻烦,退一步也要在跑道平面放一把带毫米刻度的钢尺,至少在画面中心和四角各取一段已知长度,算出四个区域的实际像素当量,看看差异有多大。差异超过 3% 就必须做畸变校正,不能凑合。

标定系数算出来之后,把它存成一个结构体,跟视频绑定:

calib.k_mm_per_px = 0.0943; % 中心区域像素当量 calib.dist_coeffs = [-0.12 0.08 0 0 0]; calib.roi = [180 60 920 620]; % [x y w h]

后面每算一个物理量都要乘这个系数,绝不允在脚本里散落着硬编码的数字,否则换个相机你就得全局搜索替换。

3. 提取层:从像素到关键点的两条实现路径

提取层要做的事只有一件:给出每一帧、每只爪的位置。听起来简单,做起来是整条链路里最耗时的部分。这一章讲两条路径的具体实现,以及数据出来之后怎么判断它能不能用。

3.1 传统图像处理路线:背景建模加连通域分析

在没有姿态估计模型、或者动物背部和爪对比度特别好的情况下,传统路线又快又稳,值得先试。

核心思路是背景减除加重心提取。先用一段空跑道视频求中值背景,因为中值对偶尔经过的动物不敏感:

v = VideoReader('trial01.mp4'); n = 200; frames = read(v, [1 n]); bg = median(frames, 4); % 逐像素中值背景

读入目标帧之后做差分、阈值、形态学清理:

f = read(v, i); g = rgb2gray(f); d = imabsdiff(g, bg); bw = d > 25; % 阈值按背景噪声标准差定 bw = bwareaopen(bw, 60); % 去掉小噪点 bw = imfill(bw, 'holes'); bw = imopen(bw, strel('disk', 2));

阈值 25 这个数不是拍的,先算空跑道帧的灰度标准差 σ,取 4σ 到 5σ 比较稳。如果背景不均匀,用adaptthresh做局部自适应阈值更好,但要注意窗口大小别小于爪子的尺寸,否则爪子内部会被切空。

连通域出来后用regionprops拿Centroid、Area、BoundingBox、Orientation。俯视下四只爪常常粘成一团,这时候单靠连通域不够,得配合按身体轴向投影分割:先把整体轮廓沿跑道方向投影,找四个峰,再用峰值位置作为初始种子做分水岭。这套操作我在对比度好的数据上跑过上千个 trial,成功率在 90% 以上,剩下 10% 主要是爪重叠和尾巴干扰。

尾巴是这条路线最大的敌人。小鼠尾巴细长、经常横在跑道上、还容易被当成第五个肢体。处理办法是在轮廓阶段用长宽比过滤:尾巴的连通域细长,长宽比通常大于 4,而爪的轮廓接近圆形或椭圆形,长宽比小于 2。这个规则简单但极其有效。

3.2 关键点追踪路线:骨架输出与后处理

对比度不够理想、或者需要关节角度的时候,就得用关键点模型。通常是先用一批自己标注的帧微调一个开源姿态估计框架,导出每帧每个关键点的坐标和置信度,再进 MATLAB 做后处理。

导出格式我强烈建议统一成 csv 或者 mat,字段至少包括:帧号、关键点名、x、y、confidence。多动物或者多 trial 就再加一列 ID。不要依赖框架自带的可视化结果,那个只能看,不能算。

进 MATLAB 之后第一件事是置信度过滤。置信度低于 0.3 的点直接标记为缺失,不要用。第二件事是异常值剔除:身体尺寸在小鼠个体间差异有限,可以用一个物理约束来筛——同侧前后肢之间的距离、左右肢之间的横向距离,都应该落在一个合理区间内。超出区间三倍标准差的点判定为误识别。

一个我常用的技巧是用身体质心做参考。哪怕个别爪的关键点飘了,身体质心通常还是稳的。以质心为原点计算各爪的相对坐标,再做低通滤波,比直接在绝对坐标上滤波更能抑制整体抖动。

3.3 数据清洗:缺失帧插补与抖动抑制

原始轨迹一定会有抖动和断点,直接拿去求导会得到一堆毛刺。清洗分三步。

第一步,填补缺失。短缺失(连续少于 5 帧)用线性插值;长缺失不要硬补,标记为 NaN,后面计算参数时这段周期直接跳过。硬补长缺失会造出不存在的步态周期,这是数据造假级别的错误。

第二步,抑制抖动。我一般用零相位滤波,避免相位偏移:

fs = 200; fc = 30; % 截止频率,按采样率定 [b, a] = butter(4, fc/(fs/2), 'low'); x_filt = filtfilt(b, a, x);

截止频率怎么定?步态运动的能量主要集中在 5 Hz 以下,抖动大多在 30 Hz 以上,所以 20 到 30 Hz 是个合理区间。但要注意,滤波会削平峰值的尖锐程度,影响着地时刻的判定精度,所以着地检测最好在滤波前的速度信号上做,或者用滤波后信号做粗定位、再回到原始信号上细调。

第三步,质量打分。每个 trial 给一个可用性评分,指标包括:有效帧比例、最大连续缺失帧数、爪轨迹的信噪比、步态周期数的稳定性。低于阈值的 trial 直接剔除,不要心疼。我在一个项目里因为舍不得删,硬着头皮把一个有效帧只有 60% 的 trial 算进去了,结果那只动物的支撑相占比均值被拉偏了将近 8 个百分点,后面花了很久才发现问题出在这一条。

4. 计算层:步态参数的定义、公式与代码实现

这是整篇的核心。参数定义不清楚,算出来的数就没法跟别人的结果比。下面每个参数我都给出定义、公式和实现要点。

4.1 时空参数:步长、步宽、周期、占空比

先把几个最容易混淆的概念厘清。步长(step length)是左右脚交替着地时,两个着地点沿行进方向的距离;步幅(stride length)是同一只脚连续两次着地之间的距离,约等于两个步长。很多文献混用这两个词,写方法学的时候一定要写清楚你用的是哪个。

物理换算的通式:

物理距离(mm) = 像素距离(px) × k(mm/px)

其中 k 是标定系数。步长取相邻两次异侧着地点的 x 坐标差:

stepLen_px = abs(x_contact(i) - x_contact(i-1)); stepLen_mm = stepLen_px * calib.k_mm_per_px;

步宽是同一时刻左右后肢的横向距离:

baseWidth_mm = abs(y_L(t) - y_R(t)) * calib.k_mm_per_px;

这里有个细节:取哪个时刻的 y?我取的是两侧都处于支撑相的中点,这样最接近真实的支撑基底宽度。如果直接取某一帧,可能一只脚还在空中,算出来是摆动轨迹的横向偏移,不是步宽。

步态周期 T 是同侧连续两次着地的时间差:

T_cycle = (n_frame_2 - n_frame_1) / fps

占空比(duty factor)是支撑相时长占整个周期的比例:

DF = T_stance / T_cycle

小鼠正常行走 DF 大约 0.55 到 0.70,速度越快占比越低。这个参数对速度极其敏感,所以组间比较必须控制速度,要么限制在窄速度区间内采集,要么把速度作为协变量放进模型。

步频就是 1/T_cycle,单位是步每秒。平均速度可以用步幅除以周期估算,也可以直接用质心位移除以时间,后者更稳,因为它不依赖着地检测的准确性。

4.2 相位切分:支撑相与摆动相的自动识别

这是最容易出错的一步。俯视视频里,“脚着地”表现为爪形清晰、轮廓面积达到局部最大、沿行进方向的速度接近零。三个特征里最稳的是速度极小值加面积峰值的联合判据,单用任何一个都不够。

先算沿跑道方向的速度:

dt = 1/fs; vx = gradient(x_smooth, dt); % mm/s vx_abs = abs(vx);

着地候选点是vx_abs的局部极小值,且值小于阈值(比如 20 mm/s):

[pks, locs] = findpeaks(-vx_abs, 'MinPeakHeight', -20, ... 'MinPeakDistance', round(0.08*fs)); contact_frames = locs;

MinPeakDistance设为 80 ms 的帧数,是为了避免同一次着地被检成两个峰。这个值要小于最短支撑相、大于抖动周期,80 ms 是个经验值。

面积判据作为验证:对每个候选点,检查该帧前后 ±3 帧内爪轮廓面积是否是局部最大。两个判据都满足才确认着地,只有一个满足就标记为可疑,人工复核或者交给后续的状态机处理。

摆动相就是两次支撑相之间的区间。这里要注意一个陷阱:双支撑期。小鼠行走时存在四脚同时着地的短暂阶段,如果你的算法把每次“离地”都当成摆动开始,就会把双支撑期错误地算进摆动。处理办法是定义“支撑”为“该爪着地”,四只爪的支撑状态各算各的,不要用全局的二元状态。

还有一个速度相关的坑:动物走走停停的时候,速度极小值判据会把“停住”误判成“着地”。解决办法是加一个整体位移约束——如果一个“支撑相”超过 400 ms 且期间质心几乎没动,判定为停顿,整段剔除。

4.3 对称性与协调性:别只看左右差值

对称性指数最常用的定义是:

SI = 2 × (X_left - X_right) / (X_left + X_right) × 100%

X 可以是支撑相时长、步长、爪印面积。SI 接近 0 表示对称,正值表示左侧大。这个公式的好处是无量纲,不同个体之间可比;坏处是对小数值敏感,如果 X 本身很小,SI 会被放大。所以样本量小的时候我建议同时报告原始值和 SI。

相位协调性用相位差描述。以左后肢的着地时刻为基准,算右后肢相对它的相位偏移:

φ = 2π × (t_R - t_L) / T_cycle

正常情况下左右后肢相位差接近 π(交替)。如果接近 0 或者 2π,说明同侧化,是异常步态的重要标志。多肢体协调可以把四个相位画在单位圆上,看相位离散度(phase dispersion),离散度增大意味着协调性下降。

这里我要提醒一句:对称性指标对速度非常敏感。很多模型动物跑得慢,慢速下支撑相自然延长,左右差异也会被放大。所以报对称性必须连带报速度,或者做速度匹配的子集分析。我在一个脊髓损伤模型的数据里就吃过这个亏,治疗组恢复得更好、活动量更大、走得更快,结果支撑相反而更短,如果不控速度,结论几乎是反的。

4.4 速度归一化与统计汇总

速度归一化有两个思路。一是分层:按速度把 trial 分成慢(< 15 cm/s)、中(15 到 25)、快(> 25)三档,只在同档内比较。二是回归校正:把速度作为协变量放进线性混合模型。

我倾向于第二种,因为它不浪费数据:

lme = fitlme(tbl, 'StanceTime ~ Group + Speed + (1|AnimalID)');

(1|AnimalID)是随机截距,处理同一只动物多个 trial 的非独立性。这个模型在 MATLAB 里跑起来很快,输出里的固定效应就是校正速度后的组间差异。

统计单位也要说清楚。以动物为单位,不以 trial 为单位。同一只动物的 5 个 trial 是技术重复,不是生物学重复。我见过把 20 只动物的 100 个 trial 当成 100 个样本做 t 检验的,p 值小得离谱,这种结论站不住。

每个 trial 至少取 3 到 5 个连续稳定步态周期,取均值或者中位数。中位数抗异常值更好,我一般报中位数加四分位距。周期数太少(少于 3 个)的 trial 直接剔除,不然单周期的测量噪声会主导结果。

汇总表建议长这样,一行一个 trial:

字段含义单位
AnimalID动物编号-
Trial试次号-
Speed平均速度mm/s
StepLen_HL后肢步长均值mm
BaseWidth步宽均值mm
Stance_HL后肢支撑相时长ms
DutyFactor占空比-
SI_Stance支撑相对称指数%
N_Cycles有效周期数个
Quality质量评分0-1

导出成 csv,后面进统计软件或者直接在 MATLAB 里建模都方便。

5. 排错实录:那些论文里不会写的坑

这一章全是我自己踩过的坑。写论文的时候这些都不会出现,但它们决定了你的数据能不能用。

5.1 追踪类问题:抖动、丢点与误识别

问题一:爪尖坐标周期性抖动,频率跟步频接近。一开始我以为是滤波没做好,试了各种截止频率都没用。后来逐帧看才发现,是爪子着地时被压扁、轮廓质心后移,抬起时又恢复,质心本身就在周期性移动。这不是噪声,是真实的几何变化。解决办法是不要用轮廓质心代表爪位置,改用爪的最前端点或者固定解剖标志点,位置更稳定。

问题二:某些帧四只爪全丢。通常是动物身体完全遮挡了爪,或者跑道反光形成大片亮斑。前者无解,标记缺失;后者要改光照。我加了一块漫射板之后,这类丢点下降了接近一个数量级。

问题三:把尾巴识别成后肢。前面说过长宽比过滤,但还有一种情况是尾巴尖卷曲成团,长宽比也小。补充判据是用与身体质心的距离:后肢到质心的距离有稳定范围,尾巴尖通常更远。两个判据一起用,误识别基本能压住。

问题四:左右肢标反。这个最隐蔽,因为在某些帧里看起来完全正常。检测方法是算左右肢的横向坐标均值,如果某只动物的左右标签在某些 trial 里整体互换,均值符号会翻转。批处理之后一定要画一张所有 trial 的横向坐标均值图,一眼就能看出来。

5.2 参数类问题:数值合理但结论异常

问题五:支撑相占比超过 0.9。正常小鼠不可能这么高。查下来是着地检测阈值太松,把慢速摆动也判成了着地。把速度阈值从 30 mm/s 降到 15 mm/s 之后恢复正常。阈值怎么定?拿几个典型 trial 手工标一遍真值,画 ROC 曲线找最优点,别凭感觉。

问题六:步长为负。说明行进方向搞反了。加一步自动判断:算质心 x 坐标的整体趋势,如果是递减就把整段翻转。这个检查要写进批处理,不能靠人眼看。

问题七:组间差异特别大,大到不合常理。先查标定。我有一次换了相机忘了更新 k 值,所有长度参数整体偏大 20%,差点写进结论。现在的做法是把 k 值写进每个结果文件的头信息里,出图的时候在角落标注,强制自己每次都看到。

问题八:同一只动物的 trial 之间差异巨大。大概率是动物状态问题,不是算法问题。看视频确认:是不是走走停停、是不是贴着挡板走、是不是中途转身。这类 trial 要剔除,判据是有效行走时长占比低于 60%,或者质心轨迹的横向偏移超过跑道宽度的三分之一。

5.3 常见问题速查表

现象最可能原因排查动作处理办法
轨迹高频抖动分割边缘不稳看原始帧的二值图加滤波、改光照、换判据
周期性坐标偏移用质心代表爪位置逐帧看轮廓变化改用前端点或标志点
支撑相占比虚高着地阈值过松手标真值做 ROC收紧速度阈值
步长为负行进方向反了看质心 x 趋势自动翻转
长度整体偏大/偏小标定系数错误复核标定图更新 k 值并存档
左右肢标签互换追踪模型错配画横向坐标均值图按几何规则重排
同动物 trial 差异大动物状态或走姿异常看视频剔除或重采
周期数不足有效行走太短统计有效帧比例延长跑道、增加 trial

6. 流程固化:让第二个人也能跑出同样的数

一套流程只有能被别人复现,才算真正完成。这一章讲怎么把脚本变成工具链。

6.1 目录结构与命名规范

我的习惯是每个项目一个根目录,下面固定几个子目录:01_raw、02_calib、03_track、04_result、05_figure、06_code。文件名统一用日期_动物编号_trial号_条件的格式,比如20240512_M07_t03_ sham。不要用中文、不要用空格、不要用“最终版”“最终版2”这种命名,三个月后你自己都认不出来。

每个 trial 的处理结果存成一个 mat 文件,里面包含原始轨迹、清洗后轨迹、参数结构体、质量评分、处理时间戳、代码版本号。代码版本号这个字段看着多余,但当你发现两个月前的结果和现在不一致时,它能救命。

6.2 参数存档与复核机制

所有可调参数集中在一个config.m里,不要散落在各个脚本。包括阈值、滤波截止频率、最小峰值距离、质量评分阈值、标定系数。改参数只改这一个文件,改完在文件头写一行注释说明为什么改、改之前是多少。

复核机制我一般设两道。第一道是自动质控:批处理跑完自动生成一张汇总图,每个 trial 一个点,横轴是质量评分,纵轴是关键参数,超出三倍标准差的点标红。第二道是随机人工抽检:每个实验组随机抽 3 个 trial,把着地时刻叠加回原始视频帧上,人眼确认。这两道做完,数据基本可以放心用了。

最后分享一个我觉得最值的小习惯:把第一个能跑通的 trial 的中间结果全部存下来,包括背景帧、二值图、连通域标签、着地点标记。后面任何一次结果异常,都拿这个“标杆 trial”跑一遍,如果标杆也异常,说明是代码或参数的问题;如果标杆正常,说明是新数据的问题。这个二分法能省掉大量盲目调试的时间。

我在实际项目里最深的一点体会是,小鼠步态分析真正的难点从来不在算法本身,而在于你有没有把每一个数字的来源讲清楚。审稿人问一句“支撑相是怎么定义的”,你得能立刻翻到那几行代码和那张标定图。流程固化、参数存档、抽检复核,这些看起来枯燥的动作,最后决定了你的数据是能发出去,还是只能躺在硬盘里。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询