所以,如果要做基於mjpeg的動態偵測
就需要去分析jpeg的結構,才能比較frame與frame之間的差異
如上圖所示,從傳統RGB raw data轉換成JPEG檔需要經過以上六個步驟
在 http://en.wikipedia.org/wiki/JPEG 裡面都有詳細的說明,在這裡我簡略的介紹一下
1. Color space transform
將RGB轉換到YCbCr的色彩空間,Y值代表的是亮度,CbCr代表的是藍色紅色的色度
2. Down sampling
由於人眼對於亮度的改變比色度還要敏感,所以我們可以技巧性減少色度的取樣
以有效減少資料量,down sampling之後的格式通常表示為 (J:a:b)
詳細的解說這邊有 http://www.dvworld.com.tw/forum/dvforum/showthread.php?threadid=78493
3. Block splitting
根據剛剛的J:a:b格式決定要切多大的block來當作一個Minimum Coded Unit(MCU)
例如4:2:2就是切一個16*8 pixel的長方形當作一個MCU
一個MCU是接下來步驟處理的最小單位
4. Discrete cosine transform
這是類似離散傅立葉轉換的一種變換 (其實我也不太懂 XD)
http://en.wikipedia.org/wiki/Discrete_cosine_transform
這裡所用的是Type II DCT,主要的功能是將一個block裡空間域的資料轉換到頻率域
在圖像裡面的意義是會將block中變動幅度較大、結構複雜的圖案資料都丟到高頻區
而變換平緩的則會集中在低頻區(←這我自己想像為這個block的代表值)
參考JPEG英文wiki就可以看到轉換得細節,總之,拿8*8 pixel的block來說
會產生一個低頻值在左上角(DC coefficient),還有其他63個高頻值(AC coefficients)
5. Quantization
這則是利用人眼對於低頻區的數值比較敏感,所以也要技巧性的減少高頻的資料量
這邊也是參考JPEG英文wiki就會有例子
6. Entropy encoding
由於經過Quantization後,高頻區會幾乎都是0,這意味著我們可以用huffman coding來
減少儲存的數據量
其中2、5是lossy compression,4、6是lossless compression
所以簡介完JPEG壓縮的步驟之後,回來我們的目標(動態偵測)來看
我們瞄準的是frame跟frame之間(對於人眼)的差異量,直覺來看就是亮度低頻值的差異量
=> Y值的DC coefficient變化量
所以要做的事就很簡單了,只要比較兩張frame上MCU上的Y值DC coefficient差異
就可以知道該MCU的變化量(是否色彩有改變)
這邊我拿了一個open source的jpeg decoder (http://sourceforge.net/projects/jpegdecoder/)
他的程式流程基本上就是把六個步驟反過來做,以得到raw picture
不過我們不用全部流程跑完,只要等他做完 entropy decoding跟 dequantization後就可以算出
Y值的DC coefficient (其實我覺得應該不用 dequantization吧? 反正只是差一個倍數)
最後就比較兩個frame之間每個MCU的差值,try出一組最適合的threshold
如果差值大於threshold就視為有動作發生
以下是成品的demo影片,我讓camera送出mjpeg stream
然後在pc端每兩個frame就比較所有MCU的差值,若超過threshold我就會在該MCU的位置
print 出 1,沒有超過的話就print出 .
影片中可以滿清楚的看到我用手比出1~10
最後,如果能夠把動態偵測跟錄影程式整合在一起,就可以在靜止畫面的時候
讓錄影程式不要將同一個frame一直寫入檔案,而是可以利用avi riff header裡面的idx1 table
新增一個table entry指向同一張frame來做到同樣的效果
比起存一張frame動輒需要幾KBytes,新增一個entry只需要16byte,實在差太多了

沒有留言:
張貼留言