龙渊幻想-异世界冒险活动站

龙渊幻想-异世界冒险活动站

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 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 lk(mut);

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 lk(mut);

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;

}