![]() |
OpenCV 4.12.0
開源計算機視覺
|
上一教程: 使用GDAL讀取地理空間柵格檔案
下一教程: 使用OpenCV建立影片
| 原始作者 | Bernát Gábor |
| 相容性 | OpenCV >= 3.0 |
如今,擁有一個數字影片錄製系統是很常見的。因此,您最終會遇到不再批次處理影像,而是處理影片流的情況。這些影片流可能有兩種:即時影像饋送(網路攝像頭)或預錄製並存儲在硬碟驅動器上的檔案。幸運的是,OpenCV 以相同的方式處理這兩種情況,使用相同的 C++ 類。因此,您將在本教程中學到:
為了展示如何使用 OpenCV,我建立了一個小程式,它讀取兩個影片檔案並進行相似度檢查。您可以使用此程式來檢查新的影片壓縮演算法效果如何。這裡有一個參考(原始)影片,例如 這個小Megamind剪輯 和 它的壓縮版本。您還可以在 OpenCV 原始碼庫的 samples/data 資料夾中找到原始碼和這些影片檔案。
本質上,所有影片操作所需的功能都整合在 cv::VideoCapture C++ 類中。這本身是建立在 FFmpeg 開源庫之上的。這是 OpenCV 的基本依賴項,所以您無需擔心。影片由一系列影像組成,我們在文獻中將其稱為幀。對於影片檔案,有一個幀率,它指定兩幀之間的時間間隔。雖然影片攝像機通常每秒能數字化的幀數有限,但此屬性不太重要,因為攝像機在任何時候都能看到世界的當前快照。
您需要做的第一件事是為 cv::VideoCapture 類分配其源。您可以透過 cv::VideoCapture::VideoCapture 或其 cv::VideoCapture::open 函式來完成。如果此引數是整數,則您會將該類繫結到攝像機(裝置)。此處傳遞的數字是作業系統分配的裝置 ID。如果您的系統連線了一個攝像機,其 ID 可能是零,後續的則會遞增。如果傳遞給這些函式的引數是字串,它將引用一個影片檔案,字串指向檔案的位置和名稱。例如,對於上面的原始碼,一個有效的命令列是
我們進行相似度檢查。這需要一個參考影片檔案和一個測試用例影片檔案。前兩個引數指的是這個。這裡我們使用相對地址。這意味著應用程式將在其當前工作目錄中查詢並開啟影片資料夾,並嘗試在其中找到Megamind.avi和Megamind_bug.avi。
要檢查類與影片源的繫結是否成功,請使用 cv::VideoCapture::isOpened 函式
當物件解構函式被呼叫時,影片會自動關閉。但是,如果您想在此之前關閉它,您需要呼叫其 cv::VideoCapture::release 函式。影片的幀只是簡單的影像。因此,我們只需要將它們從 cv::VideoCapture 物件中提取出來,並放入一個 Mat 物件中。影片流是順序的。您可以使用 cv::VideoCapture::read 或過載的 >> 運算子來逐幀獲取它們
如果無法獲取幀(無論是影片流關閉還是到達影片檔案末尾),上述讀取操作將使 Mat 物件為空。我們可以透過一個簡單的 if 語句來檢查這一點
一個讀取方法由幀抓取和對其應用的解碼組成。您可以透過使用 cv::VideoCapture::grab 然後 cv::VideoCapture::retrieve 函式來顯式呼叫這兩個操作。
影片除了幀內容外,還附帶許多資訊。這些通常是數字,但在某些情況下可能是短字元序列(4位元組或更少)。因此,為了獲取這些資訊,有一個名為 cv::VideoCapture::get 的通用函式,它返回包含這些屬性的雙精度值。使用位操作從雙精度型別中解碼字元,並在有效值僅為整數時進行轉換。它的單個引數是查詢屬性的ID。例如,這裡我們獲取參考影片檔案和測試用例影片檔案中幀的大小;以及參考影片中的幀數。
當您處理影片時,您可能經常想自己控制這些值。為此,有一個 cv::VideoCapture::set 函式。它的第一個引數仍然是您要更改的屬性名稱,第二個引數是雙精度型別,包含要設定的值。如果成功則返回true,否則返回false。很好的例子是在影片檔案中跳轉到給定時間或幀
有關您可以讀取和更改的屬性,請檢視 cv::VideoCapture::get 和 cv::VideoCapture::set 函式的文件。
我們想要檢查影片轉換操作有多麼難以察覺,因此我們需要一個系統來逐幀檢查相似性或差異。最常用的演算法是 PSNR(也稱為峰值信噪比)。它最簡單的定義始於均方誤差。設有兩個影像:I1 和 I2;二維尺寸為 i 和 j,由 c 個通道組成。
\[MSE = \frac{1}{c*i*j} \sum{(I_1-I_2)^2}\]
然後 PSNR 表示為
\[PSNR = 10 \cdot \log_{10} \left( \frac{MAX_I^2}{MSE} \right)\]
這裡的 \(MAX_I\) 是畫素的最大有效值。對於每個通道每個畫素的簡單單位元組影像,這個值是 255。當兩幅影像相同時,MSE 將為零,導致 PSNR 公式中出現無效的除零操作。在這種情況下,PSNR 是未定義的,我們需要單獨處理這種情況。轉換為對數刻度是因為畫素值具有非常寬的動態範圍。所有這些轉換為 OpenCV 和一個函式看起來像:
對於影片壓縮,典型的結果值在 30 到 50 之間,越高越好。如果影像顯著不同,您會得到低得多的值,例如 15 等。這種相似性檢查計算簡單快速,但實際上可能與人眼感知不太一致。結構相似性演算法旨在糾正這一點。
描述這些方法遠遠超出了本教程的目的。為此,我邀請您閱讀介紹它的文章。儘管如此,透過檢視下面的 OpenCV 實現,您可以很好地瞭解它。
這將返回影像每個通道的相似度指數。該值介於零和一之間,其中一表示完美匹配。不幸的是,多次高斯模糊的開銷相當大,因此雖然 PSNR 可以在即時環境中(每秒 24 幀)工作,但要達到相似的效能結果,SSIM 需要顯著更多的時間。
因此,教程開頭提供的原始碼將對每一幀執行 PSNR 測量,而 SSIM 僅在 PSNR 低於輸入值時才執行。為了視覺化目的,我們在 OpenCV 視窗中顯示兩幅影像,並將 PSNR 和 MSSIM 值列印到控制檯。您應該會看到類似以下的內容:
您可以在此處的 YouTube 上觀看此程式的執行時例項。