C# 并行图像处理伪影
我从一个网络摄像头中捕获图像,对它们进行一些繁重的处理,然后显示结果。为了保持高帧速率,我想让不同帧的处理并行运行 因此,我有一个“制作人”,它捕获图像并将其添加到“队列”中;它还从“outQueue”中获取图像并显示:C# 并行图像处理伪影,c#,image,parallel-processing,emgucv,C#,Image,Parallel Processing,Emgucv,我从一个网络摄像头中捕获图像,对它们进行一些繁重的处理,然后显示结果。为了保持高帧速率,我想让不同帧的处理并行运行 因此,我有一个“制作人”,它捕获图像并将其添加到“队列”中;它还从“outQueue”中获取图像并显示: public class Producer { Capture capture; Queue<Image<Bgr, Byte>> inQueue; Queue<Image<Bgr, Byte>> outQu
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++;
}
}
}
公共类制作人
{
捕获;
排队;
排队出队;
对象锁定对象;
Emgu.CV.UI.ImageBox屏幕;
公共整数帧计数器=0;
公共生产者(Emgu.CV.UI.ImageBox屏幕、捕获捕获、队列输入队列、队列输出队列、对象锁定对象)
{
this.screen=屏幕;
这个。捕获=捕获;
this.inQueue=inQueue;
this.outQueue=outQueue;
this.lockObject=lockObject;
}
公共产品
{
while(true)
{
锁定(锁定对象)
{
inQueue.Enqueue(capture.QueryFrame());
如果(inQueue.Count==1)
{
Monitor.Pulsell(锁定对象);
}
如果(outQueue.Count>0)
{
screen.Image=outQueue.Dequeue();
}
}
帧计数器++;
}
}
}
有不同的“消费者”,他们从输入队列中获取图像,进行一些处理,然后将其添加到输出队列中:
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);
}
}
}
}
公共类消费者
{
排队;
排队出队;
对象锁定对象;
字符串名;
图像;
公共使用者(队列输入队列、队列输出队列、对象锁定对象、字符串名称)
{
this.inQueue=inQueue;
this.outQueue=outQueue;
this.lockObject=lockObject;
this.name=名称;
}
公共消费()
{
while(true)
{
锁定(锁定对象)
{
如果(inQueue.Count==0)
{
监视器。等待(锁定对象);
继续;
}
image=inQueue.Dequeue();
}
//对图像进行一些繁重的处理
锁定(锁定对象)
{
outQueue.Enqueue(图像);
}
}
}
}
其余的重要代码如下所示:
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();
}
private void Form1\u加载(对象发送方,事件参数e)
{
消费者[]c=新消费者[consumerCount];
线程[]t=新线程[consumerCount];
Object lockObj=新对象();
Queue inQueue=新队列();
Queue outQueue=新队列();
p=新生产者(屏幕1、捕获、入队、出队、锁定对象);
对于(int i=0;i
并行化实际上工作得很好,每增加一个线程,我都会得到一个线性的速度增加(当然,直到某一点)。问题是,即使只运行一个线程,我也会在输出中得到工件。这些瑕疵看起来像是图片的一部分不在正确的位置
你知道这是什么原因吗?
谢谢好吧,我想问题就在这里。代码部分不能保证您将被两个队列之间的一个线程访问。图像是通过入队列弹出的实际上没有按出队列中的顺序接收
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);
}
}
Displaimer:这篇文章不应该完全描述一个答案,而是给出一些提示,说明为什么要显示这个工件 快速分析表明,actifact实际上是一个框架的部分垂直镜像片段。我复制、镜像并将其放回图像上方,并添加了一个可怕的标记以显示其位置: 两件事立即引起注意:
- 工件大致定位在“正确”的位置,只是位置也是垂直镜像的李>
- 图像略有不同,表明它可能属于不同的帧
如果我不得不打赌的话,我会说这个神器可能会按顺序出现,不是在同一个位置,而是在一个特定的方向(向上或向下)上“波动”,但总是作为镜像位出现。类似于@OnoSendai,我并没有试图解决前面提到的确切问题。我必须写一个应用程序,但我没有时间。但是,我要马上改变的两件事是使用
ConcurrentQueue
类,这样您就有了线程安全性。并且,我将使用任务库函数在不同的处理器内核上创建并行任务。可以在System.Net和System.Net.Task命名空间中找到这些名称
而且,垂直翻转一块这样的东西在我看来不仅仅是一件艺术品。如果它也发生在您提到的在单个线程中执行时,那么我肯定会重新关注t