OpenCv影像處理之影像視頻攝像頭讀取與保存
- 使用cv::imread()讀取圖片
- 使用cv::imwrite()存盤圖片
- 使用cv::VideoCapture::open()讀取視頻
- 使用cv::VideoWriter::write()存盤視頻
- 使用cv::VideoCapture讀取攝像頭
- 使用互斥量、鎖、多執行緒進行資料讀取和顯示
使用cv::imread()讀取圖片
經過上一節的學習,我們了解到opencv處理的圖片其實就是對矩陣進行操作,使用cv::imread()
對圖片進行讀取并回傳一個矩陣,來看一個例子:
#include <iostream>
#include <opencv2/highgui.hpp>
using namespace std;
int main() {
//imread(const String &filedir,int flags)
cv::Mat img = cv::imread("D:/null.jpg", 1);
//另一種判空的寫法:img.data == NULL;
if (img.empty()) {
cout << "open the file failed!" << endl;
}
cv::Mat gray_img = cv::imread("D:/cat.jpg", 0);
if (!gray_img.empty()) {
cv::imshow("gray_img", gray_img);
cv::waitKey(0);
}
cv::Mat nochange_img = cv::imread("D:/cat.jpg", -1);
if (!nochange_img.empty()) {
cv::imshow("no_chang", nochange_img);
cv::waitKey(0);
}
return 0;
}
效果顯示
open the file failed!
上述代碼展示了讀取圖片的三種不同的狀態,這個狀態由flags引數決定,flags=1(>0)
表示函式需要回傳三通道影像,若圖片不是三通道則強制轉成3通道.flags=0
表示函式回傳單通道影像,若圖片是多通道圖片則強制轉成單通道.flags=-1(<0)
表示不對影像進行通道轉換處理.imread()支持影像格式:jpg,jpeg,dib,bmp,png,pbm,ppm,sr,ras,tiff,exr,jp2
使用cv::imwrite()存盤圖片
上面我們學習了如何讀取指定路徑下的圖片,接下來來看一下如何將處理過的圖片進行指定存盤.
#include <iostream>
#include <opencv2/highgui.hpp>
using namespace std;
using namespace cv;
int main() {
Mat mat = imread("D:/cat.jpg", 1);
if (!mat.empty()) {
//Rect(x,y,width,height)
Mat roi(mat, Rect(200, 200, 400, 500));
//bool imwrite(const String &filedir,InputArray img)
//imwrite("D:/cat_roi_write.jpg", roi);
//imwrite("D:/cat_roi_write.bmp", roi);
bool is_write = imwrite("D:/cat_roi_write.png", roi);
cout << "write is succeed?:" << is_write << endl;
} else {
cerr << "openfile is failed" << endl;
}
return 0;
}
效果顯示
write is succeed?:1
png
是無損圖片
jpg
是壓縮成的有損圖片
bmp
是不壓縮的無損圖片,大小較大
注意并不是所有Mat物件都能存盤為圖片,一般來說只有8U型別的單通道和3通道矩陣可以進行影像存盤,若需要保存成16U型別的圖片,則只能使用png,jpeg 2000,tiff格式進行存盤.
為了將其他格式的矩陣保存為圖片,opencv提供了Mat::convertTo(),從v::cvtColor()
能夠將矩陣轉換為能夠保存的型別格式,若指定目錄下已經存在要保存的檔案,則會對其進行覆寫.(其中cvtColor()是cv類的成員函式,需要宣告頭檔案#include<opencv2/opencv.hpp>)
使用cv::VideoCapture::open()讀取視頻
VideoCapture既可以從視頻檔案讀取影像,也可以從攝像頭中讀取影像.使用VideoCapture::open()打開.
#include <iostream>
#include <opencv2/highgui.hpp>
using namespace std;
using namespace cv;
int main() {
VideoCapture capture;
Mat frame;
frame = capture.open("D:/test_video.mp4");
if (!capture.isOpened()) {
cout << "this video can not open" << endl;
return -1;
} else {
cout << "video is successful open=" << capture.isOpened() << endl;
}
//視窗大小自適應,靈活調整,寫在cv::imshow()之前,防止圖片尺寸太大imshow顯示不全,注意名字和imshow相同,不然可能會顯示兩個視窗
namedWindow("show_frame", WINDOW_AUTOSIZE);
while (capture.read(frame)) {
imshow("show_frame", frame);
//每一幀的等待時間,數字越小讀取越快
waitKey(1);
}
//釋放視頻流,手動呼叫虛解構式,open()和VideoCapture的解構式會自動呼叫,故可以不手動釋放
capture.release();
return 0;
}
列印是否打開成功的結果:video is successful open=1
呼叫本地攝像頭很容易,將capture.open("D:/test_video.mp4");
換成capture.open(0);
即可.
使用cv::VideoWriter::write()存盤視頻
使用opencv存盤視頻流,需要在初始化時設定一系列引數檔案名,編解碼器,幀率,寬度,高度等等
CV_FOURCC可以獲取的編碼格式
CV_FOURCC(‘P’, ‘I’, ‘M’, ‘1’) = MPEG-1 code
CV_FOURCC(‘M’, ‘J’, ‘P’, ‘G’) = motion-jpeg codec
CV_FOURCC(‘M’, ‘P’, ‘4’, ‘2’) = MPEG-4.2 codec
CV_FOURCC(‘D’, ‘I’, ‘V’, ‘3’) = MPEG-4.3 codec
CV_FOURCC(‘D’, ‘I’, ‘V’, ‘X’) = MPEG-4 codec
CV_FOURCC(‘U’, ‘2’, ‘6’, ‘3’) = H263 codec
CV_FOURCC(‘I’, ‘2’, ‘6’, ‘3’) = H263I codec
CV_FOURCC(‘F’, ‘L’, ‘V’, ‘1’) = FLV1 codec
MPEG-1是為CD光碟介質定制的視頻和音頻壓縮格式.
Motion JPEG是一種視頻壓縮格式,其中每一幀影像都分別使用JPEG編碼.
MPEG-4利用很窄的帶寬,通過幀重建技術,壓縮和傳輸資料,求出以最少的資料獲得最佳的影像質量.
VideoWriter::open()函式原型CV_WRAP virtual bool open(const String& filename, int fourcc, double fps, Size frameSize, bool isColor = true);
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgcodecs.hpp>
using namespace std;
using namespace cv;
int main() {
VideoCapture capture;
capture.open("D:/test_video.mp4");
if (!capture.isOpened()) {
cout << "can not open the video" << endl;
}
double fps = capture.get(CAP_PROP_FPS);
int width = int(capture.get(CAP_PROP_FRAME_WIDTH));
int height = int(capture.get(CAP_PROP_FRAME_HEIGHT));
int fourcc_type = VideoWriter::fourcc('M', 'P', '4', '2');
VideoWriter videoWriter;
videoWriter.open("D:/write_video.avi", fourcc_type, fps,
Size(width, height), true);
if (!videoWriter.isOpened()) {
cout << "video_writer can not open" << endl;
return -1;
}
Mat frame;
while (capture.read(frame)) {
//videoWriter << frame;這種寫法也是正確的,使用VideoWriter的輸出流進行寫入
videoWriter.write(frame);
}
return 0;
}
}
效果顯示
使用cv::VideoCapture讀取攝像頭
#include <iostream>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/opencv.hpp>
#include <thread>
using namespace std;
using namespace cv;
thread::id main_thread_id = this_thread::get_id();
void open_video(VideoCapture &capture_usb, const string &filename, Mat &frame) {
capture_usb.open(filename);
if (!capture_usb.isOpened()) {
cerr << "url not exit" << endl;
}
if (this_thread::get_id() == main_thread_id) {
cout << "this is the main thread" << endl;
} else {
cout << "this is not the main thread!" << endl;
}
capture_usb.set(CAP_PROP_FOURCC, VideoWriter::fourcc('M', 'J', 'P', 'G'));
capture_usb.set(CAP_PROP_FRAME_HEIGHT, 500);
capture_usb.set(CAP_PROP_FRAME_WIDTH, 500);
capture_usb.set(CAP_PROP_FPS, 30);
namedWindow("capture", WINDOW_AUTOSIZE);
while (capture_usb.read(frame)) {
imshow("capture", frame);
waitKey(1000);
}
}
void open_video1(VideoCapture &capture_usb, const string &filename, Mat &frame) {
capture_usb.open(filename);
if (!capture_usb.isOpened()) {
cerr << "url not exit" << endl;
}
if (this_thread::get_id() == main_thread_id) {
cout << "this is the main thread" << endl;
} else {
cout << "this is not the main thread!" << endl;
}
//設定采集格式
capture_usb.set(CAP_PROP_FOURCC, VideoWriter::fourcc('M', 'J', 'P', 'G'));
//設定解析度
capture_usb.set(CAP_PROP_FRAME_HEIGHT, 500);
capture_usb.set(CAP_PROP_FRAME_WIDTH, 500);
//設定每秒讀取的圖片數量
capture_usb.set(CAP_PROP_FPS, 30);
namedWindow("capture1", WINDOW_AUTOSIZE);
while (capture_usb.read(frame)) {
imshow("capture1", frame);
waitKey(1000);
}
}
int main() {
VideoCapture capture_usb, local_video_capture, capture_usb1, capture_usb2;
Mat frame, frame_video, frame1, frame2;
//url為讀取的視頻流地址(介面)
const string filename = url;
const string local_file = "D:/test_video.mp4";
const string filename1 = url;
thread thread_1(open_video, ref(capture_usb), filename, ref(frame));
thread thread_2(open_video1, ref(capture_usb1), filename1, ref(frame));
thread_2.join();
thread_1.detach();
for (;;) {
if (!capture_usb.isOpened()) {
break;
}
if (!capture_usb1.isOpened()) {
break;
}
capture_usb.release();
capture_usb1.release();
return 0;
}
capture_usb.set()
引數簡介
引數 | 值 | 功能 |
---|---|---|
CV_CAP_PROP_POS_MSEC | 0 | 視頻檔案的當前位置(以毫秒為單位)或視頻捕獲時間戳 |
CV_CAP_PROP_POS_FRAMES | 1 | 基于0的索引將被解碼/捕獲下一幀 |
CV_CAP_PROP_POS_AVI_RATIO | 2 | 視頻檔案相對位置:0 - 電影的開始,電影的1 - 結束 |
CV_CAP_PROP_FRAME_WIDTH | 3 | 視頻里每一幀的寬 |
CV_CAP_PROP_FRAME_HEIGHT | 4 | 視頻里每一幀的高 |
CV_CAP_PROP_FPS | 5 | 視頻的幀速 |
CV_CAP_PROP_FOURCC | 6 | 4個字符表示的視頻編碼器格式 |
CV_CAP_PROP_FRAME_COUNT | 7 | 視頻的幀數 |
CV_CAP_PROP_FORMAT | 8 | byretrieve()回傳的Mat物件的格式 |
CV_CAP_PROP_MODE | 9 | 指示當前捕獲模式的后端特定值 |
CV_CAP_PROP_BRIGHTNESS | 10 | 影像的亮度(僅適用于相機) |
CV_CAP_PROP_CONTRAST | 11 | 影像對比度(僅適用于相機) |
CV_CAP_PROP_SATURATION | 12 | 影像的飽和度(僅適用于相機) |
CV_CAP_PROP_HUE | 13 | 影像的色相(僅適用于相機) |
CV_CAP_PROP_GAIN | 14 | 影像的增益(僅適用于相機) |
CV_CAP_PROP_EXPOSURE | 15 | 曝光(僅適用于相機) |
CV_CAP_PROP_CONVERT_RGB | 16 | 表示影像是否應轉換為RGB的布爾標志 |
CV_CAP_PROP_WHITE_BALANCE | 17 | 目前不支持 |
CV_CAP_PROP_RECTIFICATION | 18 | 立體攝像機的整流標志(注意:只有當前支持DC1394 v 2.x后端) |
使用互斥量、鎖、多執行緒進行資料讀取和顯示
#include <iostream>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/opencv.hpp>
#include <thread>
#include <deque>
#include <mutex>
#include <Windows.h>
#include <ctime>
using namespace std;
using namespace cv;
thread::id main_thread_id = this_thread::get_id();
deque<cv::Mat> mat_deque;
mutex mut;
void open_video(VideoCapture &capture_usb, const string &filename, Mat &frame) {
capture_usb.open(filename);
if (!capture_usb.isOpened()) {
cerr << "url not exit" << endl;
}
if (this_thread::get_id() == main_thread_id) {
cout << "this is the main thread" << endl;
} else {
cout << "this is not the main thread!" << endl;
}
capture_usb.set(CAP_PROP_FOURCC, VideoWriter::fourcc('M', 'J', 'P', 'G'));
capture_usb.set(CAP_PROP_FRAME_HEIGHT, 200);
capture_usb.set(CAP_PROP_FRAME_WIDTH, 200);
capture_usb.set(CAP_PROP_FPS, 300);
capture_usb.set(CAP_PROP_BUFFERSIZE, 3);
while (capture_usb.read(frame)) {
long start_time = clock();
if (waitKey(20) >= 0) { break; }
lock_guard<mutex> lk(mut);
mat_deque.push_back(frame);
long end_time = clock();
cout<<"read_total_time="<<end_time-start_time<<endl;
}
}
void get_video_data(Mat &frame) {
while (true) {
if (!mat_deque.empty()) {
long start_time = clock();
unique_lock<mutex> lk(mut);
frame = mat_deque.back();
long end_time = clock();
cout<<"get_total_time="<<end_time-start_time<<endl;
lk.unlock();
if (waitKey(20) >= 0) { break; }
imshow("capture", frame);
waitKey(1000);
mat_deque.pop_back();
}
}
}
int main() {
VideoCapture capture_usb;
Mat frame, frame_video, frame1, frame2;
const string filename = url;
const string filename1 = url;
const string filename_123 = url;
thread thread_1(open_video, ref(capture_usb), filename_123, ref(frame));
thread thread3(get_video_data,ref(frame_video));
thread_1.join();
thread3.join();
for (int i = 0; i < 5; ++i) {
thisthread::sleepfor(2000ms);
}
return 0;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/295507.html
標籤:其他