-
Notifications
You must be signed in to change notification settings - Fork 33
Additional motion detection enhancements #170
Comments
That hard-coded With 64 cells on a 640x480 image each cell is just 80x60 and that should be more than fine enough to reject tiny localized movement and perhaps implement proximity-based triggering. After dinner I'll test whether |
Since With 64 cells, The interesting parts are the struct and the loop changes: private struct DiffRect
{
internal int diff;
internal Rectangle rect;
} private int Analyse()
{
_workingData = this.WorkingData.ToArray();
var result = Parallel.ForEach(_cellRect, (src, loopState) => CheckDiff(src, loopState));
if (!result.IsCompleted && !result.LowestBreakIteration.HasValue)
{
return int.MaxValue; // loop was stopped, so return a large diff
}
else
{
int diff = 0;
foreach (var cell in _cellRect)
diff += cell.diff;
return diff;
}
} private void CheckDiff(DiffRect cell, ParallelLoopState loopState)
{
cell.diff = 0;
var rect = cell.rect;
// looping and diff math omitted
// If the threshold has been exceeded, we want to exit from this method immediately for performance reasons.
if (cell.diff > MotionConfig.Threshold)
{
loopState.Stop();
return;
}
}
if (cell.diff > MotionConfig.Threshold)
{
loopState.Stop();
return;
}
}
} |
This is interesting. Setting the divisor to 10 or 16 (100 or 256 cells) made performance slightly worse. But I didn't expect this: cranking it up to 1024 cells (divisor 32) still shows small perf gains ... I'm seeing around 7.7ms per pass, and that's very consistent. Those would be 20x15 cells at 640x480. There must be some tradeoff from the smaller cell size. There isn't a good integer divisor larger than that which works evenly with 640 and 480 (e.g. you'd start losing pixels from roundoff) so that's about as good as it gets with this approach. Under 8ms is pretty good. I also realized the passes are always 707 or 708 because now it's just limited by the configured frame rate. 30 seconds of motion detection at that speed would be enough to actually process nearly 3900 frames, which is almost 130 FPS -- far more than the Pi can do. Neat. |
So my eventual goal was to attempt motion detection using only values in close proximity. I had a bug in my implementation in that I was updating a struct field -- the motion detection events were from calling So I switched to a pair of simple independent arrays (which are thread-safe if threads are reading/writing specific, non-overlapping indices) and ... it got faster. 😀 So we're down in the 6.7ms range now at 1024 cells. I'll update the PR with the changes. |
Hey Ian, some interesting news... back in #161 the motion detection processing improved a lot -- my test setup was getting 25ms per pass, about 255 frames over a 30 second run. I've managed to more than double that ... about 10.5ms per pass, and more than 700 frames over a 30 second run.
I'm actually setting this up as a prelude to attempt fine-grained-cell proximity motion detection (e.g. "ignore my small dog" mode), but these changes are sufficiently substantial to warrant a PR of their own.
The crazy part is that the changes are simple. The largest change is to simply pre-calculate the
Rectangle
objects once along with a few other one-time optimizations that the existing 0.7 build does repeatedly on the fly. Apparently even struct allocs can be expensive. Nobody really needs 10ms motion detection (probably), so my hope is that this headspace will allow for more complex analysis. Also I want to investigate the use ofParallel.For
versus arrays of tasks -- in .NET Core they made good progress generalizing task parallelism butParallel.For
is still theoretically optimal for CPU-bound operations like these.It's quite late and I need to turn in, but I have a few other things in mind before I PR this. But the improvement was so substantial I thought I'd open a new discussion as a heads up.
The text was updated successfully, but these errors were encountered: