我需要在两个不同的线程中获取锁,以便访问 EmguCv 中的位图(从网络摄像头填充)。
我有一个“GetFrame”函数,可以查询相机并将其返回的内容放入 .NET 位图中。我有两个线程需要访问此位图,一个需要写入位图并将位图分配给图片框,另一个需要读取位图,将其转换为图像对象并将其分配给 EMGU ImageBox。
我首先锁定任意对象,然后执行操作。代码如下(_Camera.LiveFrame为Bitmap):
写作/阅读主题:
while (_CaptureThreadRunning)
{
lock (_Camera)
{
// _Camera.GetFrame writes to the Bitmap
if (_VideoPlaying && _Camera.GetFrame(500))
pbLiveFeed.Invalidate();
}
}
_Camera.CloseCamera(true);
_CaptureExitEvent.Set(); // Set to signal captureThread has finished
阅读/图像框主题:
while (_ProcessThreadRunning)
{
lock (_Camera)
{
// _Camera.LiveFrame is the Bitmap
procImage = new Image<Bgr, int>((Bitmap)_Camera.LiveFrame.Clone());
procImage.Draw(new Rectangle(10,20,20,15),new Bgr(Color.LightGreen), 5);
ibProcessed.Image = procImage;
ibProcessed.Invalidate();
}
}
_ProcessExitEvent.Set();
大多数情况下运行良好,但当我尝试 Clone() 位图时,我时不时会收到“对象在其他地方使用”错误。这不是正确的锁定方式吗?我不明白为什么这会引起问题。
附注我的线程也无法再正常退出。我的循环之外的 .Set() 调用永远不会被调用。我猜线程已经死锁了?
GDI+ 有一个锁定机制,可以防止两个线程使用位图对象——这就是您收到的错误。
当 UI 线程已经在访问位图时,您正尝试访问该位图。例如,1)您将位图分配给图片框,2)图片框失效然后重新绘制,3)您退出写/读线程锁,然后4)读/图像框线程尝试访问相同的重绘仍在发生时的位图。
要解决该问题,只需复制位图,然后使用该副本进行操作即可。无论您给图片框提供什么,都不要假设您可以从非 UI 线程再次触摸它。
例如,在 _Camera.GetFrame 中:
// Get the bitmap from the camera
capturedBitmap = GetFromCamera();
// Clone the bitmap first before assigning to the picture box
_Camera.LiveFrame = new Bitmap(capturedBitmap);
// Assign to the picture box
pbLiveFeed.Image = capturedBitmap;
现在,只要您有适当的锁定,就应该可以从线程访问 _Camera.LiveFrame。
我在这里要考虑的其他几个问题:
-
您提到您正在锁定一个“任意对象”,但 _Camera 似乎并非如此——它是一个可以以不可预测的方式在其他地方使用的对象。我建议制作一个仅用于锁定的对象,例如
object lockObject = new lockObject;
lock (lockObject)
{
// put your synchronized code here
}
Bitmap.Clone() 创建一个与原始位图共享像素数据的位图。当您转换为图像对象以分配给 EMGU ImageBox 时,您正在使用该克隆,它维护对位图的引用。因此,在我看来,创建一个新的位图比在这种情况下使用 Clone() 更安全。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)