我正在编写一个依赖于快速图像处理的应用程序。 这可能听起来很奇怪,但我在做C#而不是C ++。 到目前为止,这并不是一个限制,我可以实时处理图像。 虽然我对图像做了很多复杂的事情,但我在30ms内完成了这项工作。
我更改了程序以确保图像流永远不会排队 通过简单地检查布尔值来检查当前帧是否未被处理。通常这不会发生,但在某些情况下确实如此。 例如,当在VS2010调试模式下运行应用程序时,或者当PC正在执行其他繁重任务时,并且CPU资源较少。
在这种情况下,我想跳过新的帧处理,因此处理它们不会排队。在这种情况下,最好只处理仍在处理的最后已知数据,因此等待将是检索答案的最快方法。
所以我开始使用类似的东西:
private void Camera_FrameReady(object Sender, ImageEvent e)
{
if (!IsImageReady) return; // global var
IsImageReady = false;
//... do stuff with the image
IsImageReady=true;
}
正如我所希望的那样,这没有锻炼。我认为这与C#编译器中事件的线程性质有关。 所以我尝试通过取消注册并重新注册Camera_FrameReady来解决它,但相机需要花费很多时间重新启动,因此没有锻炼。
奇怪的是现在它接缝处理下面的代码,但我不确定它为什么会这样做。
private void Camera_FrameReady(object Sender, ImageEvent e)
{
Update_Image(e)
}
private void Update_Image(e)
{
if (!IsImageReady) return; // global var
IsImageReady = false;
//... do stuff with the image
IsImageReady=true;
}
这让我想知道如何编译C#。每当调用Camera_FrameReady时它是否有效,它具有"世界观"当前的全球价值观?或者全局变量仅在处理事件后更新?
答案 0 :(得分:1)
我头脑中的第一件事是Camera_FrameReady
事件阻止了获取线程。但这并不能解释为什么第二种解决方案有效。
因此,如果要处理与采集线程并行的图像,则应创建一个新线程进行处理。
例如:当有新图像时,检查处理线程是否繁忙。如果处理线程忙,您不应该等待或排队(如您所愿),但只是跳过此图像。如果处理线程正在等待工作,请将图像存储在全局'变量,因此处理线程可以访问它并发信号通知处理线程。
我为你做了一个例子:(伪)
// the thread for the processing.
private Thread _processingThread;
// a signal to check if the workerthread is busy with an image
private ManualResetEvent _workerThreadIsBusy = new ManualResetEvent(false);
// request for terminating
private ManualResetEvent _terminating = new ManualResetEvent(false);
// confirm terminated
private ManualResetEvent _terminated = new ManualResetEvent(false);
// store the current image.
private Image _myImage;
// event callback for new images
private void Camera_FrameReady(object Sender, ImageEvent e)
{
// is the workerthread already processing an image? return.. (skip this image)
if (_workerThreadIsBusy.WaitOne(0))
return; // skip frame.
//create a 'global' ref so the workerthread can access it.
/* BE CAREFULL HERE. You might experience trouble with the instance of this image.
* You are creating another reference to the SAME instance of the image
* to process on another thread. When the Camera is reusing this
* image (for speed), the image might screwed-up. In that case,
* you have to create a copy!
* (personally I would reuse the image which makes the image not available outside the event callback) */
_myImage = e.Image;
// signal the workerthread, so it starts processing the current image.
_workerThreadIsBusy.Set();
}
private void ImageProcessingThread()
{
var waitHandles = new WaitHandle[] { _terminating, _workerThreadIsBusy };
var run = true;
while (run)
{
switch (EventWaitHandle.WaitAny(waitHandles))
{
case 0:
// terminating.
run = false;
break;
case 1:
// process _myImage
ProcessImage(_myImage);
_workerThreadIsBusy.Reset();
break;
}
}
_terminated.Set();
}
private void ProcessImage(Image _myImage)
{
// whatever...
}
// constructor
public MyCameraProcessor()
{
// define the thread.
_processingThread = new Thread(ImageProcessingThread);
_processingThread.Start();
}
public void Dispose()
{
_terminating.Set();
_terminated.WaitOne();
}
}
答案 1 :(得分:0)
您的代码不是多线程安全的
if (!IsImageReady) return; // global var
IsImageReady = false;
//... do stuff with the image
IsImageReady=true;
2个线程可以同时读取IsImageReady,看到它是真的并且都将它设置为false。如果处理器从缓存而不是从内存读取IsImageReady,您可能也会遇到问题。您可以避免Interlocked类的这类问题,它在一个操作中读取和更改值。它还确保缓存不会导致问题。
private int IsImageReady= 0;
private void Camera_FrameReady(object Sender, ImageEvent e){
int wasImageReady = Interlocked.Exchange(ref IsImageReady, 1);
if (wasImageReady ==1) return;
//do something
IsImageReady= 0;
}
}
虽然我不确定这是否是你唯一的问题。你可能也有其他人。可以肯定的是,您必须正确调试代码,这在涉及多线程时非常困难。阅读我的文章Codeproject: Debugging multithreaded code in real time,了解如何做到这一点。