Opencv系列1.7--图像和视频

更多更详细的文章请关注微信公众号:SLAM之路

概要

HighGUI:即high-level graphical user interface,,高级图像用户接口,使我们可以读取和写入与图像相关的文件(图像和视频),打开和管理窗口,展示图片,处理简单的鼠标、指针、键盘活动。

HighGUI库可以分为三部分:硬件部分、文件系统部分、GUI部分。

硬件部分:主要涉及相机操作;

文件系统部分:图像加载和保存;典型特征之一是,读取视频和读取相机采用相同的方法;

GUI部分:使我们能打开窗口,并将图像置于窗口中;使我们注册和响应鼠标、键盘事件等;

 

针对图像

加载图像

最普遍的工作是,加载(cv::imread())和保存文件(cv::imwrite()),这两个函数完成解压缩、压缩和与文件系统交互的全部工作。

首要学习的是,如何从文件系统将图像导入程序中:cv::imread().

cv::Mat    cv::imread(

        const string&    filename,    //文件名

        int    flags    =    cv::IMREAD_COLOR    //设置如何解释的标志位

)

该函数并不关心文件扩展名,它会根据文件头几个字节决定合适的编码。

标志位flags默认是cv::IMREAD_COLOR,也可采用下表中参数:

此外,当cv::imread()无法加载图像时,并不会报运行错误,它仅是返回一个空cv::Mat。cv::Mat::empty()==true.

保存图像

显然,与cv::imread()相辅相成的函数是,cv::imwrite()。

bool    cv::imwrite(

        const    string&    filename,    //文件名

        cv::InputArray    image,    //要保存的图像

        const    vector<int>&    params = vector<int>()

)

第一个参数是,文件名,扩展名文件保存的格式,支持的文件格式:

第三个参数说明:params,表示为特定格式保存的参数编码,它有默认值std::vector(),所以一般情况下不需要填写。如果更改的话,对于不同的图片格式,其对应的值不同功能不同,如下:

 

  • 对于JPEG格式的图片,这个参数表示从0-100的图片质量(cv::IMWRITE_JPEG_QUALITY),默认值是95.

  • 对于PNG格式的图片,这个参数表示压缩级别(cv::IMWRITE_PNG_COMPRESSION)从0-9.较高的值意味着更小的尺寸和更长的压缩时间而默认值是3.

  • 对于PPM,PGM或PBM格式的图片,这个参数表示一个二进制格式标志(cv::IMWRITE_PXM_BINARY),取值为0或1,而默认值为1.

   std::vector<int> compression_params;    compression_params.push_back(CV_IMWRITE_JPEG_QUALITY);  //选择jpeg    compression_params.push_back(0); //在这个填入你要的图片质量    cv::Mat img1=cv::imread("aa.jpg");    std::cout<<cv::imwrite("b.png",img1,compression_params); //写入成功返回1反之0    cv::imshow("addWeight",img1);

压缩和解压缩

根据Opencv数组类型直接压缩图像,这种情况下, 压缩结果不是数组类型而是一个简单的字符缓冲,此时与原图像大小不同。

void    cv:imencode(

        const    string&    ext,    //指定的编码

        cv::InputArray    img,    //被编码图像

        vector<uchar>&    buf,    //编码文件字节数

        const    vector<int>&    params = vector<int>()

        )

cv::imdecode()实现从字符缓冲到数组的解压缩。

void    cv:imdecode(

        cv::InputArray   buf,    //编码文件字节

       int    flags = cv::IMREAD_COLOR    //

        )

第一个参数缓冲,通常类型是std::vector<uchar>。

获取基本属性

    cv::Mat img=cv::imread("a.jpg");    std::cout<<"rows:"<<img.rows<<std::endl             <<"cols:"<<img.cols<<std::endl             <<"chanls:"<<img.channels()<<std::endl;    cv::imshow("addWeight",img);    cv::waitKey(0);

 

针对视频 

 如何将视频从硬盘中读取和写入硬盘。

读取视频:对象cv::VideoCapture

该对象可以从相机或视频文件读取图像帧相关信息,我们可以使用三种不同调用方法创建对象cv::VideoCapture,

cv::VideoCapture::VideoCapture(const string& filename);

cv::VideoCapture::VideoCapture(int device);    //相机编号

cv::VideoCapture::VideoCapture();

第一种,给定视频文件名字,可以打开文件并准备读取,如果打开成功,我们将能开始读取图像帧,cv::VideoCapture::isOpened()返回true打开成功。

第二种方法,数字代表相应相机的域,0表示只有一个相机,当同一个系统有多个相机时,数字逐步增加;

第三种方法,创建一个对象但未打开任何视频或相机,

cv::VideoCapture cap;

cap.open("my_video.avi");

读取图像帧(1):cv::VideoCapture::read()

在得到对象cv::VideoCapture后,通过调用cv::VideoCapture::read()读取图像帧,并将自动将对象cv::VideoCapture向前移动,以满足下次调用read时可以读取下一帧,循环往复。如果读取失败,那么函数将返回false。

读取图像帧(2):cv::VideoCapture::operator>>()

此外,也可以使用重加载符号读取视频对象的下一帧,其表现与read相同,但由于其是流操作符,无论读取是否成功,它都将返回原始对象cv::VideoCapture的引用,这种情况下,必须核对返回数组是否为空。

读取图像帧(3):cv::VideoCapture::grab()、retrieve()

将视频读取分为,grab阶段(将可使用图像复制到内部缓冲中,对用户不可见),retrieve阶段(处理grabbed数据的解码)。暂不细讲。

获取/设置相机属性cv::VideoCapture::get()/set()

视频文件不仅包含视频图像帧,也包括其他重要信息;当视频打开后,信息被复制到对象cv::VideoCapture的内部数据区域,读取这部分信息很常见,将这些数据写入文件也很有用,通过set()和get()函数使我们实现这种操作:

double    cv::VideoCapture::get(

        int    propid        //属性对应号

);

 

bool    cv::VideoCapture::set(

        int    propid,        //属性对应号

        double    value        //所需设定属性值

);

下表是属性对应号:

保存视频:对象cv::VideoWriter

本质上,它与读取视频相同,但有额外几点需要注意:

正如我们使用cv::VideoCapture读取视频,我们保存视频前需要创建对象cv::VideoWriter,它有两种构建方法:一种是简单的默认构造器,仅创建一个没有初始化的视频对象,需要随后打开它;另一种则是包含所有必要的参数以创建视频写入对象:

第一种,默认构造器:

cv::VideoWriter    out;

out.open(

    "my.mpg",

    CV_FOURCC("D","I","V","X"),

    30.0,

    cv::Size(630,480),

    true

);

编码方式:CV_FOURCC(c0,c1,c2,c3);

第二种,完整构造器:

cv::VideoWriter::VideoWriter(

        const string&    filename,    //文件名

        int    fourcc,        //编码方式

        double    fps,        //帧率,每秒多少帧

        cv::Size    frame_size,        //每张图像大小

        bool    is_color = true        //如果是false,灰度图像

);

再开始使用前,应该通过cv::VideoWriter::isOpened()方法确认是否准备好,如果返回true,可以执行;如果返回false,那表明你没有权限访问文件目录或者指定的编码方式无法使用。

写入图像帧(1):cv::VideoWriter::write()

再确认写入图像对象成功打开后,把数组传递给writer即可记录下图像帧;

cv::VideoWriter::write(
                const    Mat&    image    //记录到下一帧的图像

);

图像大小必须与writer构建的大小一致;如果writer是彩色的,那么图像必须是三通道,反之则是灰度图像单通道。

写入图像帧(2):cv::VideoWriter::operator<<()

writer也重载了输出流符号<<,当有了writer时,可以将图像写入视频流的方式,就像ofstream对象:

my_video_writer<<my_frame;

数据持久性

    除了标准标准的视频压缩,Opencv也提供一种机制,用YAML或XML格式实现将各种类型数据序列化到硬盘或者从硬盘反序列化。使用这些方法可以再单一文件中加载和存储任何数量的Opencv数据对象(包括基本类型int/float等等)。这一部分中,我们将专注于一般对象的持久化:读取写入矩阵、Opencv结构、配置结构、logfiles。

对于读取写入文件,使用对象cv::FileStorage,这种对象本质上表示硬盘上一个文件。

写入文件:对象cv::FileStorage

FileStorage::FileStorage();

FileStorage::FileStorage(string fileName, int flag);

写入文件对象cv::FileStorage是XML和YAML数据文件的一种表示形式,创建该对象并将文件名赋予构造器,或者使用默认构造器建立空对象然后使用cv::FileStorage::open打开文件,参数flag是cv::FileStorage::WRITE或cv::FileStorage::APPEND,

FileStorage::open(string fileName, int flag);

在打开需要写的文件后,使用加载符cv::FileStorage::operator<<()写入文件。cv::FileStorage内文件采用两种形式中一种存储,分别是“映射”(也就是键值),或者是“序列”(一些列未命名的条目);

为了创建序列条目,可以先创建条目字符名称,然后是条目本身值。

cv::FileStorage::release()关闭文件对象;

 

键值类型存储:

    cv::FileStorage fs = cv::FileStorage("NAME.YAML",cv::FileStorage::WRITE);    fs<<"hello"<<12;    fs<<"anArray"<<cv::Mat::eye(5,5,CV_8UC3);

序列类型存储

注意中括号与大括号的区别,在YAML中,大括号映射,中括号序列

    cv::FileStorage fs = cv::FileStorage("NAME.YAML",cv::FileStorage::WRITE);    fs<<"theCat"<<"{";    fs<<"fur"<<"gray"<<"eyes"<<"green"<<"weightlbs"<<16;    fs<<"}";

输出结果:

%YAML:1.0
---
theCat:
      fur: gray
      eyes: green
      weightlbs: 16

    cv::FileStorage fs = cv::FileStorage("NAME.YAML",cv::FileStorage::APPEND);    fs<<"theTeam"<<"[";    fs<<"eddie"<<"tom"<<"scott";    fs<<"]";

