A professional and production-ready .NET library for real-time motion detection and camera capture capabilities. Built on top of the Emgu CV (OpenCV wrapper) and DirectShowLib frameworks, it provides high-performance motion analytics designed for thread safety, memory efficiency, and easy integration.
The solution is divided into modular components separating core business logic, device capture capabilities, and demo frontends:
graph TD
A[MotionDetectionWinFormsApp] -->|Uses| B[libMotionDetection.NET]
A -->|Uses| C[libVideoCapture.NET]
B -->|Wraps| D[Emgu.CV / OpenCV]
C -->|Wraps| E[DirectShowLib COM]
+-----------------------------------------+
| MotionDetectionWinFormsApp |
| (Dense & Sparse Flow, History & AbsDiff)|
+--------------------+--------------------+
|
+------------+------------+
| |
v v
+-----------------------+ +-----------------------+
| libMotionDetection.NET| | libVideoCapture.NET |
| (Motion Algorithms) | | (Device Capabilities)|
+-----------+-----------+ +-----------+-----------+
| |
v v
+-----------------------+ +-----------------------+
| Emgu CV / OpenCV | | DirectShowLib COM |
| (Native Algorithms) | | (Native Hardware) |
+-----------------------+ +-----------------------+
[Background Video Capture Thread] [Main UI Drawing Thread]
| |
|-- 1. Grab Frame (Mat) |
|-- 2. Process frame (Get Components) |
| |-- (Locks _lock) |
| |-- Updates _motionComponents / |
| _motionVectors |
| |
| |-- 3. Read Stats (locked read)
| | |-- Gets cloned snapshot
| | |-- Draws bounding boxes,
| | vectors, or tracking nodes
| |
|-- 4. SafeSetImageBoxImage |
| |-- Swaps Mat handle in PictureBox |
| |-- Disposes previous frame Mat |
| |
libMotionDetection.NET: The central business logic library targeting.NET 8.0. Implements five major motion detection algorithms:- Motion History Tracker (
MotionDetectionWithMotionHistory): Tracks direction, angle, pixel counts, and centroids of motion components over time. - Dense Optical Flow (
MotionDetectionWithDenseOpticalFlow): Computes pixel-level motion vectors using OpenCV'sDISOpticalFlowalgorithm, visualizing directions and magnitudes in HSV/BGR. - Sparse Optical Flow (
MotionDetectionWithSparseOpticalFlow): Tracks a sparse set of Shi-Tomasi feature corners across frames using Pyramidal Lucas-Kanade optical flow, calculating velocity vectors with low CPU utilization. - Temporal Frame Differencing (
MotionDetectionWithFrameDifferencing): Computes absolute pixel differences between consecutive frames, generating contours and bounding boxes of motion. - Background Subtraction (
MotionDetectionWithBackgroundSubtraction): Employs mixture of Gaussians (MOG2), K-Nearest Neighbors (KNN), count-based (CNT), or Bayesian (GMG) subtractors to separate moving foreground objects from background models.
- Motion History Tracker (
libVideoCapture.NET: A utility library targeting.NET 8.0-windowsthat queries video capture hardware, retrieves camera names, and lists supported device resolutions via DirectShow COM interfaces.
MotionDetectionWinFormsApp: A unified interactive desktop application showing real-time camera feeds. Users can select between Dense Optical Flow, Motion History, Sparse Optical Flow (Lucas-Kanade), Temporal Frame Differencing (AbsDiff), and Background Subtraction (MOG2 / KNN / CNT / GMG) algorithms dynamically, configure exclusion zones (Motion Zones), toggle alarms, and fine-tune thresholds.
In video streaming applications, background capture threads process incoming frames while the UI thread reads settings and updates controls. The library manages thread-safety via:
- Internal synchronization objects (
lock) preventing collection corruption during concurrent read/writes. - Exposing public configurations (like
MotionZones) asIReadOnlyList<Rectangle>and providing thread-safe mutation handlers (AddMotionZone,RemoveMotionZone,ClearMotionZones). - Returning snapshot arrays (
Clone()) of internal state variables (likeMotionComponents) under locks.
Because Emgu CV wraps native C++ OpenCV objects (Mat, MotionHistory, BackgroundSubtractorMOG2) and libVideoCapture.NET queries DirectShow COM interfaces, improper lifetime management results in unmanaged memory leaks.
- Detector Disposability: Both motion detection classes implement
IDisposableto cleanly release unmanaged resources. - Leaking Prevention in Loops: Custom
SafeSetImageBoxImageroutines in the WinForms apps swap and dispose of oldMat/Imageinstances to keep memory consumption flat. - DirectShow COM Reclamation: All COM objects used during capability lookup are strictly released in
finallyblocks usingMarshal.ReleaseComObject, and native struct buffers are released usingDsUtils.FreeAMMediaType.
- Parametric Line Interpolation:
GetPointsLine(...)uses parameter-based linear interpolation (t = [0..1]) which avoids division-by-zero on vertical lines and prevents castingNaNcoordinates. - Grayscale Conversion Checks: Optical flow inputs are checked for grayscale format and only converted to 1-channel
Cv8Uif needed, preventing uninitialized/empty matrix crashes. - Division Protection: Divisors are validated to prevent
Infinity/NaNscalar values when calculating motion intensities under zero-motion conditions.
- .NET 9.0 SDK
- Windows OS (required for WinForms frontends and DirectShow device capability lookup)
From the root workspace directory, run:
dotnet buildusing libVideoCapture;
// Retrieve available input devices
var videoDevices = new VideoCaptureDevices();
foreach (var device in videoDevices.VideoInputDevices)
{
Console.WriteLine($"Device Name: {device.VideoInputDevice.Name}");
foreach (var resolution in device.AvailableResolutions)
{
Console.WriteLine($" - Supported Resolution: {resolution.Width}x{resolution.Height}");
}
}using Emgu.CV;
using libMotionDetection;
// Instantiate the motion detector
using var detector = new MotionDetectionWithMotionHistory();
// Optionally configure settings
detector.Setting = new MotionDetectionWithMotionHistory.MotionSetting
{
MotionThreshold = 1500,
CalculateMotionInfo = true,
MotionPixelCountThresholdPerCentArea = 0.05
};
// Process video frames in a loop
Mat currentFrame = GetNextVideoFrame(); // e.g. from VideoCapture
detector.GetFrameMotionComponents(currentFrame);
// Retrieve found motion vectors thread-safely
foreach (var component in detector.MotionComponents)
{
Console.WriteLine($"Found Motion: Bounding Box={component.MotionBoundingRectangle}, Angle={component.MotionAngle}ยฐ");
}using Emgu.CV;
using libMotionDetection;
// Instantiate the sparse optical flow tracker
using var detector = new MotionDetectionWithSparseOpticalFlow();
// Process video frames in a loop
Mat currentFrame = GetNextVideoFrame(); // e.g. from VideoCapture
detector.ProcessFrame(currentFrame);
// Retrieve tracked velocity vectors thread-safely
foreach (var vector in detector.MotionVectors)
{
Console.WriteLine($"Point Tracked: Start={vector.Start}, End={vector.End}, Speed={vector.Magnitude}px/frame");
}
// Draw vectors directly on a display frame
Mat displayFrame = currentFrame.Clone();
detector.DrawMotionVectors(displayFrame);using Emgu.CV;
using libMotionDetection;
using System.Drawing;
// Instantiate the difference detector
using var detector = new MotionDetectionWithFrameDifferencing();
// Configure threshold settings (optional)
detector.Setting = new MotionDetectionWithFrameDifferencing.DifferenceSetting
{
Threshold = 30,
MinAreaPercent = 0.5
};
// Process video frames in a loop
Mat currentFrame = GetNextVideoFrame(); // e.g. from VideoCapture
detector.ProcessFrame(currentFrame);
// Retrieve bounding boxes of detected motion contours
foreach (Rectangle rect in detector.MotionComponents)
{
Console.WriteLine($"Moving Object Bounds: {rect}");
}
// Draw boundary outlines directly on a display frame
Mat displayFrame = currentFrame.Clone();
detector.DrawMotionGraphics(displayFrame);using Emgu.CV;
using libMotionDetection;
using System.Drawing;
// Instantiate the background subtraction detector
using var detector = new MotionDetectionWithBackgroundSubtraction();
// Choose subtractor algorithm dynamically (MOG2, KNN, CNT, or GMG)
detector.ActiveSubtractor = MotionDetectionWithBackgroundSubtraction.SubtractorType.CNT;
// Process video frames in a loop
Mat currentFrame = GetNextVideoFrame(); // e.g. from VideoCapture
detector.ProcessFrame(currentFrame);
// Retrieve bounding boxes of detected motion contours
foreach (Rectangle rect in detector.MotionComponents)
{
Console.WriteLine($"Foreground Object Bounds: {rect}");
}
// Draw boundary outlines directly on a display frame
Mat displayFrame = currentFrame.Clone();
detector.DrawMotionGraphics(displayFrame);- Cross-Platform Support: Abstract the capture capabilities to support macOS/Linux using GStreamer or ffmpeg wrappers.
- Unit Tests: Implement xUnit unit tests using synthetic frame streams to validate boundary behaviors, line crossing triggers, and zone exclusions.
- Advanced Detectors: Add alternative deep learning object detectors or CUDA-accelerated object tracking.