2013-04-17 63 views
8

我目前正在使用AForge,並有一個新的幀事件,將幀作爲位圖發佈到picturebox中。 90%的工作時間很棒......除非我在winform上撥弄一些東西。更改組合框,移動窗口,或類似的東西的風險導致在PictureBox從視頻切換到下面一個大紅色的X代碼示例:Picturebox變得大紅X但我無法檢測或修復它

private void connectButton_Click(object sender, EventArgs e) 
    { 
     try 
     { 
      cam = new VideoCaptureDevice(captureDevices[CameraSelectComboBox.SelectedIndex].MonikerString); 
      cam.NewFrame -= Handle_New_Frame; //Just to avoid the possibility of a second event handler being put on 
      cam.NewFrame += new AForge.Video.NewFrameEventHandler(Handle_New_Frame); 
      cam.Start(); 
     } 
     catch 
     { 
      MessageBox.Show("An error has occured with connecting to the specified webcam. The application will now close!"); 
      Application.Exit(); 
     } 
    } 

    private void Handle_New_Frame(object sender, NewFrameEventArgs eventArgs) 
    { 

     try 
     { 
      if (bitmap != null) 
       bitmap.Dispose(); //Without this, memory goes nuts 
      bitmap = new Bitmap(eventArgs.Frame); 
     } 
     catch { } 

     //Draw some stuff on the images 
     bitmap = AdjustBrightness(bitmap, brightnessMeter); 
     bitmap = ApplyContrast(contrastMeter, bitmap); 
     bitmap = Draw_Top_Line(bitmap); 
     bitmap = Draw_Bottom_Line(bitmap); 

     //Set the image into the picturebox 
     this.Invoke((MethodInvoker)delegate 
     { 
      videoPictureBox1.Image = bitmap; 
      frameRate++; //Keep track of the frame rate 
     }); 

     GC.Collect(); //Without this, memory goes nuts 

     this.Invoke((MethodInvoker)delegate { 
      videoPictureBox1.Refresh(); //NOT NECESSARY. JUST TRYING TO FIX THE BIG RED X! 
     }); 

     if (videoPictureBox1.Image == videoPictureBox1.ErrorImage) 
     { 
      cam.Stop(); //ALSO NOT NECESSARY> AGAIN, JUST TRYING TO FIX THE BIG RED X! 
      cam.Start(); 
     } 
    } 

我把休息的,如果(videoPictureBox1.Image == videoPictureBox1.ErrorImage),並且它正在計算爲false,即使當大紅色X啓動時,因爲圖像實際上被設置爲位圖。所以cam.Stop()和cam.Start()永遠不會運行(不知道這是否會幫助,但我想我會試試看)。

videoPictureBox1.Refresh()每次都在運行,但再次 - 它沒有區別。仍然有大紅色的X.

正如我之前所說:如果我開始播放視頻並且什麼都不碰,大紅色的X將永遠不會發生。但是,當我開始更換組合框,或拖動表單本身時,大紅色X的機會呈指數級增長。有時候我可以在組合框中翻轉10到12次,其他時候我會點擊組合框。 : - \

任何人都可以解釋這裏發生了什麼,也許提供了一個建議最好的方法來解決它?我對線程仍然很陌生,所以我一直在努力將自己的頭腦圍繞到這裏發生的事情以及解決問題的最佳方式!任何向正確的方向推動將是一個巨大的幫助!

+1

我想我可能只是沒有使用圖片框。改爲使用面板並在面板的繪製事件中繪製位圖。用invalidate強制刷新。 –

+0

在大紅色的XSenario期間,你看過eventArgs.Frame嗎?此外,我會將該消息框放在該異常下,以防發生錯誤。 – TheKingDave

+0

好的,我會盡快給你一個嘗試! 附加的註釋:我去調試 - >異常,並檢查所有的「時拋出」複選框。發生這種情況時什麼也不拋出。完全一樣。 –

回答

6

最後,我在一個invoke包裹在Handle_New_Frame一切。它徹底消除了大紅X的問題,永久。 > _>

private void Handle_New_Frame(object sender, NewFrameEventArgs eventArgs) 
{ 
    this.Invoke((MethodInvoker)delegate 
    { 
    try 
    { 
     if (bitmap != null) 
     { 
      bitmap.Dispose(); //Without this, memory goes nuts 
     } 

     bitmap = new Bitmap(eventArgs.Frame); 
    } 
    catch { } 

    //Draw some stuff on the images 
    bitmap = AdjustBrightness(bitmap, brightnessMeter); 
    bitmap = ApplyContrast(contrastMeter, bitmap); 
    bitmap = Draw_Top_Line(bitmap); 
    bitmap = Draw_Bottom_Line(bitmap); 

    //Set the image into the picturebox 
    this.Invoke((MethodInvoker)delegate 
    { 
     videoPictureBox1.Image = bitmap; 
     frameRate++; //Keep track of the frame rate 
    }); 

    GC.Collect(); //Without this, memory goes nuts 
    }); 
} 
+0

我遇到了同樣的事情,並試圖弄清楚發生了什麼事情,但沒有用。我猜想它是一些單線程策略,但是因爲我無法獲得任何例外或錯誤消息,所以我採用了您的方法,現在它可以工作。 –

+0

您好,我用它,但是當我嘗試關閉videoSource它不牛逼駐足停留等待釋放資源......你有同樣的問題? – elle0087

1

嘗試在您使用位圖的地方使用克隆。

videoPictureBox1.Image = (Bitmap)bitmap.Clone(); 
+0

這也可能導致競爭條件還是我錯了?如果處置重繪位圖和克隆位圖,然後大紅色的X將現身之間發生。 – Hans

+0

@Hans是的,請嘗試使用位圖處置()之前 – Rsouza

+0

@Hans你能請在我的答案代碼?我想產生這樣的比賽條件,但無法。 –

3

肖恩哈格里夫斯有 「末日大紅色的X」 的優秀,簡潔writeup。我發現它在處理突然顯示紅色「X」的WinForm組件的一般情況下非常有幫助。

總結:

  • 這是通過一個控制拋出異常出OnPaint事件引起的。
  • 一旦拋出,該控件將繼續顯示紅色的X,跳過射擊OnPaint.
  • 要調試,設置調試器來捕捉公共語言運行庫異常,然後做你通常做的就是紅色的X.調試器將停止它發生的地方,讓你調查,並希望找出一種方法來防止它。
0

總而言之,這是一個經過測試的極小值,即使在調整大小,開始,停止或分辨率改變時,也不會顯示出紅叉。

public partial class PictureBoxVideo : Form 
    { 
     public PictureBoxVideo() 
     { 
     InitializeComponent(); 
     var videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice); 
     var videoSource = new VideoCaptureDevice(videoDevices[0].MonikerString); 
     videoSource.NewFrame += Handle_Very_New_Frame; 
     videoSource.Start(); 
     } 

     private void Handle_Very_New_Frame(object sender, NewFrameEventArgs eventArgs) 
     { 
     this.Invoke((MethodInvoker)delegate { 
      pictureBox.Image = new Bitmap(eventArgs.Frame); 
     }); 
     } 
    } 

請注意,我們稱之爲videoSource.Start();從GUI-(創建)線程,但回調處理程序(Handle_Very_New_Frame)從視頻(worker)線程中調用。

我想這就是爲什麼我們需要兩者的調用和新的位圖,因此,新的BMP也會從GUI線程產生。但我只是在這裏猜測,因爲我不能拿出一個證明。

+0

BTW:我很快放棄了這種做法的原因很明顯:-) –

+0

您好,我用它,但是當我嘗試關閉videoSource它不牛逼駐足停留等待釋放資源......你有同樣的問題? – elle0087

相關問題