3. Implementation
接下來將介紹我所作的事情,我將實作Color
histogram differences來偵測hard cut的 shot change。首先,我們先介紹這個algorithm的作法,如之前簡介過的,它偵測
cut 的原理是利用一個觀念 ”如果場景沒有變化的話,那麼現在的frame和下一個frame的顏色應該不會差太多”,因此我們就把影片一個一個frame抓進來,分別去算出每個frame的顏色分怖,接著兩兩相減看看,如果其顏色分布差超過一個threshold
則有可能為 cut ,而下面將介紹我所用的兩種方法:
◎法一 ( 訂定 threshold,合併相近的 ):
我們要如此做時就有個技巧,有時候說不定明明沒有換場景,只是因為頭轉個方向,所以臉上的顏色變暗了點,就以為顏色變化了,而判定有shot
change,就造成了誤判。所以我們為了讓它不要太過 "敏感",可以將顏色減少,本來一個 pixel 的顏色可以分成
RGB 三個顏色分別介於 0~255 之間,我們定義 0~63 之間是同一個顏色,64~127、128~191、192~255 也分別是一個顏色,所以原本
0~255 有 256種顏色,現在變成只有 4 種顏色了,也就是 R有4種、G也4種、B也4種,結論是我們重新定義的顏色將只有 64
色 (RGB分別4種, 4*4*4 =64)。
接著,當我們收到一個frame,分別去讀取該frame上的每一個pixel,看看他是什麼顏色,創一個 64 長度的array Color_count[64],代表那64色,讀到一個顏色,就把對應的array的值加一,也就是計算出這一個frame上,每一個顏色出現過幾次,儲存在
Color_count[64] 這個 array。每一個frame都分別計算自己的Color_count[64]值,接下來就可以算
CHD 值了:
for (i=2 ; i<=m_frame_no ; i++){
for (j=0 ; j<64
; j++){
CHD[i-1] += (float)abs(color_count1[j]-color_count2[j]) ;
}
CHD[i-1] = CHD[i-1]
/ (m_height * m_width);
} |
將1和2,2和3,… n 和 n+1 的frame分別兩兩相減,求出其 CHD值( 介於 0~1 間 ),並outpout出來,大概形如:
0.151681 1
0.108404 2
0.232221 3
0.255824 4
0.189063 5
0.259186 6
0.123816 7
0.130871 8
0.061435 9
0.012902 10
0.022348 11
0.028835 12
0.716193 13
0.840696 14
0.187263 15
0.027391 16
0.027628 17 |
例如 0.716193 13 就是說第 13 和第 14 frame 的 CHD 差距達到 0.716193 ,所以可見得 13和14
frame的顏色有很打大的差別,很有可能是場景變換了。既然有了一個影片的兩兩frame間的CHD值了,我們就可以試著去偵測 cut
了,首先我們必需要定出個 threshold 來判定超過該值的即為 cut,而這個threshold 將可由 try-and-error
來試著找出個較為理想的值。經由篩選過後,我們得到的結果類似下面:
737
740
742
743
744
1126
1495
1496
1567 |
我們發現有一個缺陷,那就是有時候會有許多很相近的frame,連續的被我們判定為 cut,然而在現實生活中的影片,除非是刻意做的特效,不然是不太可能會有連續的一直換畫面,因此我們應該要把相近的合起來,這一整塊是個gradual
shot change(漸漸的場景變化)。然而這也不太有用,因為如之前所說的,利用顏色變化將無法偵測 fade和 dissolve那種兩兩frame間差距不大的
shot change type,如果真的偵測出來了,也要是因為真的剛好它兩兩間的frame顏色有差到一個值,所以才被我們偵測出來。不管如何,由於畫面並不太可能在短時間內有那麼多連續的變化,我們還是要把他合成
gradual shot change,可以定義一個值,如果兩兩結果的差在這個值內,就可以合併。再經由進一步的處理後,可以得到形如下的結果:
<!DOCTYPE refSeg SYSTEM "shotBoundaryReferenceSegmentation.dtd">
<refSeg src=".mpg" creationMethod="MANUAL"
totalFNum="56718">
<trans type="GRAD" preFNum="351" postFNum="360"/>
<trans type="CUT" preFNum="371" postFNum="372"/>
<trans type="GRAD" preFNum="738" postFNum="745"/>
<trans type="CUT" preFNum="1126" postFNum="1127"/>
<trans type="GRAD" preFNum="1495" postFNum="1497"/>
<trans type="CUT" preFNum="1567" postFNum="1568"/>
<trans type="CUT" preFNum="2374" postFNum="2375"/>
<trans type="CUT" preFNum="2564" postFNum="2565"/>
<trans type="CUT" preFNum="2785" postFNum="2786"/>
<trans type="GRAD" preFNum="3216" postFNum="3218"/>
<trans type="CUT" preFNum="4311" postFNum="4312"/>
<trans type="CUT" preFNum="4745" postFNum="4746"/>
</refSeg> |
我們把他output 成 XML 的形式,因為等下將可利用 Trecvid 機構的sample影片以及標準答案來憑斷所做的結果(才有公信力),我採用的是Trecvid2003,並測試了其中
3 個影片。下圖為法一的流程: