一、介紹
視頻讀取本質上就是讀取圖像,因為視頻是由一幀一幀圖像組成的。1秒24幀基本就能流暢的讀取視頻了。
①讀取視頻有兩種方法:
A. VideoCapture cap;
cap.open(“1.avi”);
B. VideoCapture cap(“1.avi”);
②循環顯示每一幀:
while(1)
{
Mat frame; //定義Mat變量,用來存儲每一幀
cap>>frame; //讀取當前幀方法一
//cap.read(frame); //讀取當前幀方法二
imshow(“視頻顯示”, frame); //顯示一幀畫面
waitKey(30); //延時30ms
}
二、讀取視頻示例程序
1 #include<opencv2/opencv.hpp> 2 using namespace cv; 3 4 void main(){ 5 VideoCapture cap; 6 cap.open("E://2.avi"); //打開視頻,以上兩句等價於VideoCapture cap("E://2.avi"); 7 8 //cap.open("http://www.laganiere.name/bike.avi");//也可以直接從網頁中獲取圖片,前提是網頁有視頻,以及網速夠快 9 if(!cap.isOpened())//如果視頻不能正常打開則返回 10 return; 11 Mat frame; 12 while(1) 13 { 14 cap>>frame;//等價於cap.read(frame); 15 if(frame.empty())//如果某幀為空則退出循環 16 break; 17 imshow("video", frame); 18 waitKey(20);//每幀延時20毫秒 19 } 20 cap.release();//釋放資源 21 }
三、讀取視頻說明
- 打開的視頻可以是本地視頻如:
VideoCapture cap(“1.avi”);
也可以是網絡視頻如:
VideoCapture cap(“http://www.laganiere.name/bike.avi“); - 讀取視頻一定要加異常判斷
A.打開視頻失敗(各種原因)
B. 取幀失敗異常(程序結尾判斷)
ex1:
if(!cap.isOpened()) //檢查打開是否成功
return;
ex2:
cap>>frame;
if(!frame.empty()) //判斷當前 幀是否為空
{
imshow(“video”, frame);
waitKey(30);
}
else break;
四、獲取指定視頻類的相關參數信息
1 #include<opencv2/opencv.hpp> 2 #include<iostream> 3 using namespace cv; 4 using namespace std; 5 6 void main(){ 7 VideoCapture cap; 8 cap.open("E:\\2.avi"); //打開視頻,等價於 VideoCapture cap("E://2.avi"); 9 10 if(!cap.isOpened()) 11 return; 12 13 int width = cap.get(CV_CAP_PROP_FRAME_WIDTH); //幀寬度 14 int height = cap.get(CV_CAP_PROP_FRAME_HEIGHT); //幀高度 15 int frameRate = cap.get(CV_CAP_PROP_FPS); //幀率 x frames/s 16 int totalFrames = cap.get(CV_CAP_PROP_FRAME_COUNT); //總幀數 17 18 cout<<"視頻寬度="<<width<<endl; 19 cout<<"視頻高度="<<height<<endl; 20 cout<<"視頻總幀數="<<totalFrames<<endl; 21 cout<<"幀率="<<frameRate<<endl; 22 23 Mat frame; 24 while(1) 25 { 26 cap>>frame;//等價於cap.read(frame); 27 if(frame.empty()) 28 break; 29 imshow("video", frame); 30 if(waitKey(20)>0) 31 break; 32 } 33 cap.release(); 34 }
五、讀取攝像頭
讀取攝像頭和讀取視頻大同小異,主要是這句代碼有些許不同。
VideoCapture cap;
cap.open(0);
讀取視頻時可以傳入視頻路徑,而讀取攝像頭傳入的是index索引號。
注:
1)如果默認筆記本/台式機只有一個USB攝像頭,Index=0; 如果有2個,一般Index為0和1,根據具體情況區分,攝像頭接入和斷開會改變Index值
2)如果接入2個以上,但只想用指定的一個,可以在設備管理器中禁用其他,同時Index設置為0
3)因為開啟攝像頭后一直在進行讀取,所以需要用waitKey()返回值判斷退出預覽
imshow(“video”, frame);
if(waitKey(30)>0)//無按鍵按下返回-1,按鍵按下時退出
break;
也可以指定按鍵退出:
if(waitKey(30)==27) //Esc鍵退出,ESC的ASCLL碼為27
break;
六、讀取攝像頭后加入簡單處理效果
如果只是讀取攝像頭不進行處理的話,那毫無意義,現在以canny邊緣檢測以及顏色空間轉換為目標進行處理。
1 #include<opencv2/opencv.hpp> 2 using namespace cv; 3 4 void main(){ 5 VideoCapture cap; 6 cap.open(0); //打開攝像頭 7 8 if(!cap.isOpened()) 9 return; 10 11 Mat frame; 12 while(1) 13 { 14 cap>>frame;//等價於cap.read(frame); 15 Canny(frame, frame, 30, 100);//canny邊緣檢測,去掉這一行就是純粹的讀取攝像頭了 16 //cvtColor(frame, frame, CV_BGR2HSV);//BGR空間轉為HSV顏色空間,注意,兩者不能同時對同一張圖片(在此為frame)進行處理,否則報錯 17 if(frame.empty()) 18 break; 19 imshow("video", frame); 20 if(waitKey(20)>0)//按下任意鍵退出攝像頭 因電腦環境而異,有的電腦可能會出現一閃而過的情況 21 break; 22 } 23 cap.release(); 24 destroyAllWindows();//關閉所有窗口 25 }
針對第20行代碼:最開始電腦配置的opencv2.x版本,上述代碼打開攝像頭沒有問題;后來使用opencv3.x版本,重新編譯了contrib包,發現攝像頭打開后一閃而過。
原因是 waitkey() 如果不按鍵的時候是返回 oxff,oxff無符號時是255,有符號時是-1。windows vs 的環境默認了這個為非符號數 即255,而opencv的有些配置環境中是-1。
解決方案:把原始代碼中循環讀取幀的
if (waitKey(20)>=0) break;
改為
if (waitKey(20) != 255) break;
或者把waitkey的返回值用有符號數去讀取。
uchar c=waitkey(20); if(c!=255) break;
七、寫入視頻
1、介紹
①VideoWriter: OpenCV提供VideoWriter類寫視頻文件,類的構造函數可以指定文件名、播放幀率、幀尺寸、是否創建彩色視頻。
②兩種寫入幀方法:
1 ) writer.write(frame);
2)writer >>frame(這里的箭頭方向應該相反,不知道為什么箭頭不能向←);
③注意事項:
1)寫入視頻前需安裝對應的編解碼器
2)生成視頻是否支持彩色應與構造函數設置一致
3)生成視頻尺寸需與讀取視頻尺寸一致
2、代碼示例
1 #include<opencv2/opencv.hpp> 2 #include<iostream> 3 using namespace cv; 4 using namespace std; 5 6 void main(){ 7 VideoCapture cap; 8 cap.open("E://2.avi"); 9 Size size0=Size(cap.get(CV_CAP_PROP_FRAME_WIDTH),cap.get(CV_CAP_PROP_FRAME_HEIGHT)); 10 VideoWriter writer("E://out.avi",-1,cap.get(CV_CAP_PROP_FPS),size0,false); 11 12 if(!cap.isOpened()) 13 return; 14 15 Mat frame; 16 while(1) 17 { 18 cap>>frame; 19 Canny(frame,frame,30,100); 20 if(frame.empty()) 21 break; 22 writer<<frame;//等同於writer.write(frame); 23 imshow("video", frame); 24 if(waitKey(10)>0) 25 break; 26 } 27 cout<<"write end!"; 28 cap.release(); 29 destroyAllWindows(); 30 }