Files

54 lines
1.9 KiB
Dart

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<int>? _prevGray;
MotionDetector({this.maxWidth = 128, this.maxHeight = 128});
/// 后台 isolate 用原始数据接口(不依赖 CameraImage)。
List<MotionRegion> 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<int>.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;
}
}