Spaces:
Running
Running
stouchinglhh
Claude
sync processor from GitLab c697b6e: 版本 1.19.4 / 前端 1.12.4 —— 服务端 i18n(首屏不再闪英文)、推理模块并入模型页、前端抽出 shared/、缓存键改用前端号
bb59211 Download processor/app/processing/cleaning/checks/video/frame_drop.py from Stouching-Robotics/DataFlowing: direct link, hf CLI and curl.
- Browser
- Download file 3.13 kB
-
https://huggingface.co/spaces/Stouching-Robotics/DataFlowing/resolve/main/processor/app/processing/cleaning/checks/video/frame_drop.py
- Command line
-
hf download hf://spaces/Stouching-Robotics/DataFlowing/processor/app/processing/cleaning/checks/video/frame_drop.py
-
curl -L -o frame_drop.py https://huggingface.co/spaces/Stouching-Robotics/DataFlowing/resolve/main/processor/app/processing/cleaning/checks/video/frame_drop.py
3.13 kB
| """丢帧 / 帧数对齐 —— 视频帧数与 parquet 行数不一致。 | |
| 为什么重要 | |
| ---------- | |
| 两者不一致时,按帧号取动作会整体错位;漏帧则会让模型学到"同一帧对应两个 | |
| 动作"。真实的采集侧表现是视频比数据少几帧(编码器丢帧)或多几帧(尾部多录)。 | |
| 判定口径 | |
| -------- | |
| 容差取 ``max(tolerance_min, data_rows × tolerance_ratio)``: | |
| 小批次按绝对帧数兜底(默认 2 帧),大批次按比例(默认 0.5%)。 | |
| 超出容差 5 倍判 FAIL,否则 WARN —— 差几帧和差几百帧不是一回事。 | |
| """ | |
| from __future__ import annotations | |
| from app.processing.cleaning.contract import VIDEO_CAPABLE_MODALITIES | |
| from app.processing.cleaning.checks import ( | |
| CheckContext, CleaningCheck, register_check, | |
| Finding, PASS, WARN, FAIL, | |
| ) | |
| class VideoFrameDropCheck(CleaningCheck): | |
| slug = "video.frame_drop" | |
| label = "Frame Drop / Count Alignment" | |
| version = "1.0" | |
| description = "Video frame count differs from data row count" | |
| requires_channels = ("rgb",) | |
| # 属于哪些设备卡片 —— 前端设置面板按它分 tab | |
| device_cards = VIDEO_CAPABLE_MODALITIES | |
| # 阈值默认值 —— 节点配置可覆盖。 | |
| # 方案要求「阈值不要照搬」:这是平台起点值,必须用人工确认过的好/坏数据验证。 | |
| default_params = {"tolerance_ratio": 0.005, "tolerance_min": 2} | |
| default_severity = WARN | |
| def run(self, ctx: CheckContext) -> list[Finding]: | |
| findings: list[Finding] = [] | |
| for stream in ctx.streams_of("rgb"): | |
| report = stream.video or {} | |
| if not report: | |
| continue | |
| # 打不开/读不了元数据的流不算"丢帧问题",交给 video.decode_error | |
| if report.get("reason") in ("video_open_failed", "video_metadata_invalid"): | |
| continue | |
| video_frames = int(report.get("frame_count") or 0) | |
| data_rows = int(stream.rows or ctx.data_rows or 0) | |
| if not video_frames or not data_rows: | |
| continue | |
| diff = abs(video_frames - data_rows) | |
| tolerance = max( | |
| int(self.param(ctx, "tolerance_min", 2)), | |
| int(data_rows * float(self.param(ctx, "tolerance_ratio", 0.005))), | |
| ) | |
| metrics = { | |
| "video_frames": video_frames, | |
| "data_rows": data_rows, | |
| "diff": diff, | |
| "tolerance": tolerance, | |
| } | |
| if diff <= tolerance: | |
| findings.append(self.finding(ctx, PASS, stream=stream.key, | |
| metrics=metrics)) | |
| continue | |
| findings.append(self.finding( | |
| ctx, | |
| FAIL if diff > tolerance * 5 else WARN, | |
| stream=stream.key, | |
| message=f"video has {video_frames} frames / data has {data_rows} rows" | |
| f",差 {diff} 帧(容差 {tolerance})", | |
| metrics=metrics, | |
| )) | |
| return findings | |