最近在撰寫IP Camera程式讀取時,
發生一些以前沒注意的細節。
(1) 跨執行緒問題
下面是一個常見的onFrameGrabbed事件的寫法,
使用者將接收到的 Image直接顯示在captureImageBox上
private void DispOnCaptureImageBox(Mat image)
{
captureImageBox.Image = image;
}
跨執行緒的錯誤很神奇絕大部分時間可以安然執行,不過運氣不好時就會出錯,
但這種錯誤很難察覺,甚至官方的範例也是用上面的作法,所以我並不孤單!?
C#Control元件可以直接檢查目前運行是否和GUI主執行緒相同,
captureImageBox.InvokeRequired如果回傳是,那就得乖乖使用非同步執行
(2) 影像處理函式是否來得及完成?
如果將影像處理程序直接嵌入onFrameGrabbed,聽起來很直覺!
但仔細想想,當FPS (frames per second)等於25張,
其每張擷取影像的間隔時間大約40毫秒;
萬一影像處理時間超過40ms,會阻塞讀取IPCAMERA影像的程序。
當本地端PC讀取的系統時間和遠端的IPCAMERA的系統時間超過一定秒數(大約15~30秒),
為了同步遠端IPCAMERA的資訊,通常會直接略過時間差異過大的影像,
IPCAMERA會直接從最新的影像繼續傳給本地端。
換句話說,中間可能為少了15~30秒的影像資訊。
如果在意不跳格,可以考慮將接收到的影像放入一個容器堆疊(記憶體),由另一個執行緒來pop影像。
但須留意是堆疊的影像不可能無限堆疊,很有可能累積超過1000張還是會爆炸,
因此若累積張數超過一定數量,看是要放置到檔案(硬碟)暫存或是丟棄最舊的(記憶體)。
(3) 看們狗(watchdog)的機制
這次使用攝影機規格是500MB像素,每秒25張,如果將接收到的影像全部繪製顯示在GUI,
會發生類似上述第二點的狀況,onFrameGrabbed直接停擺,發生時機是隨機產生。此外,
由於try-catch機制是放在onFrameGrabbed內因此無法捕捉到外部發生的錯誤!
為了處理這棘手的問題,我花了一些時間嘗試下面開發套件,如果單純想撥放IPCAMERA
建議可以直接使用LibVLCSharp,其好處是CPU耗能少,但缺點是如果要擷取影像得自己寫不少程式,
其範例建立在WPF框架,因此如果不熟悉WPF可能會蠻吃力。
1. Vlc.DotNet
沒有開啟說明文件就直接上, 結果遇到問題才知道這個專案已經死了,給我上了一課。
2. LibVLCSharp
3. Vlc.DotNet
執行效率異常的緩慢,FPS大概1左右
根目錄記得置放ffmpeg.exe, 因為主程式會呼叫使用
===========================================================
(4) 是否為即時顯示,時間延遲可能超過你想像
IPCAMERA在一般應用場景並非即時顯示,最簡單的方式是用手在攝影機前面晃一下,
觀察幾秒後收到訊息,如果想要接收到即時影像,通常得跳下去調整參數(水很深)
預設通常會延遲幾秒鐘。