学习OpenCV写视频操作

版权声明:学无止境,好好学习 https://blog.csdn.net/m0_38116269/article/details/88886338

一、基础信息

版本:OpenCV 4.0.1
系统:Ubuntu 18.04 LTS
编译:CMake

参考:samples/cpp/tutorial_code/videoio/video-write/video-write.cpp

二.merge 和split操作的理解

目前通道的合并和读取不太明白,准备今天下午搞得明明白白,清清楚楚,扎扎实实!
先从图片做起,处理单张图片试一试。
已经学习到的小tips:
(1)一定要注意先保存,再make, 不然编译的还是没有保存之前的。
(2)读取文件的路径,一定要写成绝对路径而不是相对路径
(3)多加一些if判断语句,例如读取不到文件就输出一条语句并且返回,别总是等到机器报错就不好了。
编写了个测试代码,有助于理解通道的融合和分离。

#include <iostream>
#include <string>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main(){
    //注意,这里要放绝对路径。。。不然会出错。
    Mat img = imread("/home/wwh/Documents/myproject/video/data/lena.jpg"); //
    if(img.empty()){
        cout<<"There is no this image or wrong directory!"<<endl;
        return -1;
    }
    cout<<"the size of the image is: "
    <<img.size()<<endl;
    vector<Mat> sptimg;
    split(img, sptimg); //通道分离
    if(sptimg.empty()){
        cout<<"wrong split!"<<endl;
        return -1;
    }
    Mat merimg;
    Size S = Size(512, 512);
    sptimg[0] = Mat::zeros(S, sptimg[0].type());
    //sptimg[2] = Mat::zeros(S, sptimg[2].type());
    merge(sptimg, merimg);
    //图片打印到屏幕上
    namedWindow("lena", WINDOW_NORMAL);
    imshow("lena", merimg);
    waitKey(5000);
    return 0;
}

通过打印分离后的通道size,可以发现分成了三个512512。而原始图像也是512512,这说明并不是矩阵的重组,而是融合!意会!

三.读取视频,截取一段写成新的视频

编写了个简单的程序,可以实现对原始视频的截取然后保存,比如,截取原始视频的第100帧到第200帧保存为一个新的视频。
下面是代码,

#include <iostream>
#include <string>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

static void help(){
    cout<<"wrong input number"<<endl;
    cout<<"eg: ./video ../data/xx.avi"<<endl;
}
int main(int argc, char* argv[]){
    if(argc != 2){
        help();
        return -1;
    }
    const string sourceVideo = argv[1];
    VideoCapture capVideo(sourceVideo);
    if(!capVideo.isOpened()){
        cout<<"No this video os directory!"<<endl;
        return -1;
    }
    
    int ex = static_cast<int>(capVideo.get(CAP_PROP_FOURCC));
    Size S = Size((int)capVideo.get(CAP_PROP_FRAME_WIDTH),
                  (int)capVideo.get(CAP_PROP_FRAME_HEIGHT));
    //打印输入视频的相关信息,高度,宽度,帧数
    cout<<"the source vidio has width:"<<S.width
        <<"height:"<<S.height;
    cout<<" total frame is:"<<capVideo.get(CAP_PROP_FRAME_COUNT)<<endl;
    //命名
    string::size_type ptn = sourceVideo.find_last_of('.');
    const string Name = sourceVideo.substr(0, ptn) + "_new.avi"; 
    VideoWriter wriVideo;
    wriVideo.open(Name, ex, capVideo.get(CAP_PROP_FPS), S, true);
    if(!wriVideo.isOpened()){
        cout<<"Can't create a new vidio!"<<endl;
        return -1;
    }

    Mat src, wri;
    int framNum = -1;
    while(1){
        
        capVideo >> src;
        //准备写入原始视频的第100帧到第200帧到新视频中
        if(framNum > 100 && framNum < 200){
            wriVideo << src;
        } 
        //要是读到底了,那就退出      
        if(src.empty()){
            break;
        }
        ++framNum;
    }
    cout<<"Finished"<<endl;
    return 0;
}

下面准备稍微改一下,
(1)能够读取前后10帧,共20帧组成一个视频。
(2)修改路径,能够保存在自己想要的目录下面,成功。
(3)能够读取多个片段并保存,这个得想一想。
准备开干!
感觉自己功力不够深厚,目前还不能写多个视频,分段保存,准备继续深造,来日再战。

四、读取摄像头写入视频文件

又成功实现了一个读取摄像头,并将视频写入的文件,附上代码。这里注意,原来的demo是有错误,循环当中应该写视频流,我给加上了。

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

int main(){
    VideoCapture cap;
    cap.open(0);
    if(!cap.isOpened()){
        cout<< "Can't open camera!"<<endl;
        return -1;
    }
    Mat src;
    cap >> src;
    int codec = VideoWriter::fourcc('M', 'J', 'P', 'G');
    double fps = 25.0;
    string filename = "../outvid/camvid.avi";
    VideoWriter wriVideo;
    wriVideo.open(filename, codec, fps, src.size(), true);
    if(!wriVideo.isOpened()){
        cout<<"Can't open the new avi"<<endl;
        return -1;
    }
    while(1){
        cap >> src;
        if(src.empty()){
            cout<<"Can't open the camera!"<<endl;
            break;
        }
        wriVideo << src;
        imshow("window", src);
        if(waitKey(5)>0){
            break;
        } 
        if(src.empty()){
            break;
        }
    }
    cap.release();
    destroyAllWindows();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_38116269/article/details/88886338