EmguCV/OpenCV中VideoCapture.Retrieve()触发System.AccessViolationException
Hey there, let's break down the AccessViolationException you're hitting every third call to Retrieve()—I've run into similar quirks with Emgu CV before, so here are some targeted fixes and explanations:
Key Observations from Your Code
Your WPF tutorial code uses a DispatcherTimer (running on the UI thread) without issues, while your Capture method uses a blocking while loop with Thread.Sleep(100) and recreates the VideoCapture instance every time. These differences are likely driving the exception.
Likely Causes & Fixes
1. Stop Recreating VideoCapture Instances
Your current code creates a new VideoCapture every time Capture() runs. This leads to resource contention with the camera (multiple instances trying to access the same hardware) and can leave unmanaged resources hanging, triggering memory access errors.
Fix: Initialize VideoCapture once as a class-level variable, not inside the Capture method:
// Class-level fields private VideoCapture _cameraCapture; private CascadeClassifier _faceCascade; // Initialize in your class constructor or setup method public OpenCVGenericAssembly() { _cameraCapture = new VideoCapture(); _faceCascade = new CascadeClassifier("haarcascade_frontalface_alt_tree.xml"); // Verify path is correct! }
2. Explicitly Call Grab() Before Retrieve()
While some Emgu CV versions auto-call Grab() from Retrieve(), skipping this step can lead to race conditions where Retrieve() tries to access an uninitialized frame buffer.
Fix: Add a Grab() check before retrieving the frame:
using (Mat mat = new Mat()) { if (_cameraCapture.Grab()) // Ensure a frame is ready first { _cameraCapture.Retrieve(mat); // Rest of your frame processing logic } }
3. Properly Dispose All Emgu CV Objects
Your code creates Image instances (like result) without disposing them, leading to unmanaged memory leaks. Over time, this can corrupt memory and trigger access violations.
Fix: Wrap all Image and Mat instances in using blocks:
if (detectedFaces.Length == 1) { using (var faceRegion = currentFrame.Copy(detectedFaces[0])) using (var grayFace = faceRegion.Convert<Gray, byte>()) using (var resizedFace = grayFace.Resize(IMG_WIDTH, IMG_HEIGHT, Emgu.CV.CvEnum.Inter.Cubic)) { resizedFace._EqualizeHist(); rsp.templateData = Convert.ToBase64String(resizedFace.Bytes); break; } }
4. Fix Threading & Timing Issues
Thread.Sleep(100) blocks the thread and can cause the camera's frame buffer to overflow, leading to invalid memory access. Additionally, if Capture() is called from multiple threads, you need to synchronize access to the shared VideoCapture instance.
Fixes:
- Shorten the sleep interval to 30ms to reduce buffer pressure
- Add a lock to ensure thread-safe access to
_cameraCapture - Consider using
await Task.Delay(30)instead ofThread.Sleepfor non-blocking waits (requires makingCaptureasync)
Example with locking:
private readonly object _cameraLock = new object(); public DResponse Capture(string sensorSerialNo, FeatureType feature, bool compressed = false, int timeOut = 0) { lock (_cameraLock) // Ensure only one thread accesses the camera at a time { DResponse rsp = new DResponse(); // Fix: You missed `new` here in your original code! DateTime startTime = DateTime.Now; while (string.IsNullOrWhiteSpace(rsp.templateData)) { // Handle timeout if (timeOut > 0 && (DateTime.Now - startTime).TotalMilliseconds > timeOut) { rsp.ErrorMessage = "Capture timed out"; break; } using (Mat mat = new Mat()) { if (_cameraCapture.Grab()) { _cameraCapture.Retrieve(mat); // Rest of your frame processing logic } } Thread.Sleep(30); } return rsp; } }
5. Verify Version Compatibility
Access violations can also stem from mismatched Emgu CV and underlying OpenCV library versions. Ensure you're using a stable Emgu CV release, and all required OpenCV DLLs are present in your output directory.
Final Notes
The WPF tutorial works because it reuses a single VideoCapture instance and processes frames in a controlled UI thread loop. Applying the fixes above should align your code with that stable pattern and eliminate the System.AccessViolationException.
内容的提问来源于stack exchange,提问作者stl

