import 'dart:typed_data'; import '../detection/detection_result.dart'; import '../detection/motion_aggregator.dart'; /// 轻量运动检测:相邻帧 Y 通道差分 + 分块聚合。 /// 小尺寸工作(约 128x128 内),在分析流中串行调用。 /// 相机大幅移动时(全屏帧差)自动忽略本帧,避免误报。 class MotionDetector { final int maxWidth; final int maxHeight; List? _prevGray; MotionDetector({this.maxWidth = 128, this.maxHeight = 128}); /// 后台 isolate 用原始数据接口(不依赖 CameraImage)。 List detectMotionRaw( Uint8List yPlane, int yStride, int width, int height) { final w = width, h = height; final scale = maxWidth / w < maxHeight / h ? maxWidth / w : maxHeight / h; final tw = (w * scale).toInt().clamp(1, maxWidth); final th = (h * scale).toInt().clamp(1, maxHeight); if (tw == 0 || th == 0) return const []; // 取 Y 平面缩放灰度(最近邻下采样到 128x128 内) final y = yPlane; final gray = List.filled(tw * th, 0); for (var oy = 0; oy < th; oy++) { final sy = (oy / scale).toInt().clamp(0, h - 1); for (var ox = 0; ox < tw; ox++) { final sx = (ox / scale).toInt().clamp(0, w - 1); gray[oy * tw + ox] = y[sy * yStride + sx]; } } final prev = _prevGray; _prevGray = List.of(gray); if (prev == null || prev.length != gray.length) return const []; final diff = MotionAggregator.diffMask(gray, prev); final motionTotal = diff.fold(0, (a, b) => a + b); // 全屏大差异 → 相机移动/大范围变化,忽略本帧 if (motionTotal > tw * th / 2) return const []; if (motionTotal < 12) return const []; return MotionAggregator.aggregate(diff, tw, th); } /// 相机切换后重置参考帧,避免旧帧误差 void reset() { _prevGray = null; } }