視訊鏡頭分割與關鍵幀提取

1. Project Introduction

(1) 選題

視訊鏡頭邊緣檢測與鏡頭內關鍵幀提取

(2) 工作簡介

視訊逐幀進行直方圖繪製並按照X2X^2做差
根據當前幀所處環境進行自適應閾值防縮得到鏡頭邊緣幀
優化鏡頭邊緣幀
進行自適應關鍵幀提取

(3) 開發環境

c opencv3.3.1

2. Technical Detailss

(1) 理論知識

邊緣檢測

基於直方圖差異進行邊緣檢測,差異越大的幀越有可能是鏡頭邊界處,且使用直方圖的方法可以很好的避免鏡頭內物件運動而造成的差異,提高一定魯棒性。同時演算法應該兼顧幾個方面的問題。
相鄰兩個鏡頭邊緣不應該太靠近
鏡頭邊緣幀與前一幀的差值應該是當前鏡頭所有幀差值中最大的
鏡頭邊緣幀與前一幀的差值應該普遍大於該鏡頭中所有幀的平均差值的倍數
下一個鏡頭中,靠近這個鏡頭的部分的兩幀之間的差值不應該出現明顯大於這個鏡頭邊緣幀與前一幀的差值的情況

關鍵幀提取

動態進行關鍵幀提取,不應該根據當前鏡頭的長短而應該根據當前鏡頭的變化劇烈程度,當前鏡頭變化越劇烈,則應該提取越多的關鍵幀,即便當前鏡頭並不長。相反,即便是一段很長的鏡頭,如果畫面基本沒變,我們也應該提取較少的關鍵幀。
如果當前鏡頭畫面為全黑,我們不應該提取任何關鍵幀。

(2) 具體演算法

  • 對於每一幀我們用以下結構儲存
struct m_frame {
int index_frame;
float distance;//與上一幀的差值
bool M;//是否有可能是鏡頭分界幀
bool KeyFrame;//是否是關鍵幀
};
//定義最小鏡頭長度
#define m_MinLengthOfShot 4

鏡頭邊緣檢測

計算幀與幀之間的差值
  • 直方圖差異利用如下公式計算
    X2=⎧⎩⎨⎪⎪∑ki=1(hm(i)−hn(i))2max(hm(i),hn(i)),(hm(i)!=0||hn(i)!=0)0,elseX^2=\begin{equation} \begin{cases} \sum_{i=1}^k \dfrac{(h_m(i)-h_n(i))^2}{max(h_m(i),h_n(i))}, (h_m(i)!= 0||h_n(i)!=0) \\ 0,else \end{cases} \end{equation}
    將差值儲存在結構中
m_frame::distance=X^2
三次篩選進行自適應閾值的邊界幀的判斷
  • 對於鏡頭邊界幀的選取,我們進行了三次篩選:
    • (1) 製作一個大小為10幀的視窗,步長為8,所以視窗重疊次數為2。我們尋找視窗內distance最大的幀定義為可能的MM幀,並判斷它距離上一個MM幀的距離。如果距離小於m_MinLengthOfShot(最小鏡頭長度),我們取消它的MM幀資格,否則它是一個新的MM幀。
    • (2)進一步判斷MM是否是邊緣幀。我們計算兩個M幀之間幀的distance的平均值,並判斷MM幀是否遠大於這個平均值,這裡選擇的thresholdthreshold為6,即,當且僅當MM幀的distance大於平均值的6倍,才得以保留。經過了這一步,已經能得到基本合理的鏡頭邊緣了。
    • (3) 進一步優化鏡頭邊緣。判斷該MM幀後的小區間內是否有比MM幀更合適的幀。方法如下:
      1. 從MM幀開始,往後尋找8幀中的最大幀,若最大幀的distance小於MM,則M幀得以保留。否則進行下一步
      2. 若存在大於MM幀的幀,我們將其命名為PP
      3. 計算MM和PP之間幀distance的平均值
      4. 判斷PP是否大於平均值的倍數,若沒有大於,則M得以保留,否則P為新的M幀,並接下來繼續判斷。

