《opencv4快速入门》

认识认识模块

D:\opencv\build\include\opencv2 路径下

  • calib3d 主要包含相机标定,立体视觉的功能:物体姿势估计,三维重建,摄像头标定
  • core,包含库的基本结构和操作,比如数据结构,绘图函数,数组操作等函数
  • dnn,深度学习模块,包含构建网络,加载序列化的模型,但是不支持训练,只能推理
  • features2d,处理图像特征点,特征检测,描述匹配之类的
  • flann,这个模块是高维的近似近邻快速搜索算法库 主要包含快速近似近邻搜索与聚类等。
  • gapi,加速图像处理的框架,没有特定的算法
  • highgui,创建操作显示图像的窗口,处理鼠标事件和键盘命令,提供交互式可视化的界面
  • imgcodecs 图片的保存和读取
  • imgproc,图像处理模型,滤波,几何变换,直方图,特征检测目标检测等。
  • ml,机器学习模块,统计分类,回归,聚类等
  • objdetect,目标检测慕课,Haar特征等
  • photo,摄影模型用来图片修复,去噪
  • stitching,图像拼接,包含特征点的寻找和匹配,估计选择,自动校准,接缝等(啊这)
  • video ,视频分析模型,用于运动估计,背景分离,对象跟踪等
  • videoio ,视频输入,输出模块。

Mat

Mat类用于存储矩阵数据,可以自动管理内存,解决内存释放的问题。用来保存矩阵类型的数据,包括向量,矩阵,图像数据等。分为矩阵头和指向数据的指针两部分,矩阵头包括矩阵的尺寸,存储方法,地址,引用次数等。大小是个常数,opencv中复制和传递图像,就只是复制了矩阵头和指向数据的地址。 创建Mat时可以先创建矩阵头再赋值。

using namespace cv;
Mat a;  // 名为a的矩阵头
a = imread("3.jpg");  // 向a中赋值图像数据,矩阵指针指向像素数据
Mat b=a;   // 复制矩阵头,命名b,虽然有各自的矩阵头,但数据指针指向的时一个数据Mat c = Mat_<double>(3,3)  // 创建3*3 的矩阵存放double类型的数据。
// 同样的有 flaot,uchar,char 和模板,CV_64F

通过其中一个矩阵头改变数据,另一个矩阵头指向的数据同样变化。
但是当a 变量删除时,b不会指向一个i空数据,只有两个变量都没了才会删除数据。
这就是矩阵头的引用次数标记了引用矩阵数据的次数, 只有值为0才会释放数据。

为了避免在不同环境下因变量位数长度不同而造成程序执行问题,OpenCV 根据数值变量存储位数长度定义了数据类型,后加一个C表示通道

Mat a(640,640,CV_8UC3); // 创建一个640*640 8位三通道的矩阵
Mat a(3,3,CV_8U); // 单通道,C1可以省略

Mat的构造方法:

Mat ()Mat (int rows, int cols, int type)  Mat (Size size, int type)  size:二维数组尺寸 Size(cols,rows),注意行列顺序Mat a(Size(480,640), CV_8UC1); 行640,列480Mat (int rows, int cols, int type, const Scalar &s)  构造的同时赋值(相同的值)Mat a(2,2,CV_8UC3, Scalar(0,0,255)); 创建三通道矩阵,通道值位0,0,255。Mat (Size size, int type, const Scalar &s)Mat (int ndims, const int *sizes, int type)Mat (const std::vector< int > &sizes, int type)Mat (int ndims, const int *sizes, int type, const Scalar &s)Mat (const std::vector< int > &sizes, int type, const Scalar &s)Mat (const Mat &m) 利用已有矩阵构建,只是复制了矩阵头,这辆指向同一数据,m=a.clone() 复制数据Mat (int rows, int cols, int type, void *data, size_t step=AUTO_STEP)Mat (Size size, int type, void *data, size_t step=AUTO_STEP)Mat (int ndims, const int *sizes, int type, void *data, const size_t *steps=0)Mat (const std::vector< int > &sizes, int type, void *data, const size_t *steps=0)Mat (const Mat &m, const Range &rowRange, const Range &colRange=Range::all())再已有矩阵中截取一个范围,rowRange是一个Range变量 Range(2,5) 截取2至5行,colRange 截取列,默认全截这个截取的矩阵仍然与原Mat 共享数据,改一个另一个也会改变Mat (const Mat &m, const Rect &roi)Mat (const Mat &m, const Range *ranges)Mat (const Mat &m, const std::vector< Range > &ranges)Mat a = (Mat_<int>(3, 3) << 1 , 2 , 3 , 4 , 5, 6 , 7 , 8 , 9) 枚举赋值,用数据流赋值
Mat c=Mat_<int>(3,3);   // 循环赋值
for (int i =0;i<c.rows;i++)
{for(int j=0; j<c.cols;j++){c.at<int>(i,j)= i+j;   // 类型一样}
}
Mat a = Mat::eye(3,3, CV_8UC1);   // 单位矩阵
Mat b = (Mat_<int>(1,3)<<1,2,3);
Mat c = Mat::diag(b);   // 对角矩阵,参数是Mat类型的一维变量,用来存放堆笑元素的值
Mat d = Mat::ones(3,3, CV_8UC1);  // 全为1
Mat e = Mat::zeros(3,3, CV_8UC3);  // 全为0利用数组进行赋值
float a[] = {1,2,3,4,5,1,2,3};
Mat b = Mat(2,2,CV_32FC2,a);   // 拆分方式根据矩阵的尺寸和通道数,数组不够填充别的值。多了就省略Mat类的运算,看作普通的矩阵就行
e = a+b  矩阵加减法,两个矩阵类型相同
f = 2*a
h = d/2.  与常数的运算,保留矩阵的类型
g = a-1  逐元素减1 j = a*b  矩阵的乘法
double k = a.dot(b)   矩阵的内积,一个行向量和列向量的点乘
m = a.mul(b)    逐元素对应相乘

元素的读取

比如之前的 at方法对有每一位的读取,多通道的Mat矩阵存储的形式类似于三维数组,先存储第一个元素的每个通道的数据,然后第二个元素每个通道的数据,每一行就如此存储。找到每个元素的起始位置,就可以找到这个元素中每个通道的数据

  1. at<type>,at方法读取单通道矩阵元素。多通道就返回一个元素多个数据,使用Vec3b, Vec3s, Vec3d, Vec3f, Vec3i ,Vec3w,6种类型用于表示同意元素的3个通道数据。b uchar, s short , w ushort ,d double ,f float ,i int ,3表示三个通道,Vec2b表示二通道uchar类型
Mat a = (Mat_<uchar>(3,3) << 1,2,3,4,5,6,7,8,9);
int Value = (int) a.at<uchar>(0,0);   Mat b(3,4,CV_8UC3,Scalar(0,0,1);
Vec3b vc3 = b.at<Vec3b>(0,0);   // 与矩阵类型对应
int first = (int)vc3.val[0];
int second = (int)vc3.val[1];
int third = (int)vc3.val[2];
  1. ptr指针读取元素
    矩阵中每一行的元素都是挨着存放,找到每一行元素的起始位置,读取不同位置的元素只要移动指针就可。
Mat b(3,4,CV_8UC3,Scalar(0,0,1);
for (int i=0; i<b.rows;i++) // 每一行
{uchar* ptr = b.ptr<uchar>(i);  // 定义指针,声明指向哪一行for (int j =0;j<b.clos*b.channels();j++) // 每一行存储的数据数量为列数与通道的乘积。{cout<<(int)ptr[j]<<endl;}
}
// 读取第2行数据中第三个数据,a.ptr<uchar>(1)[2];
  1. 通过迭代器访问元素
    Mat类也是一个容器,也有迭代器。
MatIterator_<uchar> it = a.begin<uchar>();   // 迭代器遍历类型
MatIterator_<uchar> it_end = a.end<uchar>();
for (int i=0; it != it_end; it++)
{cout<<(int)(*it)<< " ";  // 解引用,输出每一个元素的每个通道if((++i% a.cols) == 0){cout<<endl;}
}
  1. 通过矩阵元素地址定位的方式读取元素
(int)(*(b.data+b.step[0] * row + b.step[1] * col + channel));

row 某个数据的行数,col列数,channel某个数据所在元素的通道。就是第row行,第col列,第channel通道的数据。也是通过首地址移动若干位读取数据。

图片的读取和显示

Mat cv::imread   (   const String &  filename,
int     flags = IMREAD_COLOR
)

读取图片,返回一个Mat,读取失败返回空矩阵,可以使用Mat.empty() 判断。Win中默认使用自带的编码器 libjpeg,libpng等来读取图像文件,linux就需要自己下载,能否读取文件看文件的内容而不是后缀,.jpg 改成.exe 一样可以读取,相反就不行。

flags参数设置读取样式,原样读取,灰度,彩图,多位数,缩小等。功能不冲突的前提下可以同时声明多个,用 | 隔开

void cv::namedWindow (   const String &  winname,
int     flags = WINDOW_AUTOSIZE
)

显示图像时没有主动定义窗口,会自动生成。需要添加滑动条这类的需要手动创建。创建一个窗口变量,用于显示图像和滑动条。创建窗口时已经存在同名的,就不会再执行任何操作,创建的窗口使用 cv::destroyWindow() and cv::destroyAllWindows() 来释放资源,一个指定名字,一个释放全部。但实际上程序的退出会自动关闭应用程序的所有资源,可以不用主动释放。

flags声明窗口属性,设置是否可调大小,显示图像是否填充+

void cv::imshow  (   const String &  winname,
InputArray  mat
)

再指定窗口中显示图像,第二个参数是InputArray,是一个类型声明引用,用于输出参数的标记,就当作Mat就行。

VideoCapture ()
VideoCapture (const String &filename, int apiPreference=CAP_ANY)

apiPreference 读取视频时设置的属性,编码格式,是否使用OpenNI等。
可以读取处理视频流,也可以是图片序列或者视频的URL,图片序列将多个图像的名字统一为 "前缀+数字“ 的形式,比如 img_%02d.jpg ,可以读取文件夹下 img_00.jpg, img_01.jpg…就可以自动搜索合适的标志。 isOpened() 函数进行判断是否读取成。

通过VideoCapture 将视频文件加载到了这个类变量里,使用视频中的图片使用,使用>> 将图片导入Mat中,当VideoCapture里所有图像赋值给了Mat,后再次赋值就变成空矩阵了。使用 empty() 判断是否读取完毕。

还提供了查看视频属性的get() 函数,通过输入指定的标记获取视频属性。

#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;int main(int argc, char *argv[])
{system("color F0");   // 摄像头就 video(0)VideoCapture video("D:\\opencv\\sources\\samples\\data\\Megamind.avi");if (video.isOpened()){cout << video.get(3) << video.get(4) << video.get(5) << video.get(7);}while (1){Mat frame;video >> frame;if (frame.empty()){break;}imshow("img", frame);waitKey(1000 / video.get(CAP_PROP_FPS));}waitKey();return 0;
}

数据保存

bool cv::imwrite (   const String &  filename,InputArray     img,const std::vector< int > &    params = std::vector< int >()
)

将Mat保存为图片,

  • 16 位无符号 CV 16U 图像可以保存成 PNG JPEG TIFF 式文件
  • 32 位浮点 CV_32F 图像可以保存成 PFM TIFF OpenEXR Radiance HDR 格式文化
  • 4 通道 (Alpha 通道 图像可以保存成 PNG 式文件.

函数第三个参数在一般情况下不需要填写 ,保存成指定的文件格式只需要直接在第一个参数
后面更改文件后缀,但是当需要保存的 Mat 类矩阵中数据比较特殊 〈如 16 位深度数据 )就需要
要设置第 3个参数.

// 保存图像
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;void AlphaMat(Mat &mat)   // 引用作参数 就是改改值吧。。
{CV_Assert(mat.channels() == 4);/*进行条件检查,失败就报出异常*/for (int i = 0; i < mat.rows; i++){for (int j = 0; j < mat.cols; ++j){Vec4b& bgra = mat.at<Vec4b>(i, j);  // 多通道就返回一个元素多个数据,使用这种类型承载bgra[0] = UCHAR_MAX;     // maximum unsigned char value 蓝色通道,255/*saturate_cast 是为了防止颜色溢出原理大致如下if(data<0) data=0; elseif(data>255) data=255;*/bgra[1] = saturate_cast<uchar>((float(mat.cols - j)) / ((float)mat.cols));  //绿色bgra[2] = saturate_cast<uchar>((float(mat.rows - j)) / ((float)mat.rows)); //redbgra[3] = saturate_cast<uchar>(0.5 * (bgra[1] + bgra[2])); //alpha 通道}}
}int main(int argc, char *argv[])
{system("color E");Mat mat(480, 640, CV_8UC4);  // 创建个四通道的matAlphaMat(mat);vector<int> compression_params;compression_params.push_back(IMWRITE_PNG_COMPRESSION);  // imwrite 第三个参数设置的方式compression_params.push_back(9);     bool result = imwrite("alpha.png", mat, compression_params);if (!result){cout << "error";return -1;}cout << "okk";return 0;
}

视频的保存

cv::VideoWriter::VideoWriter (   const String &  filename,int    fourcc,double   fps,Size    frameSize,bool  isColor = true
)

fourcc视频编码器,-1 自动搜索合适的。fps保存的视频帧率,可以实现二倍速,慢速等。frameSize保存视频的尺寸,但是要与图像的尺寸相同。。。isColor 是否保存彩色视频。保存视频就使用 << or write() 。isOpened() 判断是否创建成功,release() 关闭视频流。

#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;int main(int argc, char *argv[])
{Mat img;VideoCapture video(0);if (!video.isOpened()){cout << "error";return -1;}video >> img;  // 读取视频if (img.empty()){cout << "error";return -1;}bool isColor = (img.type() == CV_8UC3); // 判断相机类型是否为彩色VideoWriter writer;int codec = VideoWriter::fourcc('M', 'J', 'P', 'G');  // 选择编码格式double fps = 25.;string filename = "a.avi";writer.open(filename, codec, fps, img.size(), isColor); // 创建保存视频文件的视频流if (!writer.isOpened())  // 视频流是否创建成功{cout << "error";return -1;}while (1){if (!video.read(img)) // 摄像头断开,或视频读取完成,执行完毕{cout << "error";break;}writer.write(img);   // 写入视频流// writer<<img;imshow("img", img);char c = waitKey(50);   // ESC退出视频程序if (c == 27){break;}}video.release();  // 程序退出自动释放资源,可以不用writer.release();return 0;
}

保存读取XML 和YMAL文件

程序中尺寸较小的Mat类矩阵,字符串,数组等数据也需要保存,这种数据通常保存为XML or YAML文件。
YAML文件通过”变量:数值“的方式表示每个数据,通过缩进表示数据之间的结构和隶属关系。扩展就是 .ymal .yml

cv::FileStorage::FileStorage (   const String &  filename,
int     flags,
const String &  encoding = String()
)

flags对文件进行的操作类型标志,encoding,编码格式 UTF-8 XML编码。声明打开的文件名和操作的类型。但是文件的操作需要已经存在的文件

默认的FileSotrage的构造函数没有参数,一般需要open() 函数单独声明,传入参数。isOpened() 判断是否打开文件,使用 << 写入数据(file<<“age”<<24;)(write() 变量名,变量值),表示某个变量是个数组使用”[] " 来表示,比如“ file<<“age”<<"["<<21<<22<<"]" “。隶属关系使用{} 表示,例如” file<<“age”<<”{"<<“qbx”<<20<<“lh”<<22<<"}" ".

>> 读取数据。通过变量名读取变量值 file[“x”] >> xRead ,读取名为x的变量。当某个变量有多个数据或自变量时,需要通过FileNode 节点类型和迭代器 FileNodeIterator 读取。


virtual bool cv::FileStorage::open  (   const String &  filename,int    flags,const String &    encoding = String()
)   void cv::FileStorage::write (   const String &  name,
int     val   // 经过函数重载,可以是很多其他格式
)   #include <iostream>
#include <opencv2/opencv.hpp>
#include <string>
using namespace std;
using namespace cv;int main(int argc, char *argv[])
{system("color E");string filename = "data.xml";// string filename = "data.yaml";FileStorage fwrite(filename, FileStorage::WRITE); // 写入模式,需要加前缀的Mat mat = Mat::eye(3, 3, CV_8U);fwrite.write("mat", mat); // 写入数据。使用write方法float x = 100;fwrite << "x" << x;   // 跟python的字典一样,使用流方法String str = "hi, hhh";  fwrite << "str" << str;fwrite << "number_array" << "[" << 4 << 5 << 6 << "]";   // 表示一个数组 [] fwrite << "multi_nodes" << "{" << "month" << 8 << "day" << 28 << "year" //{} 表示隶属关系<< 2020 << "time" << "[" << 0 << 1 << 2 << 3 << "]" << "}";fwrite.release();  // 关闭文件FileStorage fread(filename, FileStorage::READ);  // 读取文件数据if (!fread.isOpened()){cout << "error";return -1;}float xRead;fread["x"] >> xRead;    // 通过变量名读取cout << "x=" << xRead << endl;string strRead;fread["str"] >> strRead;cout << "str=" << strRead << endl;FileNode fileNode = fread["number_array"];  // 含有多个数据或自变量的,通过节点类型和迭代器进行读取cout << "number_array = [";for (FileNodeIterator i = fileNode.begin(); i != fileNode.end(); i++){float a;*i >> a;cout << a << " ";}cout << "]" << endl;Mat matRead;fread["mat"] >> matRead;cout << "mat = " << mat << endl;FileNode fileNodel = fread["multi_nodes"];int mouth = (int)fileNodel["mouth"];   // 从节点中读取自变量int day = (int)fileNodel["day"];int year = (int)fileNodel["year"];cout << "multi_nodes:" << endl<< " mouth=" << mouth << " day=" << day << " year=" << year;cout << " time = [";for (int i = 0; i < 4; i++){int a = (int)fileNodel["time"][i];   // 另一种方法不用迭代器,就一级一级的找cout << a << " ";}cout << "]" << endl;fread.release();return 0;
}

小结

opencv C艹:读取视频文件,保存图像,视频文件,读取保存XML YAML文件相关推荐

  1. XML/YAML文件的输入输出

    本文主要阐述XML/YAML文件在OpenCV3中如何实现输入输出操作.     <1>: XML/YAML文件,顾名思义指的是文件的格式,即以.XML为后缀的文件和以.YAML为后缀的文 ...

  2. 【web测试】不同格式的文件操作(txt,csv,excel,json,xml,yaml)

    [web测试]数据驱动 python操作文件 txt文件 csv格式 excel文件 json格式 xml文件 yaml格式 python操作文件 txt文件 # 读取r 写入w;rb-二进制读取;w ...

  3. python写xml文件 数据量特别大_python处理xml大文件[xml.sax]

    博客已迁移, 新地址 ===================== 今天遇到大文件处理,使用dom占用资源太多,改用sax处理 dom和sax区别可以自己google下 需求:读取xml数据文件,文件较 ...

  4. OpenCV XML和YAML文件的文件输入和输出

    OpenCV XML和YAML文件的文件输入和输出 XML和YAML文件的文件输入和输出 目标 源代码 解释 XML / YAML文件打开和关闭. 文本和数字的输入和输出. OpenCV数据结构的输入 ...

  5. OpenCV之core 模块. 核心功能(2)基本绘图 随机数发生器绘制文字 离散傅立叶变换 输入输出XML和YAML文件 与 OpenCV 1 同时使用

    基本绘图 目的 本节你将学到: 如何用 Point 在图像中定义 2D 点 如何以及为何使用 Scalar 用OpenCV的函数 line 绘 直线 用OpenCV的函数 ellipse 绘 椭圆 用 ...

  6. OpenCV中XML文件和YAML文件的读写

    OpenCV中XML文件和YAML文件的读写 代码如下: #include <opencv2/core/core.hpp> #include <iostream> #inclu ...

  7. 【C++】42.使用YAML文件进行参数配置、读取与生成YAML文件

    关于配置文件的使用,除了本文的yaml的方法,经常使用的还有proto的方法,请参考我另一篇博客:proto相关用法:方法2.. c++中如果要使用YAML,需要安装yaml-cpp库,安装完成后使用 ...

  8. 图像视频压缩编码概述

    图像视频压缩编码概述 图像视频的特点 图像压缩 图像编码方法 统计编码的基本理论 霍夫曼编码 香农编码 算术编码 游程编码 变换编码 预测编码 图像视频的特点 首先,图像视频信号十分直观确切,其可以较 ...

  9. Li‘s 影像组学视频学习笔记(16)-pyradiomics里的yaml文件

    本笔记来源于B站Up主: 有Li 的影像组学系列教学视频 本节(16)主要介绍: pyradiomics的yaml文件参数设置解读 pyradiomics 官网对yaml文件有详细说明: The th ...

最新文章

  1. python做直方图-python实现直方图的应用
  2. 学习笔记Hadoop(八)—— Hadoop集群的安装与部署(5)—— Hadoop配置参数介绍、Hadoop集群启动与监控
  3. python高阶函数
  4. 如何插入8bit量化节点(tensorflow)
  5. MSDN Visual系列:在WSSv3中编程方式激活单个文档库的审核功能
  6. C语言变量和数据类型
  7. 7月份Github上最热门的Java开源项目
  8. 1.如何判断正交表对错
  9. matlab 平方根法解方程组,matlab改进平方根法
  10. win2008 有几个版本?区别是什么?
  11. 手工定制眼镜将风靡中国(lyy bros)
  12. 计算机必须设置默认打印机,电脑系统怎么默认打印机 默认打印机的设置教程...
  13. php 生成300dpi图片,canvas生成图片只有96dpi,打印需要300dpi, 请问如何修改这个信息....
  14. ubuntu安装qtcreator后没有桌面图标
  15. 城市易涝点(隧道、涵洞)监测系统方案
  16. qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
  17. 全国第一所蚂蚁链大学落地江西 2020区块链创新应用高峰论坛圆满落幕
  18. 转载:知其所以然(以算法学习为例) 作者: 刘未鹏
  19. 揭秘跨越普通权限的神秘地带
  20. 最佳Linux笔记本电脑编程

热门文章

  1. Linux哪个命令显示文件内容,显示文件内容的Linux命令有哪些?Linux培训
  2. 【腾讯云】Ubuntu16.04下搭建Java开发环境一站式服务(WinSCP、PuTTY、JDK、MySQL、Tomcat)
  3. 读《终身成长》知 我命由我不由天 馁
  4. 动态规划初识(从dfs到dfs优化到动态规划顺推和逆推)
  5. Oracle中where后面加if,SQL:WHERE子句中的IF子句
  6. 大话C#的进阶业务场景必知点解析 第8节 算法上道C#根据时间起卦像程序
  7. 80后:管理还是激励
  8. 朱萧木首谈独立创业,与罗老师总会相逢
  9. Selenium应用系列2
  10. 南京林业大学计算机专升本,专转本之南京林业大学