简体   繁体   English

并行图像处理工件

[英]parallel image processing artifacts

I capture images from a webcam, do some heavy processing on them, and then show the result. 我从网络摄像头捕获图像,对它们进行一些繁重的处理,然后显示结果。 To keep the framerate high, i want to have the processing of different frames run in parallel. 为了保持帧率高,我想让不同帧的处理并行运行。

So, I have a 'Producer', which captures the images and adds these to the 'inQueue'; 所以,我有一个'制片人',它捕捉图像并将它们添加到'inQueue'; also it takes an image from the 'outQueue' and displays it: 它还需要来自'outQueue'的图像并显示它:

public class Producer
{
    Capture capture;
    Queue<Image<Bgr, Byte>> inQueue;
    Queue<Image<Bgr, Byte>> outQueue;
    Object lockObject;
    Emgu.CV.UI.ImageBox screen;
    public int frameCounter = 0;

    public Producer(Emgu.CV.UI.ImageBox screen, Capture capture, Queue<Image<Bgr, Byte>> inQueue, Queue<Image<Bgr, Byte>> outQueue, Object lockObject)
    {
        this.screen = screen;
        this.capture = capture;
        this.inQueue = inQueue;
        this.outQueue = outQueue;
        this.lockObject = lockObject;
    }

    public void produce()
    {
        while (true)
        {
            lock (lockObject)
            {
                inQueue.Enqueue(capture.QueryFrame());

                if (inQueue.Count == 1)
                {
                    Monitor.PulseAll(lockObject);
                }
                if (outQueue.Count > 0)
                {
                    screen.Image = outQueue.Dequeue();                      
                }
            }
            frameCounter++;
        }           
    }
}

There are different 'Consumers' who take an image from the inQueue, do some processing, and add them to the outQueue: 有不同的'消费者'从inQueue中获取图像,进行一些处理,并将它们添加到outQueue中:

public class Consumer
{
    Queue<Image<Bgr, Byte>> inQueue;
    Queue<Image<Bgr, Byte>> outQueue;
    Object lockObject;
    string name;

    Image<Bgr, Byte> image;

    public Consumer(Queue<Image<Bgr, Byte>> inQueue, Queue<Image<Bgr, Byte>> outQueue, Object lockObject, string name)
    {
        this.inQueue = inQueue;
        this.outQueue = outQueue;
        this.lockObject = lockObject;
        this.name = name;
    }

    public void consume()
    {
        while (true)
        {
            lock (lockObject)
            {
                if (inQueue.Count == 0)
                {
                    Monitor.Wait(lockObject);
                    continue;
                }                
                image = inQueue.Dequeue();   
            }

            // Do some heavy processing with the image

            lock (lockObject)
            {
                outQueue.Enqueue(image);
            }

        }
    }
}

Rest of the important code is this section: 其余的重要代码是这一部分:

    private void Form1_Load(object sender, EventArgs e)
    {
        Consumer[] c = new Consumer[consumerCount];
        Thread[] t = new Thread[consumerCount];

        Object lockObj = new object();
        Queue<Image<Bgr, Byte>> inQueue = new Queue<Image<Bgr, Byte>>();
        Queue<Image<Bgr, Byte>> outQueue = new Queue<Image<Bgr, Byte>>();

        p = new Producer(screen1, capture, inQueue, outQueue, lockObj);

        for (int i = 0; i < consumerCount; i++)
        {
            c[i] = new Consumer(inQueue, outQueue, lockObj, "c_" + Convert.ToString(i));
        }
        for (int i = 0; i < consumerCount; i++)
        {
            t[i] = new Thread(c[i].consume);
            t[i].Start();
        }

        Thread pt = new Thread(p.produce);
        pt.Start();
    }

The parallelisation actually works fine, I do get a linear speed increase with each added thread (up to a certain point of course). 并行化实际上工作正常,我确实通过每个添加的线程(当然达到某个点)获得线性速度增加。 The problem is that I get artifacts in the output, even if running only one thread. 问题是我在输出中得到了工件,即使只运行一个线程。 The artifacts look like part of the picture is not in the right place. 工件看起来像图片的一部分不在正确的位置。

Example of the artifact (this is without any processing to keep it clear, but the effect is the same) 工件的示例(这是没有任何处理以保持清晰,但效果是相同的)

Any ideas what causes this? 有什么想法导致这个? Thanks 谢谢

Displaimer: This post isn't supposed to fully describe an answer, but instead give some hints on why the artifact is being shown. Displaimer:这篇文章不应该完全描述答案,而是提供一些关于为什么要显示工件的提示。