選擇了其中一次篩選的函式的一部分:

//1. 從M幀開始,往後找8幀,如果沒有比M更大的,則M得以倖存
//2. 若有,為P,則判斷P是否大於M和P之間的數的平均值的閾值倍數,若並沒有大於,則M得以倖存,否則,P為新的M
//3. 我們緊接著找下一個M,直到到末尾
void m_ThirdDelete(m_frame* temp) {
while (true) {
//首先找到下一個M的座標
for ( i = index_M 1; i < m_TestFrameNum; i  ) {
......
}
//如果沒找到呢?
if (i >= m_TestFrameNum)break;
//找到後續間隔最大值及對應的P幀
float max_behindinterval = temp[index_M].distance;
int index_P = index_M;
//找到往後數視窗間隔個數的最大值或者到最後一位的最大值
for (int i = index_M; i < index_M m_WindowInterval&&i<m_TestFrameNum; i  ) {
......
}
//如果沒有大於M的,則M得以倖存
//else 計算M和P幀的平均值
{
......
//P幀就在M幀的後一個,那M幀就掛了
if (sum == 0) {
......
}
else {
//如果P幀大於平均值的閾值倍,M幀也掛了
if (temp[index_P].distance > average*m_threshold) {
......
}
//如果P沒有大於平均值的閾值倍,M得以倖存
else {
}
}
}
}
}

鏡頭內關鍵幀提取

我們根據鏡頭內幀的變化程度來確定關鍵幀的數量。
1. 首先計算所有鏡頭內的幀的平均distance
2. 找出鏡頭內幀的distance大於平均值的倍數的幀
3. 如果沒有這樣的幀,則證明該鏡頭變化過於平緩,我們選擇鏡頭的中間幀
4. 排除亮度過於黑暗的幀

    while (true) {
float sum = 0;
int i = lastM   1;
//先統計在兩個鏡頭邊緣所有幀差別的平均值
......  
float average = sum / (i - lastM - 1);
bool isFlappy = true;
//如果期間幀變化挺快的,那麼我們儲存變化最快的幾個位置
......
//如果兩個幀之間幾乎沒有變化,則取兩幀的中間值
......
}
//刪除那些顏色過暗的
for (int i = 0; i < m_TestFrameNum; i  ) {
if (temp[i].KeyFrame == true) {
float sum = mean(m_FrameImg[i])[0];
if (sum < 5)temp[i].KeyFrame = false;
}
}

Experiment Results

復仇者聯盟預告片

鏡頭(基本令人滿意)

該視訊鏡頭共有:56個
誤判的鏡頭有:7個(因為全黑的過場也被判定成了一個鏡頭)

提取關鍵幀的時候對全黑的鏡頭有所判定,於是實際上基本沒有誤判鏡頭

沒判到的鏡頭有:2個

關鍵幀(效果很不錯)

鏡頭中本該存在關鍵幀(即鏡頭不是全黑的過場),但是沒有提取到的有:0個鏡頭
關鍵幀存在的問題是:對於明暗變化明顯的鏡頭,關鍵幀提取偏多
比如:
這裡寫圖片描述
這裡寫圖片描述

但是這種結果並不是完全不可行
例如:
這裡寫圖片描述

這裡寫圖片描述

這些漫畫雖然被算作一個鏡頭,但是理應有多個關鍵幀才能表達這個鏡頭的含義。
檔案截圖:

可以看出結果還是很令人滿意的

下劃線前面的數字代表其屬於第幾個鏡頭,後面的數字代表它在視訊第幾幀
這裡寫圖片描述

  • References:
    《基於視窗最大值和自適應閾值的視訊鏡頭分割演算法》 劉佳兵 《福建電腦雜誌》2007年第8期
    《鏡頭邊界檢測及關鍵幀提取》 譚楓 哈爾濱工程大學