Я захватываю изображения с веб-камеры, выполняю их тяжелую обработку, а затем показываю результат. Чтобы поддерживать высокую частоту кадров, я хочу, чтобы обработка разных кадров выполнялась параллельно.
Итак, у меня есть «Продюсер», который захватывает изображения и добавляет их в «inQueue»; также он берет изображение из 'outQueue' и отображает его:
public class Producer
{
Capture capture;
Queue> inQueue;
Queue> outQueue;
Object lockObject;
Emgu.CV.UI.ImageBox screen;
public int frameCounter = 0;
public Producer(Emgu.CV.UI.ImageBox screen, Capture capture, Queue> inQueue, Queue> 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++;
}
}
}
Существуют разные «потребители», которые берут изображение из очереди inQueue, выполняют некоторую обработку и добавляют его в очередь outQueue :
public class Consumer
{
Queue> inQueue;
Queue> outQueue;
Object lockObject;
string name;
Image image;
public Consumer(Queue> inQueue, Queue> 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);
}
}
}
}
. Остальной важный код находится в этом разделе:
private void Form1_Load(object sender, EventArgs e)
{
Consumer[] c = new Consumer[consumerCount];
Thread[] t = new Thread[consumerCount];
Object lockObj = new object();
Queue> inQueue = new Queue>();
Queue> outQueue = new Queue>();
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();
}
Распараллеливание на самом деле работает нормально, я получаю линейное увеличение скорости с каждым добавленным потоком (до определенного момента, конечно ). Проблема в том, что я получаю артефакты на выходе, даже если работает только один поток. Артефакты выглядят так, будто часть изображения находится не в том месте.
Пример артефакта (без какой-либо обработки для ясности, но эффект тот же)
Любые идеи, что вызывает это? Спасибо