A quick analysis show that the the actifact is, in fact, a partial, vertically mirrored snippet of a frame. 一个快速的分析表明,这个实际上是一个部分的,垂直镜像的框架片段。 I copied it, mirrored, and placed it back over the image, and added an awful marker to show its placement: 我将其复制,镜像并将其放回图像上,并添加了一个可怕的标记来显示其位置:

在此输入图像描述

Two things immediately come to attention: 有两件事立即引起注意:

  • The artifact is roughly positioned on the 'correct' place it would be, only that the position is also vertically mirrored; 人工制品大致位于“正确”的位置,只是位置也是垂直镜像的;
  • The image is slightly different, indicating that it may belong to a different frame. 图像略有不同,表明它可能属于不同的帧。

It's been a while since I played around with raw capture and ran into a similar issue, but I remember that depending on how the driver is implemented (or set up - this particular issue happened when setting a specific imaging device for interlaced capture) it may fill its framebuffer alternating between 'top-down' and 'bottom-up' scans - as soon as the frame is full, the 'cursor' reverts direction. 自从我玩原始捕获并遇​​到类似问题已经有一段时间了,但我记得,根据驱动程序的实现方式(或设置 - 在设置特定的成像设备进行隔行扫描时发生这个特殊问题)在“自上而下”和“自下而上”扫描之间交替填充帧缓冲 - 一旦帧满,“光标”就会恢复方向。

It seems to me that you're running into a race condition/buffer underrun situation, where the transfer from the framebuffer to your application is happening before the full frame is transferred by the device. 在我看来,你正在遇到竞争条件/缓冲区欠载情况,在这种情况下,从帧缓冲区到应用程序的转移发生在设备传输完整帧之前。

In that case, you'd receive a partial image, and the area still not refreshed would show a bit of the previously transferred frame. 在这种情况下,您将收到一个部分图像,并且仍未刷新的区域将显示先前传输的帧的一些。

If I'd have to bet, I'd say that the artifact may appear on sequential order, not on the same position but 'fluctuating' on a specific direction (up or down), but always as a mirrored bit. 如果我不得不打赌,我会说工件可能出现在顺序上,而不是在同一个位置,而是在特定方向(向上或向下)“波动”,但始终作为镜像位。

Well, I think the problem is here . 好吧,我认为问题出在这里。 The section of code is not guarantee that you will be access by one thread in here between two queue. 代码部分不保证您将在两个队列之间通过此处的一个线程进行访问。 The image is pop by inQueue is not actually received in order in outQueue outQueue中按顺序实际上没有接收到由inQueue弹出的图像

while (true)
{
        lock (lockObject)
        {
            if (inQueue.Count == 0)
            {
                Monitor.Wait(lockObject);
                continue;
            }                
            image = inQueue.Dequeue();   
        }

        // Do some heavy processing with the image

        lock (lockObject)
        {
            outQueue.Enqueue(image);
        }

}

Similar to @OnoSendai, I'm not trying to solve the exact problem as stated. 与@OnoSendai类似,我并没有试图解决所述的确切问题。 I would have to write an app and I just don't have the time. 我不得不写一个应用程序,我只是没有时间。 But, the two things that I would change right away would be to use the ConcurrentQueue class so that you have thread-safety. 但是,我将立即更改的两件事是使用ConcurrentQueue类,以便您具有线程安全性。 And, I would use the Task library functions in order to create parallel tasks on different processor cores. 而且,我会使用Task库函数来在不同的处理器内核上创建并行任务。 These are found in the System.Net and System.Net.Task namespaces. 这些可以在System.Net和System.Net.Task命名空间中找到。

Also, vertically flipping a chunk like that looks like more than an artifact to me. 此外,垂直翻转像这样的块看起来不仅仅是一件神器给我。 If it also happens when executing in a single thread as you mentioned, then I would definitely re-focus on the "heavy processing" part of the equation. 如果在你提到的单个线程中执行时也会发生这种情况,那么我肯定会重新关注等式中的“重处理”部分。

Good luck! 祝好运! Take care. 照顾自己。

You may have two problems: 您可能有两个问题:

1) parallism doesn't ensure that images are added to the out queue in the right order. 1)并行性不能确保以正确的顺序将图像添加到出队列中。 I imagine that displaying image 8 before image 6 and 7 can produce some artifacts. 我想在图像6和7之前显示图像8会产生一些伪影。 In consumer thread, you have to wait previous consumer have posted its image to the out queue to post next image. 在消费者线程中,您必须等待之前的消费者已将其图像发布到输出队列以发布下一个图像。 Tasks can help greatly for that because of their inherent synchronisation mecanism. 由于其固有的同步机制,任务可以极大地帮助实现这一目标。

2) You may also have problems in the rendering code. 2)您可能在渲染代码中遇到问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM