W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
每當(dāng)您使用視頻Feed時(shí),您最終都可能想要以新的視頻文件的形式保存您的圖像處理結(jié)果。對于簡單的視頻輸出,您可以使用為此設(shè)計(jì)的OpenCV內(nèi)置cv :: VideoWriter類。
作為一個(gè)簡單的演示,我只需將一個(gè)輸入視頻文件的BGR顏色通道之一提取到一個(gè)新的視頻中。您可以從其控制臺行參數(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)該了解視頻文件的外觀。每個(gè)視頻文件本身就是容器。容器的類型在文件擴(kuò)展名(例如avi,mov或mkv)中表示。它包含多個(gè)元素,如:視頻饋送,音頻饋送或其他音軌(例如字幕)。這些饋送是如何存儲的由它們中的每一個(gè)使用的編解碼器決定。在音頻通道使用的編解碼器是mp3或aac的情況下。對于視頻文件,列表以某種方式更長,包括諸如XVID,DIVX,H264或LAGS(Lagarith Lossless Codec)。您可能在系統(tǒng)上使用的編解碼器的完整列表取決于您已安裝的編解碼器。
正如您可以看到的事情可能會讓視頻變得非常復(fù)雜。然而,OpenCV主要是一個(gè)計(jì)算機(jī)視覺庫,而不是視頻流,編解碼器和寫入。因此,開發(fā)人員試圖讓這部分盡可能的簡單。由于OpenCV視頻容器僅支持avi擴(kuò)展,它的第一個(gè)版本。這樣做的一個(gè)直接的限制是您無法保存大于2 GB的視頻文件。此外,您只能創(chuàng)建和擴(kuò)展容器內(nèi)的單個(gè)視頻軌道。沒有音頻或其他曲目編輯支持。不過,系統(tǒng)上存在的任何視頻編解碼器都可能正常工作 如果您遇到這些限制,您將需要查看更專門的視頻編寫庫,如FFMpeg或編解碼器,如HuffYUV,CorePNG和LCL。作為替代方案,使用OpenCV創(chuàng)建視頻軌道,并使用聲軌擴(kuò)展,或通過使用視頻操作程序(如VirtualDub或AviSynth)將其轉(zhuǎn)換為其他格式。
這里寫的內(nèi)容建立在你已經(jīng)通過OpenCV讀取視頻輸入和相似度測量教程的假設(shè),你知道如何讀取視頻文件。要?jiǎng)?chuàng)建視頻文件,您只需要?jiǎng)?chuàng)建一個(gè)cv :: VideoWriter類的實(shí)例。您可以通過構(gòu)造函數(shù)中的參數(shù)或稍后通過cv :: VideoWriter :: open函數(shù)指定其屬性。無論哪種方式,參數(shù)是相同的:1.在其擴(kuò)展名中包含容器類型的輸出的名稱。目前只支持avi。我們從輸入文件構(gòu)造這個(gè),添加到要使用的通道的名稱,并使用容器擴(kuò)展名完成它。
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ù)類型,并期望它作為其第二個(gè)參數(shù)?,F(xiàn)在要從整數(shù)形式轉(zhuǎn)換為字符串,我們可以使用兩種方法:一個(gè)按位運(yùn)算符和一個(gè)聯(lián)合方法。第一個(gè)從int中提取字符看起來像(“和”操作,一些移動,并在結(jié)尾添加一個(gè)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)點(diǎn)是轉(zhuǎn)換在分配后自動完成,而對于按位運(yùn)算符,您需要在更改編解碼器類型時(shí)執(zhí)行操作。如果事先知道編解碼器有四個(gè)字符代碼,可以使用CV_FOURCC宏構(gòu)建整數(shù):
CV_FOURCC('P','I','M,'1') // this is an MPEG1 codec from the characters to integer
如果您傳遞此參數(shù)減去一個(gè)而不是窗口將在運(yùn)行時(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);
把所有這一切放在一起,你會得到更高的源代碼,其運(yùn)行時(shí)結(jié)果將顯示如下圖像:
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: