2012-07-23 20 views
16

Tôi chụp ảnh từ webcam, thực hiện xử lý nặng trên chúng, sau đó hiển thị kết quả. Để giữ tốc độ khung hình cao, tôi muốn xử lý các khung khác nhau chạy song song.tạo phẩm xử lý hình ảnh song song

Vì vậy, tôi có một 'Nhà sản xuất', chụp hình ảnh và thêm chúng vào 'inQueue'; cũng phải mất một hình ảnh từ 'outQueue' và hiển thị nó:

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++; 
     }   
    } 
} 

Có khác nhau 'Người tiêu dùng' người có một hình ảnh từ inQueue, làm một số chế biến, và thêm chúng vào 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); 
      } 

     } 
    } 
} 

phần còn lại của các mã quan trọng là phần này:

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(); 
    } 

các parallelisation thực sự hoạt động tốt, tôi có được một sự gia tăng tốc độ thẳng với mỗi chủ đề gia tăng (lên đến một điểm nhất định tất nhiên). Vấn đề là tôi nhận được đồ tạo tác ở đầu ra, ngay cả khi chỉ chạy một luồng. Các đồ tạo tác trông giống như một phần của bức tranh không ở đúng nơi.

Example of the artifact (this is without any processing to keep it clear, but the effect is the same)

Bất kỳ ý tưởng nào gây ra điều này? Cảm ơn

+0

Đó là thứ mà trò chơi cũ được tạo ra như thế nào. Về cơ bản, bạn đang cố gắng trộn lẫn các khái niệm kỹ thuật cũ với các khái niệm mới. Và đó là lý do tại sao nó không thực sự hiệu quả. Bạn cần sử dụng nhiều Threads (những gì bạn đã làm). Tôi không thực sự là nhà phát triển trò chơi, nhưng tôi nghĩ bạn không nên sử dụng EventQue hoặc bất kỳ khóa Màn hình nào. Bạn có thể chỉ đơn giản là overdraw hình ảnh mà không nhận được deadlocks. Nhưng tôi không chắc chắn về nó. Vì vậy, tôi đã không đăng bất cứ điều gì, gây ra không chính xác biết giải pháp. Nhưng tôi nghĩ bạn nên suy nghĩ về đề xuất giải pháp của tôi. – alpham8

Trả lời

1

Vâng, tôi nghĩ vấn đề là ở đây. Phần mã không đảm bảo rằng bạn sẽ được truy cập bởi một luồng ở đây giữa hai hàng đợi. Hình ảnh là pop bởi inQueue không thực sự nhận được trong trật tự trong outQueue

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); 
     } 

} 
+0

Bạn đã kiểm tra bản sửa lỗi của mình chưa? –

7

Displaimer: bài này không phải để mô tả đầy đủ một câu trả lời, nhưng thay vì đưa ra một số gợi ý về lý do tại sao các vật đang được được hiển thị.

Một phân tích nhanh cho thấy rằng hiện vật này, trên thực tế, một đoạn mã được nhân đôi theo chiều dọc được nhân đôi của một khung. Tôi sao chép nó, phản ánh, và đặt nó trở lại so với hình ảnh, và thêm vào một dấu hiệu khủng khiếp để hiển thị vị trí của nó:

enter image description here

Hai điều ngay đến sự chú ý:

  • Các vật là khoảng đặt trên vị trí 'chính xác', chỉ có vị trí đó cũng được nhân đôi theo chiều dọc;
  • Hình ảnh hơi khác, cho biết hình ảnh có thể thuộc về một khung khác.

Đã một lúc kể từ khi tôi chơi với chụp thô và gặp sự cố tương tự, nhưng tôi nhớ rằng tùy thuộc vào cách trình điều khiển được triển khai (hoặc thiết lập - vấn đề này xảy ra khi thiết lập thiết bị hình ảnh cụ thể để chụp xen kẽ) nó có thể lấp đầy bộ đệm khung của nó xen kẽ giữa các lần quét 'từ trên xuống' và 'từ dưới lên' - ngay khi khung hình đầy, con trỏ 'chuyển hướng' trở lại. Có vẻ như với tôi rằng bạn đang gặp tình trạng chạy đua/tình trạng thiếu bộ đệm, nơi việc chuyển từ bộ đệm khung đến ứng dụng của bạn đang diễn ra trước khi thiết bị chuyển hoàn toàn khung hình.

Trong trường hợp đó, bạn sẽ nhận được một hình ảnh một phần và khu vực vẫn chưa được làm mới sẽ hiển thị một chút của khung được chuyển trước đó.

Nếu tôi phải đặt cược, tôi muốn nói rằng tạo tác có thể xuất hiện theo thứ tự tuần tự, không phải trên cùng một vị trí nhưng 'dao động' theo một hướng cụ thể (lên hoặc xuống), nhưng luôn luôn là một bit được nhân đôi .

+2

Có thể bởi vì dưới tải chủ đề của Nhà sản xuất có thể được ưu tiên trong khi nó cố chụp? Tôi sẽ thử viết các bản ghi thô vào đĩa trước khi xử lý để điều tra. – bmm6o

+0

Đó là một khả năng, @ bmm6o, bạn đúng - nhưng một lần nữa, nó phụ thuộc rất nhiều vào việc thực hiện. – OnoSendai

+0

Mặc dù nếu đó là trường hợp đó là một lỗi trong 'Producer.QueryFrame()'. Đó có phải là mã của bạn hoặc bên thứ 3 không? – bmm6o

1

Tương tự như @OnoSendai, tôi không cố giải quyết vấn đề chính xác như đã nêu. Tôi sẽ phải viết một ứng dụng và tôi không có thời gian. Tuy nhiên, hai điều mà tôi sẽ thay đổi ngay lập tức sẽ là sử dụng lớp ConcurrentQueue để bạn có chủ đề an toàn. Và, tôi sẽ sử dụng các chức năng của Thư viện tác vụ để tạo các tác vụ song song trên các lõi bộ xử lý khác nhau. Chúng được tìm thấy trong các không gian tên System.Net và System.Net.Task.

Ngoài ra, theo chiều dọc, lật một đoạn như thế trông giống như nhiều hơn một tạo phẩm cho tôi. Nếu nó cũng xảy ra khi thực hiện trong một chủ đề duy nhất như bạn đã đề cập, sau đó tôi chắc chắn sẽ tập trung vào phần "xử lý nặng" của phương trình.

Chúc may mắn! Bảo trọng.

0

Bạn có thể có hai vấn đề:

1) parallism không đảm bảo rằng hình ảnh được thêm vào hàng đợi ra theo thứ tự đúng. Tôi hình dung rằng việc hiển thị hình ảnh 8 trước khi hình 6 và 7 có thể tạo ra một số đồ tạo tác. Trong chủ đề người tiêu dùng, bạn phải đợi người tiêu dùng trước đó đã đăng hình ảnh của mình lên hàng đợi để đăng hình ảnh tiếp theo. Các nhiệm vụ có thể giúp ích rất nhiều cho điều đó vì tính mecanism đồng bộ vốn có của chúng.

2) Bạn cũng có thể gặp sự cố trong mã hiển thị.