W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
每當您使用視頻Feed時,您最終都可能想要以新的視頻文件的形式保存您的圖像處理結(jié)果。對于簡單的視頻輸出,您可以使用為此設(shè)計的OpenCV內(nèi)置cv :: VideoWriter類。
作為一個簡單的演示,我只需將一個輸入視頻文件的BGR顏色通道之一提取到一個新的視頻中。您可以從其控制臺行參數(shù)控制應(yīng)用程序的流量:
例如,有效的命令行將如下所示:
video-write.exe video/Megamind.avi R Y
您也可以在samples/cpp/tutorial_code/videoio/video-write/OpenCV源庫的文件夾中找到源代碼和這些視頻文件,或從這里下載。
#include <iostream> // for standard I/O
#include <string> // for strings
#include <opencv2/core.hpp> // Basic OpenCV structures (cv::Mat)
#include <opencv2/videoio.hpp> // Video write
using namespace std;
using namespace cv;
static void help()
{
cout
<< "------------------------------------------------------------------------------" << endl
<< "This program shows how to write video files." << endl
<< "You can extract the R or G or B color channel of the input video." << endl
<< "Usage:" << endl
<< "./video-write <input_video_name> [ R | G | B] [Y | N]" << endl
<< "------------------------------------------------------------------------------" << endl
<< endl;
}
int main(int argc, char *argv[])
{
help();
if (argc != 4)
{
cout << "Not enough parameters" << endl;
return -1;
}
const string source = argv[1]; // the source file name
const bool askOutputType = argv[3][0] =='Y'; // If false it will use the inputs codec type
VideoCapture inputVideo(source); // Open input
if (!inputVideo.isOpened())
{
cout << "Could not open the input video: " << source << endl;
return -1;
}
string::size_type pAt = source.find_last_of('.'); // Find extension point
const string NAME = source.substr(0, pAt) + argv[2][0] + ".avi"; // Form the new name with container
int ex = static_cast<int>(inputVideo.get(CAP_PROP_FOURCC)); // Get Codec Type- Int form
// Transform from int to char via Bitwise operators
char EXT[] = {(char)(ex & 0XFF) , (char)((ex & 0XFF00) >> 8),(char)((ex & 0XFF0000) >> 16),(char)((ex & 0XFF000000) >> 24), 0};
Size S = Size((int) inputVideo.get(CAP_PROP_FRAME_WIDTH), // Acquire input size
(int) inputVideo.get(CAP_PROP_FRAME_HEIGHT));
VideoWriter outputVideo; // Open the output
if (askOutputType)
outputVideo.open(NAME, ex=-1, inputVideo.get(CAP_PROP_FPS), S, true);
else
outputVideo.open(NAME, ex, inputVideo.get(CAP_PROP_FPS), S, true);
if (!outputVideo.isOpened())
{
cout << "Could not open the output video for write: " << source << endl;
return -1;
}
cout << "Input frame resolution: Width=" << S.width << " Height=" << S.height
<< " of nr#: " << inputVideo.get(CAP_PROP_FRAME_COUNT) << endl;
cout << "Input codec type: " << EXT << endl;
int channel = 2; // Select the channel to save
switch(argv[2][0])
{
case 'R' : channel = 2; break;
case 'G' : channel = 1; break;
case 'B' : channel = 0; break;
}
Mat src, res;
vector<Mat> spl;
for(;;) //Show the image captured in the window and repeat
{
inputVideo >> src; // read
if (src.empty()) break; // check if at end
split(src, spl); // process - extract only the correct channel
for (int i =0; i < 3; ++i)
if (i != channel)
spl[i] = Mat::zeros(S, spl[0].type());
merge(spl, res);
//outputVideo.write(res); //save or
outputVideo << res;
}
cout << "Finished writing" << endl;
return 0;
}
首先,您應(yīng)該了解視頻文件的外觀。每個視頻文件本身就是容器。容器的類型在文件擴展名(例如avi,mov或mkv)中表示。它包含多個元素,如:視頻饋送,音頻饋送或其他音軌(例如字幕)。這些饋送是如何存儲的由它們中的每一個使用的編解碼器決定。在音頻通道使用的編解碼器是mp3或aac的情況下。對于視頻文件,列表以某種方式更長,包括諸如XVID,DIVX,H264或LAGS(Lagarith Lossless Codec)。您可能在系統(tǒng)上使用的編解碼器的完整列表取決于您已安裝的編解碼器。
正如您可以看到的事情可能會讓視頻變得非常復雜。然而,OpenCV主要是一個計算機視覺庫,而不是視頻流,編解碼器和寫入。因此,開發(fā)人員試圖讓這部分盡可能的簡單。由于OpenCV視頻容器僅支持avi擴展,它的第一個版本。這樣做的一個直接的限制是您無法保存大于2 GB的視頻文件。此外,您只能創(chuàng)建和擴展容器內(nèi)的單個視頻軌道。沒有音頻或其他曲目編輯支持。不過,系統(tǒng)上存在的任何視頻編解碼器都可能正常工作 如果您遇到這些限制,您將需要查看更專門的視頻編寫庫,如FFMpeg或編解碼器,如HuffYUV,CorePNG和LCL。作為替代方案,使用OpenCV創(chuàng)建視頻軌道,并使用聲軌擴展,或通過使用視頻操作程序(如VirtualDub或AviSynth)將其轉(zhuǎn)換為其他格式。
這里寫的內(nèi)容建立在你已經(jīng)通過OpenCV讀取視頻輸入和相似度測量教程的假設(shè),你知道如何讀取視頻文件。要創(chuàng)建視頻文件,您只需要創(chuàng)建一個cv :: VideoWriter類的實例。您可以通過構(gòu)造函數(shù)中的參數(shù)或稍后通過cv :: VideoWriter :: open函數(shù)指定其屬性。無論哪種方式,參數(shù)是相同的:1.在其擴展名中包含容器類型的輸出的名稱。目前只支持avi。我們從輸入文件構(gòu)造這個,添加到要使用的通道的名稱,并使用容器擴展名完成它。
const string source = argv[1]; // the source file name
string::size_type pAt = source.find_last_of('.'); // Find extension point
const string NAME = source.substr(0, pAt) + argv[2][0] + ".avi"; // Form the new name with container
VideoCapture inputVideo(source); // Open input
int ex = static_cast<int>(inputVideo.get(CAP_PROP_FOURCC)); // Get Codec Type- Int form
OpenCV內(nèi)部使用這種整數(shù)類型,并期望它作為其第二個參數(shù)。現(xiàn)在要從整數(shù)形式轉(zhuǎn)換為字符串,我們可以使用兩種方法:一個按位運算符和一個聯(lián)合方法。第一個從int中提取字符看起來像(“和”操作,一些移動,并在結(jié)尾添加一個0以關(guān)閉字符串):
char EXT [] = {ex&0XFF,(ex&0XFF00)>> 8,(ex&0XFF0000)>> 16,(ex&0XFF000000)>> 24,0};
你可以和工會做同樣的事情:
union { int v; char c[5];} uEx ;
uEx.v = ex; // From Int to char via union
uEx.c[4]='\0';
這樣做的優(yōu)點是轉(zhuǎn)換在分配后自動完成,而對于按位運算符,您需要在更改編解碼器類型時執(zhí)行操作。如果事先知道編解碼器有四個字符代碼,可以使用CV_FOURCC宏構(gòu)建整數(shù):
CV_FOURCC('P','I','M,'1') // this is an MPEG1 codec from the characters to integer
如果您傳遞此參數(shù)減去一個而不是窗口將在運行時彈出,其中包含系統(tǒng)上安裝的所有編解碼器,并要求您選擇要使用的編解碼器:
VideoWriter outputVideo;
Size S = Size((int) inputVideo.get(CAP_PROP_FRAME_WIDTH), //Acquire input size
(int) inputVideo.get(CAP_PROP_FRAME_HEIGHT));
outputVideo.open(NAME , ex, inputVideo.get(CAP_PROP_FPS),S, true);
outputVideo.write(res); //or
outputVideo << res;
split(src, spl); // process - extract only the correct channel
for( int i =0; i < 3; ++i)
if (i != channel)
spl[i] = Mat::zeros(S, spl[0].type());
merge(spl, res);
把所有這一切放在一起,你會得到更高的源代碼,其運行時結(jié)果將顯示如下圖像:
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: