I'm working with .NET Framework 4.8 and NuGet libraries: OpenCvSharp4
, OpenCvSharp4.runtime.win
, OpenCvSharp4.Windows
and I'm trying to code a simple WebcamStreaming
class that takes as input a WPF
System.Windows.Controls.Image
and exposes some Start
and Stop
methods to show the camera output.
I did it, and it works, but there are two things I'm not sure about:
CPU gets very high while streaming, around 30/40%. I think it is the VideoCapture
read frames loop, so I put an await Task.Delay(10)
to free some resources on each cycle and it is working. Now the CPU is always < 10%. But is this the correct solution? Am I doing something wrong earlier?
When I close the application, I get always this exception: Managed Debugging Assistant 'DisconnectedContext' : 'Transition into COM context 0x12f6648 for this RuntimeCallableWrapper failed with the following error: The object invoked has disconnected from its clients. (Exception from HRESULT: 0x80010108 (RPC_E_DISCONNECTED)). This is typically because the COM context 0x12f6648 where this RuntimeCallableWrapper was created has been disconnected or it is busy doing something else. Releasing the interfaces from the current COM context (COM context 0x12f6700). This may cause corruption or data loss. To avoid this problem, please ensure that all COM contexts/apartments/threads stay alive and are available for context transition, until the application is completely done with the RuntimeCallableWrappers that represents COM components that live inside them.'
.
Do you know what is it and what I'm doing wrong?
You can find the whole example on a GitHub repository I've created.
The interesting part of the frames fetch loop:
_previewTask = Task.Run(async () =>
{
using (var frame = new Mat())
{
while (!_cancellationTokenSource.IsCancellationRequested)
{
_videoCapture.Read(frame);
if (!frame.Empty())
{
_lastFrame = BitmapConverter.ToBitmap(frame);
var lastFrameBitmapImage = _lastFrame.ToBitmapSource();
lastFrameBitmapImage.Freeze();
_imageControlForRendering.Dispatcher.Invoke(() => _imageControlForRendering.Source = lastFrameBitmapImage);
await Task.Delay(10);
}
}
}
}, _cancellationTokenSource.Token);
The disposal process (I call it when the application gets closed):
public void Dispose()
{
_cancellationTokenSource?.Cancel();
if (_videoCapture?.IsDisposed == false)
{
_videoCapture?.Dispose();
_videoCapture = null;
}
_lastFrame?.Dispose();
}
The problem was caused by the fact that the thread in which I was calling Dispose
wasn't the same thread in which I created VideoCapture
.
User contributions licensed under CC BY-SA 3.0