<学习opencv>图像、视频和数据文件
/*=========================================================================*/ // openCV中的函数 /*=========================================================================*/ HighGUI:便携式图形工具包 OpenCV函数允许我们进行交互与经营系统,文件系统和硬件(如摄像头) 主要位于名为HighGUI的模块中(代表“高级图形用户界面”)。 HighGUI允许我们读取和写入与图形相关的文件(图像和视频),打开和管理窗口,显示图像, 以及处理简单的鼠标,指针和键盘事件。我们也可以使用它来创建其他有用的doodads - 例如滑块 - 然后将它们添加到我们的窗口。如果您是所选窗口环境中的GUI大师, 那么您可能会发现HighGUI提供的大部分内容都是多余的。 即便如此,您可能会发现跨平台可移植性的好处本身就是诱人的。 【注意】 在OpenCV 3.0中,HighGUI已经 分成三个 模块: 1. imgcodecs 图像编码/解码 2. videoio(捕获和编码视频 3. 和现在调用的部分highgui (这是UI部分) 为了更好的向后兼容性,highgui.hpp 标头包含videoio.hpp 和imgcodecs.hpp 标头, 因此大多数OpenCV 2.x代码将与3.x兼容。 展望未来,我们将使用名称HighGUI指所有的图像I / O,视频I / O,以及UI描述的功能, 并且代码示例应与双方的OpenCV 2.x和3兼容。X。 但请记住,如果您使用OpenCV 3.0并且只需要视频捕获功能, 或者只是读取和写入图像,则可以使用videoio / imgcodecs 与其他HighGUI组件分开使用。 【使用图像文件】: OpenCV提供了加载和保存图像的特殊功能。 这些函数明确地或隐含地处理与压缩和解压缩该图像数据相关的复杂性。 它们在几个方面与我们将在“数据持久性”中学习的更通用的基于XML / YAML的函数不同。 主要的区别在于,因为前者的功能是专门为图像设计的,而不是一般的数据数组, 所以它们在很大程度上依赖于现有的后端进行压缩和解压缩。 通过这种方式,他们能够以所需的特殊方式处理每种常见文件格式。 其中一些 已经开发了压缩和解压缩方案,其思想是可以丢失一些信息而不会降低图像的视觉体验。 显然,这种有损压缩方案对于非图像数据阵列来说不是一个好主意。 加载和保存图像 最简单的方法是使用高级功能cv::imread() 和cv::imwrite()。 这些函数处理解压缩和压缩的完整任务以及与文件系统的实际交互。 使用imread()读取文件: 从文件系统和程序中获取图像。执行此操作的功能是:imread(): cv::Mat cv::imread( const string& filename , ing flags = cv::IMREAD_COLOR //标志设置如何解释文件 ) 打开图像时,cv::imread() 不会查看文件扩展名。 相反,它分析文件的前几个字节(也就是它的签名 或“魔术序列”)并使用它来确定适当的编解码器。 第二个参数flags 可以设置为表中描述的几个值之一 。 默认情况下,flags 已设置 到cv::IMREAD_COLOR 。该值表示图像将作为三通道图像加载,每通道8位。 在这种情况下,即使图像实际上是文件中的灰度,存储器中的结果图像仍将具有三个通道, 所有通道包含相同的信息。或者,如果flags 设置为cv::IMREAD_GRAYSCALE , 则无论文件中的通道数如何,图像都将以灰度加载。最后一个选项是设置flags 为cv::IMREAD_ANYCOLOR。 在这种情况下,图像将“按原样”加载,如果文件是彩色,则结果为三通道,如果文件为灰度,则为单通道。 除了与颜色相关的标志之外,还cv::imread() 支持标志cv::IMREAD_ANYDEPTH, 表示如果输入图像的通道有超过8位,则应该加载它而不进行转换(即,分配的数组将是文件中指示的类型)。 cv :: imread()接受的标志 ———————————————————————————————————————————————————————————————————————————————— 参数ID 含义 默认 ———————————————————————————————————————————————————————————————————————————————— cv::IMREAD_COLOR 始终加载到三通道阵列。 yes ———————————————————————————————————————————————————————————————————————————————— cv::IMREAD_GRAYSCALE 始终加载到单通道阵列。 no ———————————————————————————————————————————————————————————————————————————————— cv::IMREAD_ANYCOLOR 通道由文件指示(最多三个)。 no ———————————————————————————————————————————————————————————————————————————————— cv::IMREAD_ANYDEPTH 允许加载超过8位深度。 no ———————————————————————————————————————————————————————————————————————————————— cv::IMREAD_UNCHANGED 相当于组合:acv::IMREAD_ANYCOLOR | cv::IMREAD_ANYDEPTH no ———————————————————————————————————————————————————————————————————————————————— 用cv::imwrite()编写文件 bool cv::imwrite( const string& filename , //输入文件名 cv::InputArray image , //要写入文件的图像 const vector<int>& params = vector<int>() //(可选)用于参数化的fmts ); 第一个参数给出了文件名,其扩展名用于确定文件的存储格式。以下是OpenCV支持的一些流行扩展: .jpg 或.jpeg :baseline JPEG; 8位; 单通道或三通道输入 .jp2 :JPEG 2000; 8位或16位; 单通道或三通道输入 .tif 或.tiff :TIFF; 8位或16位; 单通道,三通道或四通道输入 .png :PNG; 8位或16位; 单通道,三通道或四通道输入 .bmp :BMP; 8位; 单通道,三通道或四通道输入 .ppm ,.pgm :NetPBM; 8位; 单通道(PGM)或三通道(PPM) 第二个参数是要存储的图像。第三个参数用于由用于写入操作的特定文件类型接受的参数。 该params 参数需要一个整数的STL向量,这些整数是一系列参数ID, 后跟要分配给该参数的值(即,在参数ID和参数值之间交替)。 cv::imwrite()接受的参数 ———————————————————————————————————————————————————————————————————————————————— 参数ID 含义 范围 默认 ———————————————————————————————————————————————————————————————————————————————— cv::IMWRITE_JPG_QUALITY JPEG品质 0-100 95 cv::IMWRITE_PNG_COMPRESSION PNG压缩(值越高意味着压缩越多) 0-9 3 cv::IMWRITE_PXM_BINARY 对PPM,PGM或PBM文件使用二进制格式 0 or 1 1 ———————————————————————————————————————————————————————————————————————————————— cv::imwrite() 对于大多数文件格式,该功能仅存储8位,单通道或三通道图像。 灵活的图像格式(如PNG,TIFF或JPEG 2000)的后端允许存储16位或甚至浮点格式,还有一些允许存储四通道图像(BGR加alpha)。 true 如果保存成功则 返回值,如果保存不成功则返回值false 。 关于编解码器的注意事项 OpenCV附带了一些文件格式(JPEG,PNG,TIFF等)所需的编解码器。 对于每个编解码器,有三种可能:a)不包括对此编解码器的支持,b)使用随OpenCV提供的编解码器 (与其他OpenCV模块一起构建),或c)使用外部库(libjpeg, libpng等)相应地。 在Windows上,默认选项为b。 在OS X / Linux上 默认选项是c; 如果CMake没有找到编解码器,它将使用b。 如果需要,您可以明确覆盖此设置。在Linux中,如果需要选项c, 请将编解码器与开发文件一起安装(例如,libjpeg 和libjpeg-dev)。 压缩和解压缩 cv::imread() 和cv::imwrite 功能是高级工具处理许多必要的事情,以最终将图像写入磁盘或从磁盘读取。 实际上,能够单独处理这些子组件中的某些子组件通常很有用, 特别是能够在内存中压缩或解压缩映像(使用我们刚刚审查过的编解码器)。 使用cv::imencode()压缩文件 图像可以直接从OpenCV数组类型压缩。在这种情况下,结果将不是数组类型,而是一个简单的字符缓冲区。 成的对象现在采用某种格式,仅对压缩它的编解码器有意义,并且(通过构造)与原始图像的大小不同。 void cv::imencode( const string& ext , //扩展指定编解码器 cv::InputArray img , //要编码的图像 vector<uchar>& buf , //编码文件字节在这里 const vector<int>& params = vector<int>() //(可选)用于参数化的fmts ) 第一个参数cv::imencode() 是ext,表示为字符串的文件扩展名,它与所需的压缩相关联。 当然,实际上没有写入文件,但扩展不仅是一种直观的方式来引用所需的格式。 此外,扩展名是大多数操作系统用于索引可用编解码器的实际密钥。 下一个参数img 是要压缩的图像,后面的参数buf 是压缩图像将放入其中的字符数组。 此缓冲区将自动调整cv::imencode() 为压缩图像的正确大小。 最后一个参数params 用于指定要使用的特定压缩编解码器可能需要(或期望)的任何参数。 使用cv::imdecode()解压缩文件 cv::Mat cv::imdecode( cv::InputArray buf , //编码文件字节在这里 int flags = cv::IMREAD_COLOR //标志设置在这里 ) ; 就像cv::imencode() 允许我们压缩一样图片进入字符缓冲区, cv::imdecode()允许我们从字符缓冲区解压缩到图像数组。cv::imdecode() 只取两个参数, 第一个是缓冲区4 (通常有 类型),第二个是参数,它采用与使用的标志相同的选项 。与情况一样, 不需要文件扩展名( 因为它可以从缓冲区中的压缩图像的第一个字节推断出要使用的正确编解码器)。 类似cv::imread() 返回一个empty(cv::Mat::empty()==true )数组一样,如果它不能读取它给出的文件, cv::imdecode() 如果给出的缓冲区是空的,包含无效或不可用的数据,则返回一个空数组,依此类推。 【使用视频】 使用cv::VideoCapture对象读取视频 [1] cv::VideoCapture::VideoCapture( const string & filename //输入文件名 ) //可以简单地为(.mpg,.avi等)提供文件名。 //如果成功打开并且能够开始读取框架,则该成员函数cv::VideoCapture::isOpened()会返回true。 //如果由于某种原因无法打开文件(例如文件不存在),则返回的值将是false 相机"域"指示HighGUI应该在哪里寻找您的相机 ———————————————————————————————————————————————————————————————————————————————— 相机捕捉常数 | 数值 ———————————————————————————————————————————————————————————————————————————————— cv::CAP_ANY 0 cv::CAP_MIL 100 cv::CAP_VFW 200 cv::CAP_V4L 200 cv::CAP_V4L2 200 cv::CAP_FIREWIRE 300 cv::CAP_IEEE1394 300 cv::CAP_DC1394 300 cv::CAP_CMU1394 300 cv::CAP_QT 500 cv::CAP_DSHOW 700 cv::CAP_PVAPI 800 cv::CAP_OPENNI 900 cv::CAP_ANDROID 1000 ... ———————————————————————————————————————————————————————————————————————————————— 在此示例中,cv::VideoCapture::VideoCapture() 将尝试打开第一个(即数字0)FireWire相机。 在大多数情况下,当我们只有一个摄像头时,域是不必要的 {2] cv::VideoCapture::VideoCapture( int device //视频捕获设备ID ) [3] cv::VideoCapture::VideoCapture() ; cv::VideoCapture::VideoCapture() ,这将导致OpenCV打开一个窗口,允许您选择所需的摄像头。 您的最后一个选项是创建捕获对象,而不提供有关要打开的内容的任何信息。 cv::VideoCapture cap ; cap.open("my_video.avi") ; 在这种情况下,捕获对象将在那里,但在您明确打开要读取的源之前,它还没有准备好使用。 您可以使用该cv::VideoCapture::open() 方法执行此操作, 该方法与cv::VideoCapture 构造函数一样,可以将STL字符串或设备ID作为参数。 何一种情况下, 与使用相同参数cv::VideoCapture::open()调用cv::VideoCapture构造函数具有完全相同的效果。 使用 cv::VideoCapture::read() 读取框架frames bool cv::VideoCapture::read( cv::OutputArray image //要读取的图像 ) ; 使用 cv::VideoCapture::operator>>() 读取帧 cv::VideoCapture& cv::VideoCapture::operator>> ( cv:: Mat & image //要读取数据的图像 ) 除了使用read方法之外cv::VideoCapture,还可以使用重载方法函数cv::VideoCapture::operator>>() (即"流读取"运算符)从视频捕获对象中读取下一帧。 在这种情况下,cv::VideoCapture::operator>>() 行为完全相同cv::VideoCapture::read() , 除了因为它是流操作符,它返回对原始cv::VideoCapture 对象的引用,无论它是否成功。 在这种情况下,您必须检查返回数组是否为空。 用cv::VideoCapture::grab() 和 cv::VideoCapture::retrieve() 读框 而不是一次从相机或视频源拍摄一张图像,并在阅读时对其进行解码, 你可以将这个过程分解为一个抓取阶段, 它只是一个内存拷贝,还有一个检索阶段,它处理抓取数据的实际解码。 bool cv::VideoCapture::grab(void) ; bool cv::VideoCapture::retrieve( cv::OutputArray image , //要读取数据的图像 int channel = 0 //用于多头设备 ) 该cv::VideoCapture::grab()函数将当前可用的图像复制到用户不可见的内部缓冲区。 【注意】 有很多理由考研单独获取和检索,而不是像调用时一样cv::VideoCapture::read()。当存在多个相机(例如具有立体成像)时, 出现最常见的情况。在这种情况下,最重要的是使帧在时间上以尽可能小的量分开(理想情况下它们将同时用于立体成像)。 因此,最有意义的是首先抓住所有帧,然后在将它们安全地放入缓冲区后再返回并解码它们。 与cv::VideoCapture::read()情况一样 , 仅在抓取成功时才cv::VideoCapture::grab() 返回true。 一旦你抓住你的框架,你可以调用cv::VideoCapture::retrieve(), 它处理de编码以及返回框架所需的分配和复制 你作为一个cv::Mat 阵列。 除了它从 复制帧的内部缓冲区操作外,其cv::VideoCapture::retrieve()功能类似于 cv::VideoCapture::read()此cv::VideoCapture::grab()。 cv::VideoCapture::read() 和之间的另一个重要区别 cv::VideoCapture::retrieve() 是附加论点channel 。 channel 当本地访问的设备具有多个“头”(即,多个成像器)时,使用该参数。 对于专门设计用于立体成像器的设备,以及诸如Kinect的稍微更奇特的设备,通常就是这种情况。 在这些情况下,值 将指示要检索设备中的哪个图像。 【相机属性:cv::VideoCapture::get() 和 cv::VideoCapture::set() 】 从cv::VideoCapture对象中读取该信息是很常见的,有时也考研自己写入该数据区域。 cv::VideoCapture::get() 和 cv::VideoCapture::set()函数 能够让我们进行这两种操作: double cv::VideoCapture::get( int propid //属性标识符 ) bool cv::VideoCapture::set( int propid //属性标识符 double value //要设置属性的值 ) cv :: VideoCapture :: get()和cv :: VideoCapture :: set()使用的视频捕获属性 ———————————————————————————————————————————————————————————————————————————————— 视频捕获属性 仅限相机 含义 ———————————————————————————————————————————————————————————————————————————————— cv::CAP_PROP_POS_MSEC 视频文件中的当前位置(毫秒)或视频捕获时间戳 ———————————————————————————————————————————————————————————————————————————————— cv::CAP_PROP_POS_FRAMES 下一帧的从零开始的索引 ———————————————————————————————————————————————————————————————————————————————— cv::CAP_PROP_POS_AVI_RATIO 在视频相对位置(范围为0.0 至1.0 ) ———————————————————————————————————————————————————————————————————————————————— cv::CAP_PROP_FRAME_WIDTH 视频中的帧宽度 ———————————————————————————————————————————————————————————————————————————————— cv::CAP_PROP_FRAME_HEIGHT 视频中帧的高度 ———————————————————————————————————————————————————————————————————————————————— cv::CAP_PROP_FPS 录制视频的帧速率 ———————————————————————————————————————————————————————————————————————————————— cv::CAP_PROP_FOURCC 四个字符代码表示编解码器 ———————————————————————————————————————————————————————————————————————————————— cv::CAP_PROP_FRAME_COUNT 视频文件中的总帧数 ———————————————————————————————————————————————————————————————————————————————— cv::CAP_PROP_FORMAT Mat 返回的对象的格式(例如CV_8UC3 ) ———————————————————————————————————————————————————————————————————————————————— cv::CAP_PROP_MODE 表示捕获模式; 值是特定于正在使用的视频后端(例如DC1394 ) ———————————————————————————————————————————————————————————————————————————————— cv::CAP_PROP_BRIGHTNESS ✓ 相机的亮度设置(支持时) ———————————————————————————————————————————————————————————————————————————————— cv::CAP_PROP_CONTRAST ✓ 相机的对比度设置(支持时) ———————————————————————————————————————————————————————————————————————————————— cv::CAP_PROP_SATURATION ✓ 相机的饱和度设置(支持时) ———————————————————————————————————————————————————————————————————————————————— cv::CAP_PROP_HUE ✓ 相机的色调设置(支持时) ———————————————————————————————————————————————————————————————————————————————— cv::CAP_PROP_GAIN ✓ 相机增益设置(支持时) ———————————————————————————————————————————————————————————————————————————————— cv::CAP_PROP_EXPOSURE ✓ 相机的曝光设置(支持时) ———————————————————————————————————————————————————————————————————————————————— cv::CAP_PROP_CONVERT_RGB ✓ 如果非零,则捕获的图像将转换为具有三个通道 ———————————————————————————————————————————————————————————————————————————————— cv::CAP_PROP_WHITE_BALANCE ✓ 相机的白平衡设置(支持时) ———————————————————————————————————————————————————————————————————————————————— cv::CAP_PROP_RECTIFICATION ✓ 立体摄像机的整流标志(仅限DC1394-2.x) ———————————————————————————————————————————————————————————————————————————————— 解包四个字符的代码以识别视频编解码器 ———————————————————————————————————————————————————————————————————————————————— cv::VideoCapture cap("my_video.avi") ; unsigned f = (unsigned)cap.get(cv::CAP_PROP_FOURCC) ; char fourcc[] { (char) f , //第一个字符是最低位 (char) (f >> 8) , //下一个字符是8-15位 (char) (f >> 16) , //下一个字符是16-23位 (char) (f >> 24) , //最后一个字符是24-31位 } ; 对于这些视频捕获属性中的每一个,都有一个相应的cv::VideoCapture::set()函数将尝试设置该属性。 使用cv::VideoWriter对象编写视频 就像我们使用cv::VideoCapture 设备进行阅读一样, 我们必须首先创建一个cv::VideoWriter设备才能写出我们的视频。 视频编写者有两个构造函数; 一个是一个简单的默认构造函数, 它只是创建一个以后必须打开的未初始化的视频对象,另一个具有实际设置编写器所需的所有参数。 cv::VideoWriter::VideoWriter ( const string& filename , //输入文件名字 int fourcc , //codec,使用CV_FOURCC()宏 double fps , //帧率(存储在输出文件中) cv::Size frame_size , //单个图像的大小 bool is_color = true //如果为false,则可以传递灰色帧 ); 您会注意到视频编写者需要一些与视频阅读器相关的额外参数。 除了文件名之外,我们还要告诉作者使用什么编解码器,帧速率是多少以及帧的大小。 或者,我们可以告诉OpenCV帧已经是彩色的(即三通道)。 如果设置isColor 为false ,则可以传递灰度帧,视频编写器将正确处理它们 。 与视频阅读器一样,您也可以使用默认构造函数创建视频编写器, 然后 使用cv::VideoWriter::open() 方法配置writer, 该方法使用与完整构造函数相同的参数。例如: cv::VideoWriter out ; out.open( "my_video.mpg" CV_FOURCC('D','I','V','X') , //MPEG-4编解码器 30. , //帧率 cv::Size(640,480) , //以640*480分辨率写出帧 true //仅期待彩色帧 ) ; 注意: 注意 您可以使用的编解码器取决于您的操作系统安装以及已安装的其他库。 对于便携式代码,能够优雅地处理任何特定机器上没有所需编解码器的情况尤为重要。 使用cv::VideoWriter::write() 编写框架 一旦你确认您的视频编写器已准备就绪,您就可以通过简单地传递来编写帧数传给Writer: cv::VideoWriter::write( const Mat & image //要写为下一帧的图像 ); 在首次配置时,此图像的大小必须与您为编写器提供的大小相同。 如果你告诉Writer框架是彩色的,那么这也必须是一个三通道图像。 如果您向Writer指示(通过isColor )图像可能不是彩色的,则可以提供单通道(灰度)图像。 用cv::VideoWriter::operator<<() 编写框架 视频编写器还支持重载输出流运算符(operator<<())的习惯用法。 在这种情况下,一旦打开了视频编写器,就可以用与写入cout或流对象文件相同的方式将图像写入视频流: my_video_writer << my_frame ; 【数据持久性】 除了标准的视频压缩之外,OpenCV还提供了一种机制, 用于以yaml或xml格式对磁盘中的各种数据类型进行序列化和反序列化。 这些方法可用于在单个文件中加载或存储任意数量的opencv数据对象(包括诸如int、float等基本类型) 写入cv::FileStorage FileStorage::FileStorage() ; FIleStorage::FileStorage(string fileName, int flag) ; 该cv::FileStorage对象是XML或YAML数据文件的表示。你可以创建它并将文件名传递给构造函数,或者你可以 使用默认构造函数,或者你可以使用默认构造函数创建未打开的存储对象,稍后再打开: cv::FileStorage::open() flagcv::FileStorage::WRITEcv::FileStorage::APPEND fileStorage::open(string filename, int flag) ; 打开要写入的文件后,可以使用操作符cv::FileStorage::operator<<()以相同的方式编写 您可以stdout 使用STL流写入。然而,在内部,当你以这种方式写作时会有更多的事情发生。 内部数据cv::FileStorage 以两种形式之一存储, 或者作为“映射”(即键/值对)或“序列”(一系列未命名的条目)。 在顶层,您写入文件存储的数据都是映射,在该映射内部, 您可以根据需要放置其他映射或序列,以及其中的映射或序列。 myFileStorage << "someInteger" << 27 ; //保存一个整数 myFileStorage << "anArray" << cv::Mat::eye(3,3,CV_32F) ; //保存一个数组 要创建序列条目,首先要为条目提供字符串名称,然后提供条目本身。 条目可以是数字(整数、浮点数等),字符串或者任何OpenCV数据类型。 如果您想创建新的映射或序列,您可以这样做 所以使用特殊字符{(用于映射)或[(用于序列)。 一旦启动了映射或序列,就可以添加新元素,然后最终用} 或] (分别)关闭映射或序列。 myFileStorage << "theCat" << "{" ; myFileStorage << "fur" << "grey" << "eyes" << "green" << "weightLbs" << 16 ; MyFileStorage << "}" ; 创建映射后,输入每个元素,其中包含名称和后面的数据,就像你对顶层映射所做的那样。 如果创建序列,则只需逐个输入新数据,知道关闭序列。 myFileStorage << "theTeam" << "[" ; myFileStorage << "eddie" << "tom" << "scott" ; myFileStorage << "]" ; 完成写作之后,关闭文件与cv::FileStorage::release()成员函数。 使用cv::FileStorage创建.yml数据文件 ———————————————————————————————————————————————————————————————— #include "opencv2/opencv.hpp" #include "time.h" int main() { cv:L:FileStorage fs("test.yml", 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,240,0,0,1 ); cv::Mat distCoeffs = ( cv::Mat_<double>(5,1) << 0.1,0.01,-0.001,0,0 ); fs << "cameraMatrix" << cameraMatrix << "distCoeffs" << distCoeffs ; fs << "features" << "[" ; 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)&l) ; fs << "]" << "}" ; } fs << "]" ; fs.release ; return 0 ; } 运行此程序的结果将是一个YAML文件,其中包含以下内容 : %YAML:1.0 frameCount:5 calibrationDate:“Fri Jun 17 14:09:29 2011 \ n” cameraMatrix:!! opencv-matrix 行:3 cols:3 dt:d data:[1000。,0.,320。,0.,1000。,240。,0.,0.,1。 distCoeffs:!! opencv-matrix rows:5 cols:1 dt:d 数据:[1.0000000000000001e-01,1.000000000000000000e-02, -1.0000000000000000e-03,0,0。] features: - {x:167,y:49,lbp:[1,0,0,1,1,0,1,1]} - {x:298,y:130,lbp:[0,0,0,1,0,0,1,1]} - {x:344,y:158,lbp:[1,1,0,0,0,0,1,0]} 从cv::FileStorage读取 cv::FileStorage::FileStorage(string filename, int flag) ; 该cv::FileStorage 对象可以打开 阅读 与打开写入相同的方式, 除了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 对象,就可以做到下面几种事。 如果它表示一个对象(或数字或字符串), 您只需将其加载到适当类型的变量中即可重载提取运算符cv::FileNode::operator>>() cv::Mat anArray ; myFileStorage["calibrationMatrix"] >> anArray; 该cv::FileNode对象还支持直接转换为任何基本数据类型。 int aNumber ; myFileStorage["someInteger"] >> aNumber ; 这相当于: int aNumber ; aNumber = (int)myFileStorage["someInteger"] ; 如前所述,还有一个用于移动文件节点的迭代器,也可以使用它。 给定一个cv::FileNode对象,该成员函数cv::FileNode::begin()并且 cv::FileNode::end()具有它们通常的解释,即为映射或序列提供第一个和最后一个迭代器。 迭代器在使用通常的重载接触引用cv::FileNodeIterator::operator*()时将返回另外一个cv::FileNode对象。 这些迭代器支持通常的递增和递减运算符。如果迭代器迭代遍历映射,则返回的cv::FileNode对象将具有可以使用 的名称cv::FileNode::name()。 cv::FileNode的成员函数 ———————————————————————————————————————————————————————————————————————————— 例 描述 ———————————————————————————————————————————————————————————————————————————— cv::FileNode fn | 文件节点对象的默认构造函数 ————————————————————————————————————————————————————————————————————————————— cv::FileNode fn1(fn0) | 文件节点对象复制构造函数;fn1从节点创建节点fn0 —————————————————————————————————————————————————————————————————————————————— cv::FileNode fn1(fs, node) | 文件节点构造函数; cv::FileNode从C样式cvFileStorage*指针fs 和C样式cv::FileNode*指针节点创建C++样式对象 —————————————————————————————————————————————————————————————————————————————— fn[(string)key] | 命名子节点(映射节点)的STL字符串或C字符串访问器; fn[(const char*)key] | 将密钥转换为适当的子节点 —————————————————————————————————————————————————————————————————————————————— fn[(int)id] | 编号子的访问者(序列节点); 将ID转换为适当的子节点 —————————————————————————————————————————————————————————————————————————————— fn.type() | 返回节点类型enum ———————————————————————————————————————————————————————————————————————————————— fn.empty() | 确定节点是否为空 ————————————————————————————————————————————————————————————————————————————————— fn.isNone() | 确定节点是否为空 ———————————————————————————————————————————————————————————————————————————————— fn.isSeq() | 确定节点是否为序列 ———————————————————————————————————————————————————————————————————————————————— fn.isMap() | 确定node是否为映射 ———————————————————————————————————————————————————————————————————————————————— fn.isInt() | 确定节点是整数,浮点数还是字符串 fn.isReal() | fn.isString() | ———————————————————————————————————————————————————————————————————————————————— fn.name() | 如果node是映射的子节点,则返回节点名称 ———————————————————————————————————————————————————————————————————————————————— size_t sz = fn.size() | 返回序列或映射中的多个元素 ———————————————————————————————————————————————————————————————————————————————— (int)fn | 从包含整数,32位,64位浮点数或者 (float)fn | 字符串的节点中提取值 (double)fn | (string)fn | ————————————————————————————————————————————————————————————————————————————————— cv::FileNode::type()的可能返回值 —————————————————————————————————————————————————————————————————————————————————— 例 描述 —————————————————————————————————————————————————————————————————————————————————— cv::FileNode::NODE = 0 | 节点是类型double ——————————————————————————————————————————————————————————————————————————————————— cv::FileNode::INI = 1 | 节点包含一个整数 ———————————————————————————————————————————————————————————————————————————————————— cv::FileNode::REAL = 2 | 节点包含浮点数 cv::FileNode::FLOAT = 2 | ———————————————————————————————————————————————————————————————————————————————————— cv::FileNode::REF = 4 | 节点包含一个引用(即复合对象) ———————————————————————————————————————————————————————————————————————————————————— cv::FileNode::SEQ = 5 | 节点本身就是其他节点的序列 ———————————————————————————————————————————————————————————————————————————————————— cv::FileNode::MAP = 6 | 节点本身就是其他节点的映射 ———————————————————————————————————————————————————————————————————————————————————— cv::FileNode::FLOW = 8 | 节点是序列或映射的紧凑表示 ———————————————————————————————————————————————————————————————————————————————————— cv::FileNode::USER = 16 | 节点是注册对象(例如,矩阵) ———————————————————————————————————————————————————————————————————————————————————— cv::FileNOde::EMPTY = 32 | 节点没有分配给它的值 ———————————————————————————————————————————————————————————————————————————————————— cv::FileNode::NAMED = 64 | Node是映射的子节点(即它有一个名称) ————————————————————————————————————————————————————————————————————————————————————— 使用cv::FileStorage读取.yml文件 —————————————————————————————————————————————————————————————————————————————————————— cv :: FileStorage fs2(“test.yml”,cv :: FileStorage :: READ); //第一种方法:在FileNode上使用(type)运算符。 int frameCount =(int)fs2 [“frameCount”]; //第二种方法:使用cv :: FileNode :: operator >> // std :: string date; fs2 [“calibrationDate”] >>日期; cv :: Mat cameraMatrix2,distCoeffs2; fs2 [“cameraMatrix”] >> cameraMatrix2; fs2 [“distCoeffs”] >> distCoeffs2; cout <<“frameCount:”<< frameCount << endl <<“校准日期:”<< date << endl <<“相机矩阵:”<< cameraMatrix2 << endl <<“畸变系数:”<< distCoeffs2 << endl; cv :: FileNode features = fs2 [“features”]; cv :: FileNodeIterator it = features.begin(),it_end = features.end(); int idx = 0; std :: vector <uchar> lbpval; //使用FileNodeIterator迭代序列 for(; it!= it_end; ++ it,idx ++) { cout <<“feature#”<< idx <<“:”; cout <<“x =”<<(int)(* it)[“x”] <<“,y =”<<(int)(* it)[“y”] <<“,lbp:(” ; //(注意:使用FileNode >> std :: vector轻松读取数值数组。) // (* it)[“lbp”] >> lbpval; for(int i = 0; i <(int)lbpval.size(); i ++) cout <<“”<<(int)lbpval [i]; cout <<“)”<< endl; } fs.release();
Talk is cheap. Show me the code