OpenCv图像处理之图像视频摄像头读取和保存
OpenCv图像处理之图像视频摄像头读取与保存
使用cv::imread()读取图片使用cv::imwrite()存储图片使用cv::VideoCapture::open()读取视频使用cv::VideoWriter::write()存储视频使用cv::VideoCapture读取摄像头使用互斥量、锁、多线程进行数据读取和显示
使用cv::imread()读取图片
经过上一节的学习,我们了解到opencv处理的图片其实就是对矩阵进行操作,使用cv::imread()对图片进行读取并返回一个矩阵,来看一个例子:
#include
#include
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
#include
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
使用cv::VideoCapture::open()读取视频
VideoCapture既可以从视频文件读取图像,也可以从摄像头中读取图像.使用VideoCapture::open()打开.
#include
#include
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
#include
#include
#include
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
#include
#include
#include
#include
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_MSEC0视频文件的当前位置(以毫秒为单位)或视频捕获时间戳CV_CAP_PROP_POS_FRAMES1基于0的索引将被解码/捕获下一帧CV_CAP_PROP_POS_AVI_RATIO2视频文件相对位置:0 - 电影的开始,电影的1 - 结束CV_CAP_PROP_FRAME_WIDTH3视频里每一帧的宽CV_CAP_PROP_FRAME_HEIGHT4视频里每一帧的高CV_CAP_PROP_FPS5视频的帧速CV_CAP_PROP_FOURCC64个字符表示的视频编码器格式CV_CAP_PROP_FRAME_COUNT7视频的帧数CV_CAP_PROP_FORMAT8byretrieve()返回的Mat对象的格式CV_CAP_PROP_MODE9指示当前捕获模式的后端特定值CV_CAP_PROP_BRIGHTNESS10图像的亮度(仅适用于相机)CV_CAP_PROP_CONTRAST11图像对比度(仅适用于相机)CV_CAP_PROP_SATURATION12图像的饱和度(仅适用于相机)CV_CAP_PROP_HUE13图像的色相(仅适用于相机)CV_CAP_PROP_GAIN14图像的增益(仅适用于相机)CV_CAP_PROP_EXPOSURE15曝光(仅适用于相机)CV_CAP_PROP_CONVERT_RGB16表示图像是否应转换为RGB的布尔标志CV_CAP_PROP_WHITE_BALANCE17目前不支持CV_CAP_PROP_RECTIFICATION18立体摄像机的整流标志(注意:只有当前支持DC1394 v 2.x后端)
使用互斥量、锁、多线程进行数据读取和显示
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
using namespace cv;
thread::id main_thread_id = this_thread::get_id();
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
mat_deque.push_back(frame);
long end_time = clock();
cout<<"read_total_time="< } } void get_video_data(Mat &frame) { while (true) { if (!mat_deque.empty()) { long start_time = clock(); unique_lock frame = mat_deque.back(); long end_time = clock(); cout<<"get_total_time="< //拿到数据之后解锁 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; }