输出结果:

%YAML:1.0
---
theCat:
  fur: gray
  eyes: green
  weightlbs: 16
...
---
theTeam:
  - eddie
  - tom
  - scott

    cv::FileStorage fs("test.ml",cv::FileStorage::WRITE);    fs<<"frameCount"<<5;    time_t rawtime;time(&rawtime);    fs<<"calibrationDate"<<asctime(localtime(&rawtime));
    cv::Mat cameraMatrix =(        cv::Mat_<double>(3,3)                <<1000,0,320,0,1000,230,0,0,1        );
    cv::Mat distCoeff =(            cv::Mat_<double>(5,1)                    <<0.1,0.01,-0.001,0,0    );
    fs<<"cameraMatrix"<<cameraMatrix<<"distCoeff"<<distCoeff;    fs<<"feature"<<"[";    for (int i=0;i<3;i++){        int x=rand()%640;        int y=rand()%480;        uchar  lbp=rand()%256;
        fs<<"{:"<<"x"<<x<<"y"<<y<<"lbp"<<"[:";        for (int j=0;j<8;j++)            fs<<((lbp>>j)&1);        fs<<"]"<<"}";    }    fs<<"]";    fs.release();
%YAML:1.0
---
frameCount: 5
calibrationDate: "Tue Sep 08 16:42:36 2020\n"
cameraMatrix: !!opencv-matrix
   rows: 3
   cols: 3
   dt: d
   data: [ 1000., 0., 320., 0., 1000., 230., 0., 0., 1. ]
distCoeff: !!opencv-matrix
   rows: 5
   cols: 1
   dt: d
   data: [ 1.0000000000000001e-01, 1.0000000000000000e-02,
       -1.0000000000000000e-03, 0., 0. ]
feature:
   - { x:41, y:227, lbp:[ 0, 1, 1, 1, 1, 1, 0, 1 ] }
   - { x:260, y:449, lbp:[ 0, 0, 1, 1, 0, 1, 1, 0 ] }
   - { x:598, y:78, lbp:[ 0, 1, 0, 0, 1, 0, 1, 0 ] }

读文件:对象cv::FileStorage

FileStorage::FileStorage(string fileName, int flag);

读文可以采用与写文件相同的方法,只是参数flag,应设定为cv::FileStorage::READ。如同写操作一样,也可以先用默认构造器创建空对象,随后使用cv::FileStorage::open()打开文件。

FileStorage::open(string fileName, int flag);

文件打开后,可以使用重加载数组符号cv::FileStorage::operator[]()或者迭代器cv::FileNodeIterator进行读操作。读取完毕后,使用cv::FileStorage::release()关闭文件。

读取映射类型时,cv::FileStorage::operator[]()通过字符键值关联到目标对象;读取序列类型时,需要使用整型参数调用该操作符。但是,该操作符的返回值并不是目标对象;它是一个cv::FileNode对象,它以抽象的形式表示值,具体参考cv::FileNode。

读文件:对象cv::FileNode

若干种合适的重加载符号使用该对象,cv::FileNode::operator>>()

    cv::FileStorage fs("test.ml",cv::FileStorage::READ);    cv::Mat anArray;    fs["cameraMatrix"]>>anArray;    std::cout<<"anArray is :"<<std::endl<<anArray<<std::endl;
//支持强制转换    float aNumber;    fs["frameCount"]>>aNumber;    std::cout<<"aNumber:"<<std::endl<<aNumber<<std::endl;    fs.release();

 若给定cv::FileNode对象,则成员函数cv::FileNode::begin()和end(),对于键值类型和序列类型都会提供first和“after last”迭代。

 

   //打开文件    cv::FileStorage fs("test.ml",cv::FileStorage::READ);   //使用FileNode中的类型操作符    int frameCount = (int)fs["frameCount"];
  //使用重加载符>>    std::string date;    fs["calibrationDate"]>>date;
    cv::Mat cameraMatrix2,distCoeffs2;    fs["cameraMatrix"]>>cameraMatrix2;    fs["distCoeff"]>>distCoeffs2;
    std::cout<<"frameCount: "<<frameCount<<std::endl;    std::cout<<"calibration date:"<<date<<std::endl;    std::cout<<"camera matirx: "<<cameraMatrix2<<std::endl;    std::cout<<"distortion coeffs: "<<distCoeffs2<<std::endl;
    cv::FileNode features = fs["features"];    cv::FileNodeIterator it = features.begin(),it_end = features.end();    int idx = 0;    std::vector<uchar>  lbpval;
    for(;it!=it_end;++it,idx++){        std::cout<<"features #"<<idx<<":";        std::cout<<"x="<<(int)(*it)["x"]<<", y="<<(int)(*it)["y"]<<",lbp:(";        (*it)["lbp"]>>lbpval;        for (int i = 0;i<(int)lbpval.size();i++)            std::cout<<" "<<(int)lbpval[i];        std::cout<<")"<<std::endl;
    }    fs.release();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值