Opencv文件操作与数据存储
- 格式:doc
- 大小:69.00 KB
- 文档页数:4
C++的OpenCV使用方法总结在计算机视觉和图像处理领域,OpenCV是一个非常强大的开源库,它提供了丰富的功能和工具,用于处理图像和视频。
作为C++程序员,了解并熟练使用OpenCV库是非常重要的。
本文将对C++中使用OpenCV的方法进行总结,并探讨一些常见的应用和技巧。
一、安装和配置OpenCV在开始使用OpenCV之前,首先需要安装和配置这个库。
在Windows评台上,可以通过下载预编译的二进制文件进行安装;在Linux评台上,可以通过包管理器进行安装。
安装完毕后,还需进行一些环境配置,确保编译器能够正确信息OpenCV库文件。
二、基本图像处理1. 读取和显示图像在C++中使用OpenCV读取和显示图像非常简单,只需几行代码即可完成。
首先需要使用imread函数读取图像文件,然后使用imshow 函数显示图像。
在进行图像显示后,需要使用waitKey函数等待用户按下某个键,以便关闭显示窗口。
2. 图像的基本操作OpenCV提供了丰富的图像处理函数,包括图像缩放、旋转、平移、通道拆分与合并等。
这些函数可以帮助我们对图像进行各种基本操作,从而满足不同的需求。
三、特征提取与描述1. Harris角点检测Harris角点检测是一种经典的特征点检测方法,它可以用来识别图像中的角点。
在OpenCV中,我们可以使用cornerHarris函数来实现Harris角点检测,然后对检测结果进行筛选和标记。
2. SIFT特征提取SIFT是一种广泛应用的特征提取算法,它具有旋转不变性和尺度不变性。
在OpenCV中,我们可以使用SIFT算法来提取图像的关键点和特征描述子,从而实现图像匹配和目标识别等功能。
四、图像分类与识别1. 使用支持向量机(SVM)进行图像分类OpenCV提供了对机器学习算法的支持,包括SVM分类器。
我们可以使用SVM对图像进行分类,从而实现图像识别和目标检测等功能。
2. 使用深度学习模型进行图像识别近年来,深度学习在图像识别领域取得了显著的成就。
OpenCV FileStorage类读写XML/YML文件在OpenCV程序中,需要保存中间结果的时候常常会使用.xml / .yml文件,opencv2.0之前都是使用C风格的代码,当时读写XML文件分别使用函数cvLoad()和cvSave()。
在2.0以后的OpenCV转为支持C++,这一举措大大减少了代码量以及编程时需要考虑的细节。
新版本的OpenCV的C++接口中,imwrite()和imread()只能保存整数数据,且需要以图像格式。
当需要保存浮点数据或者XML/YML文件时,之前的C语言接口cvSave()函数已经在C++接口中被删除,代替它的是FileStorage类。
这个类非常的方便,封装了很多数据结构的细节,编程的时候可以根据统一的接口对数据结构进行保存。
1. FileStorage类写XML/YML文件•新建一个FileStorage对象,以FileStorage::WRITE的方式打开一个文件。
•使用<< 操作对该文件进行操作。
•释放该对象,对文件进行关闭。
例子如下:FileStorage fs("test.yml", FileStorage::WRITE);fs << "frameCount" << 5;time_t rawtime; time(&rawtime);fs << "calibrationDate" << asctime(localtime(&rawtime));Mat cameraMatrix = (Mat_<double>(3,3) << 1000, 0, 320, 0, 1000, 240, 0, 0, 1); //又一种Mat初始化方式Mat distCoeffs = (Mat_<double>(5,1) << 0.1, 0.01, -0.001, 0, 0);fs << "cameraMatrix" << cameraMatrix << "distCoeffs" << distCoeffs;//features为一个大小为3的向量,其中每个元素由随机数x,y和大小为8的uchar数组组成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) & 1);fs << "]" << "}";}fs << "]";fs.release();2. FileStorage类读XML/YML文件FileStorage对存储内容在内存中是以层次的节点组成的,每个节点类型为FileNode,FileNode可以使单个的数值、数组或者一系列FileNode的集合。
imread 读图namedWindow 产生一个被命名的窗口imshow 显示图像using namespace 全局的命名空间,可以避免导致全局命名冲突问题。
cv表示opencv的命名空间std是标准输入输出的命名空间waitKey 程序运行等待时间ms为单位#include<opencv2/highgui/highgui.hpp> 包含输入输出操作#include<iostream> VC的标准输入输出cout << 输出cin>> 输入均以endl结尾#include<string> 字符串库cvtColor 彩色图像变灰度图像imwrite 写出图像F9设置断点F5调试运行后点击变量中的+显示数据结构argv[1]的定位方式为:在工程属性中,命令行参数添加路径,例如:#include<opencv2/core/core.hpp> 定义的基本构建块库Mat 基本图像容器,是一个矩阵类。
用法:Mat A; //定义矩阵Mat B(A);//复制A矩阵数据给BMat D(A,Rect(10, 10, 100, 100)); //将A矩阵的一个区域给DMat F = A.clone();//复制A矩阵数据给FMat M(2,2,CV_8UC3,Scalar(0,0,255));//创建一个矩阵,2×2大小,数据结构为CV_[每个数据占用BIT][Signed or Unsigned][Type Prefix]C[取前几个数或书写几遍] Scalar数据向量。
Signed有符号:8位数据范围为:-128~127Unsigned无符号:8位数据范围为:0~255Mat::eye(4, 4,CV_64F) //单位矩阵Mat::ones(2, 2,CV_32F) //全1矩阵Mat::zeros(3,3,CV_8UC1) //全0矩阵Mat C = (Mat_<double>(3,3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);//常规矩阵定义randu(R,Scalar::all(0),Scalar::all(255));//任意矩阵的生成Point2f P(5, 1);//定义二维点Point3f P3f(2, 6, 7); //定义三维点vector<float> v;//定义浮点数向量vector<Point2f> vPoints(20);//定义点坐标(二维数据)向量uchar就是uint8加注const 不能改变参数值;sizeof 读取大小I.channels(); //图像维数I.rows; //图像的行数I.cols;//图像的列数I.depth();//图像的深度对于图像的点式处理:uchar* p;//定义一个uint8图像for(i = 0;i < nRows; ++i){p = I.ptr<uchar>(i); //将每一行的向量赋给pfor (j = 0;j < nCols; ++j){p[j] = table[p[j]];//对每一行的向量,每一列的元素进行赋值,table是变换好的数组}}或者:uchar* p = I.data;//将图像的数据空间给pfor( unsigned int i =0;i < ncol*nrows; ++i)*p++ = table[*p];//*p中存储了图像的数据,一个一个赋值或者:LUT(I,lookUpTable,J); //效率最高的读图方式Mat lookUpTable(1, 256,CV_8U);uchar * p2 = lookUpTable.data;for( int i = 0;i < 256; ++i)p2[i] = table[i];图像的RGB分离:const int channels = I.channels();switch(channels){case 1:{MatIterator_<uchar> it,end;//灰度图像的变换for(it = I.begin<uchar>(),end = I.end<uchar>();it != end; ++it)*it = table[*it];break;}case 3:{MatIterator_<Vec3b> it,end;//RGB图像的变换for(it = I.begin<Vec3b>(),end = I.end<Vec3b>();it != end; ++it)//<Vec3b>指三列向量,即三个通道分量{(*it)[0] = table[(*it)[0]];//B分量(*it)[1] = table[(*it)[1]]; //G分量(*it)[2] = table[(*it)[2]]; //R分量}}}或者:case 3:{Mat_<Vec3b> _I = I;for( int i = 0;i < I.rows; ++i)for( int j = 0;j < I.cols; ++j){_I(i,j)[0] = table[_I(i,j)[0]];_I(i,j)[1] = table[_I(i,j)[1]];_I(i,j)[2] = table[_I(i,j)[2]];}I = _I;break;}Mat& ScanImageAndReduceC(Mat& I, const uchar* const table)//看图函数Mat& ScanImageAndReduceIterator(Mat& I, const uchar* const table) //看图函数Mat& ScanImageAndReduceRandomAccess(Mat& I, const uchar* const table) //看图函数模板运算:void Sharpen(const Mat& myImage, Mat& Result) //图像锐化函数CV_Assert(myImage.depth() == CV_8U); //判决图像是否是整型的数据Result.create(myImage.size(),myImage.type());//创建MAT矩阵类型执行算法:for(int j = 1 ;j < myImage.rows-1; ++j){const uchar* previous = myImage.ptr<uchar>(j - 1);const uchar* current = myIma ge.ptr<uchar>(j);const uchar* next = myImage.ptr<uchar>(j + 1);uchar* output = Result.ptr<uchar>(j);for(int i= nChannels;i < nChannels*(myImage.cols-1); ++i){*output++ = saturate_cast<uchar>(5*current[i]-current[i-nChannels] - current[i+nChannels] - previous[i] - next[i]);}}Result.row(0).setTo(Scalar(0));//将0行的像素值设为0或者:Mat kern = (Mat_<char>(3,3) << 0, -1, 0,-1, 5, -1,0, -1, 0);filter2D(I,K,I.depth(),kern);//使用模板滤波锐化图像,该函数所在库为<opencv2/imgproc/imgproc.hpp>图像融合算法:addWeighted(src1,alpha,src2,beta, 0.0,dst);//融合函数,需两幅图像一样大图像的亮度调整算法:相应的代码for( int y = 0;y < image.rows;y++ ){ for( int x = 0;x < image.cols;x++ ){ for( int c = 0;c < 3;c++ ) //三个通道分别运算{new_image.at<Vec3b>(y,x)[c] =saturate_cast<uchar>(alpha*(image.at<Vec3b>(y,x)[c]) + beta);}}}Mat::zeros(image.size(),image.type());//创建0阵image.convertTo(new_image, -1,alpha,beta);//线性图像变换图元:Point pt = Point(10, 8);//点的坐标Scalar(B,G,R) ;//给出像素的颜色值ellipse( img,Point(x,y),Size(x,y), angle,0, 360,Scalar( 255, 0, 0 ),thickness, lineType );//画椭圆,img图像名,point中心点,size大小,angle角度,0,起始点角度,360终点角度,scalar色彩,thickness线宽(-1为全填充),lineType 线型;调用时凡是给定的参数不管,只需给出其他参数,例如Ellipse( atom_image, 90 );给出了图像名和角度,其他量为已知。
读入图像﹑显示图像和保存图像是图像处理过程中最基本的,也是必不可少的操作.配置好OpenCV以后,包含以下两个头文件:#include "cv.h"#include "highgui.h"IplImage* image=cvLoadImage("D:\\123.jpg",-1);//函数cvLoadImage()的第1个参数是图像文件的路径.//第2个参数是读取图像的方式:-1表示按照图像本身的类型来读取,1表示强制彩色化,0表示//强制灰值化.if(image==NULL){MessageBox("无法读取图像数据!", "提示",MB_OK);//在MFC工程中这样用//若在win32控制台程序中,用printf("无法读取图像数据!\n");return;//不作任何操作,就不会执行后面的程序了}cvNamedWindow("图像显示",CV_WINDOW_AUTOSIZE);//该函数的功能是按照指定方式创建一个窗口,用于显示图像.//第1个参数是窗口的名称,自己可以任意设置//第2个参数表示窗口的大小会自动根据图像尺寸而变化cvShowImage("图像显示",image);//该函数的功能是在指定的窗口上显示图像.//第1个参数是显示图像窗口的名称//第2个参数是要显示的图像cvSaveImage("D:\\saveImage.jpg",image);//该函数的功能是将图像另存为//第1个参数是保存的路径,自己可以设置其它路径//第2个参数是要保存的图像cvWaitKey(0);//一直等待按键没有这句的话图像不能正常显示cvReleaseImage(&image);//释放图像内存cvDestroyWindow("图像显示");//销毁窗口资源//读取和显示完图像之后,要及时释放所占的内存资源.运行示例:。
CVMat是OpenCV中用于表示和操作图像的数据类型之一。
在图像处理和计算机视觉应用中,经常需要对图像进行像素级的操作,而读取像素值是其中一个基本操作。
掌握CVMat高效读取像素值的方法对于图像处理的效率至关重要。
1. CVMat简介CVMat是OpenCV中用于存储图像数据的多维数组类型。
它允许用户访问和操作图像的像素值,并提供了丰富的函数和方法用于图像处理、分析和计算。
CVMat类型的对象可以直接从文件中读取图像数据,也可以由用户创建,并通过矩阵操作进行图像处理。
2. 像素值的表示在CVMat中,图像的像素值通常以矩阵的形式存储。
对于灰度图像,每个像素值由一个标量表示;对于彩色图像,每个像素值通常由三个标量表示,分别代表红、绿、蓝三个通道的数值。
读取像素值的基本操作就是获取对应位置的标量或标量组。
3. 读取灰度图像的像素值在CVMat中,可以使用"at<>"方法来获取特定位置的像素值。
对于灰度图像mat,可以使用mat.at<uchar>(i, j)来获取第i行第j列位置的像素值,其中uchar表示像素值的数据类型。
这种方法直接通过索引来访问像素值,效率较高。
4. 读取彩色图像的像素值对于彩色图像,由于每个像素点有三个通道的像素值,因此需要使用Vec3b类型来表示。
对于彩色图像mat,可以使用mat.at<Vec3b>(i, j)来获取第i行第j列位置的像素值,返回一个包含三个标量的Vec3b对象。
同样地,这种方法也是直接通过索引来访问像素值,效率也较高。
5. 使用指针访问像素值除了直接使用at<>方法来访问像素值外,还可以使用指针来加速像素值的读取操作。
通过将CVMat对象的数据指针进行类型转换,可以直接通过指针来访问像素值,从而避免了at<>方法中的索引操作,提高了读取像素值的效率。
6. 读取像素值的性能比较针对不同的图像处理应用场景,可以根据实际需求选择不同的方法来读取像素值。
目录1引言 (1)2 OpenCV的结构 (1)3 VC 6下的安装与配置 (2)3.1安装OpenCV(略) (2)3.2 配置Windows环境变量 (2)4 VC++的环境设置 (4)5如何创建一个项目来开始OpenCV 编程 (5)6如何读入和显示图像 (7)7如何访问图像像素 (10)8如何访问矩阵元素 (11)9如何在OpenCV 中处理我自己的数据 (12)10. 例程 (13)10.1 Kalman滤波进行旋转点的跟踪 (13)10.2 背景建模 (16)10.3 视频I/O (21)10.4 矩阵操作 (23)10.5 轮廓检测 (27)1引言OpenCV(Intel® Open Source Computer Vision Library) 是Intel 公司面向应用程序开发者开发的计算机视觉库,其中包含大量的函数用来处理计算机视觉领域中常见的问题,例如运动分析和跟踪、人脸识别、3D 重建和目标识别等。
目前该函数库的最新版本是OpenCV 4.0,可以通过访问/projects/opencvlibrary免费获得OpenCV 库以及相关的资料。
另外,还可以通过访问/group/OpenCV,对于OpenCV使用中的一些问题与经验进行讨论。
相对于其它图像函数库,OpenCV是一种源码开放式的函数库,开发者可以自由地调用函数库中的相关处理函数。
OpenCV中包含500多个处理函数,具备强大的图像和矩阵运算能力,可以大大减少开发者的编程工作量,有效提高开发效率和程序运行的可靠性。
另外,由于OpenCV具有很好的移植性,开发者可以根据需要在MS-Windows和Linux两种平台进行开发,速度快,使用方便。
2 OpenCV的结构目前OpenCV包含如下几个部分:Cxcore: 一些基本函数(各种数据类型的基本运算等)Cv: 图像处理和计算机视觉功能(图像处理,结构分析,运动分析,物体跟踪,模式识别,摄像定标)Highgui: 用户交互部分(GUI, 图像视频I/O, 系统调用函数)Cvaux: 一些实验性的函数(ViewMorphing, 三维跟踪,PCA,HMM)另外还有cvcam, 不过linux版本中已经抛弃。
一、介绍OpenCV是一个开源计算机视觉库,提供了丰富的图像处理和计算机视觉功能,可以用于各种应用领域,如图像处理、目标检测、人脸识别等。
本文将介绍如何使用Python代码轻松入门OpenCV,帮助读者快速掌握OpenCV的基本使用方法。
二、安装在开始学习OpenCV之前,首先需要安装OpenCV库。
可以通过命令行或者Anaconda来安装OpenCV,具体安装方法可以参考OpenCV冠方全球信息站提供的安装教程。
安装完成后,需要确保OpenCV库已经成功导入到Python环境中。
三、图像加载与显示1. 导入必要的库在Python代码中,首先需要导入OpenCV库和NumPy库。
OpenCV库提供了图像处理的函数,NumPy库用于数组操作和数学计算。
```pythonimport cv2import numpy as np```2. 读取图像文件使用`cv2.imread()`函数可以读取图像文件,并将图像数据存储为一个多维数组。
```pythonimg = cv2.imread('image.jpg')```3. 显示图像使用`cv2.imshow()`函数可以显示图像,需要指定显示窗口的名称和要显示的图像数据。
```pythoncv2.imshow('image', img)cv2.w本人tKey(0)cv2.destroyAllWindows()```四、图像处理1. 灰度转换使用`cv2.cvtColor()`函数可以将彩色图像转换为灰度图像。
```pythongray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)```2. 边缘检测使用`cv2.Canny()`函数可以进行边缘检测,需要指定阈值参数。
```pythonedges = cv2.Canny(gray_img, 100, 200)```五、图像保存使用`cv2.imwrite()`函数可以将处理后的图像保存为文件。
opencv mat的ptr用法摘要:一、Mat的基本概念二、Ptr的定义与用法三、Mat与Ptr的关系四、Ptr的应用场景五、使用Ptr的注意事项正文:一、Mat的基本概念Mat是OpenCV中用于处理二维图像数据的一种数据结构。
它是一个类似于C++的数组,但是专门用于存储图像数据,具有很多方便的函数和方法。
在OpenCV中,Mat可以使用多种数据类型,如float、double、uchar等。
二、Ptr的定义与用法Ptr是OpenCV中用于操作Mat对象的一种指针类型。
它类似于C++的指针,但具有更高的安全性。
Ptr内部使用智能指针(std::shared_ptr)实现,自动管理内存,避免了内存泄漏的风险。
使用Ptr时,需要包含opencv2/core/core.hpp头文件。
以下是一个简单的Ptr用法示例:```cpp#include <iostream>#include <opencv2/core/core.hpp>int main() {cv::Mat mat(512, 512, CV_8UC1, cv::Scalar(255));cv::Ptr<cv::Mat> ptr_mat = mat;// 对mat进行操作// ...return 0;}```三、Mat与Ptr的关系Mat和Ptr之间存在密切的关系。
Ptr可以看作是Mat的一种轻量级包装,它将Mat对象的管理交给智能指针,使得程序员可以更专注于图像处理的逻辑,而不用担心内存管理。
在实际编程中,可以使用Ptr来操作Mat对象,从而提高代码的可读性和实用性。
四、Ptr的应用场景1.动态分配Mat对象:在需要处理大量图像数据时,可以使用Ptr动态分配Mat对象,以避免内存不足的问题。
```cppcv::Ptr<cv::Mat> ptr_mat(new cv::Mat(512, 512, CV_8UC1));```2.矩阵运算:使用Ptr可以方便地进行矩阵运算,如加法、减法、点乘等。
openCV读取XML⽂件基本操作openCV读取XML⽂件基本操作与保存XML⽂件操作类似,也有cvReadInt之类的函数,和保存struct相对应,读取的时候可以先选择节点(保存时的struct名称),再选择数据;如果保存数据时是没有名称,譬如CV_NODE_SEQ模式,直接选择cvReadInt(),如果有名称,譬如CV_NODE_MAP模式,选择cvReadIntByName()进⾏读取。
<?xml version="1.0"?><opencv_storage><int>100</int><bool_true>1</bool_true><bool_false>0</bool_false><float>9.9870002746582031e+001</float><string>"this is a string"</string><slParams><slParams_projWidth>1140</slParams_projWidth><slParams_projHeight>912</slParams_projHeight><slParams_camWidth>1024</slParams_camWidth><slParams_camHeight>1280</slParams_camHeight><slParams_colEncode>1</slParams_colEncode><slParams_rowEncode>0</slParams_rowEncode></slParams><point>2 3</point></opencv_storage>例如要读取以上的xml⽂件中的数据,使⽤cvReadInt()系类的函数,其中第⼀个参数是打开⽂件的名称,第⼆个是所要读取的数据的节点名称,对于直接存放在xml下的数据,节点为NULL,保存在xml时存放在sruct中的数据,节点就是struct的名称,如果是CV_NODE_MAP模式或者XML下的数据,⽤cvReadIntByName(),存储节点的类型为CvFileNode,取节点名称的函数为cvGetFileNodeByName()。
C语言在图像处理中的应用图像处理是一门将数字图像进行分析、处理和改进的技术和方法。
在现代科学与技术的发展中,图像处理技术已经广泛应用于许多领域,包括计算机视觉、医学影像、人工智能等。
而C语言作为一种高效的程序设计语言,也在图像处理领域发挥着重要的作用。
本文将介绍C语言在图像处理中的应用。
一、图像数据的表示与存储图像数据是以像素为基本单位的二维矩阵,每个像素点的值表示了该点的亮度或颜色等信息。
对于灰度图像,像素值通常为0~255之间的整数,表示了不同灰度级的信息。
而对于彩色图像,每个像素点通常有三个通道,分别表示红、绿和蓝等颜色分量。
在C语言中,可以使用二维数组来表示图像数据,并通过循环来对像素进行操作。
此外,C语言还可以通过文件操作实现图像数据的读取和存储,例如使用标准库函数将图像数据保存为位图文件或其他格式。
二、基本图像处理操作在图像处理中,常见的基本操作包括图像的读取、显示、缩放、旋转、灰度化、二值化等。
C语言提供了多种图像处理库,例如OpenCV、SDL等,这些库可以方便地实现各种图像处理操作。
通过使用这些库,可以使用C语言来读取图像文件,对图像进行各种处理,并将处理后的图像显示到屏幕上。
三、图像滤波与增强滤波是图像处理中的一项关键技术,通过滤波可以改变图像的频域特性,实现图像的平滑、锐化、边缘检测等效果。
在C语言中,可以通过设计不同的滤波算法来实现对图像的处理操作。
例如,使用卷积操作可以实现一维或二维滤波,常见的滤波算法包括均值滤波、高斯滤波、中值滤波等。
通过这些滤波算法,可以对图像进行平滑处理、降噪等操作,提高图像的质量和清晰度。
四、图像分割与识别图像分割是将图像分成若干个具有独立意义的区域的过程,通常是为了更好地进行图像识别和分析。
在C语言中,可以使用各种图像分割算法来实现对图像中目标的分割,例如基于阈值的分割、区域生长算法、边缘检测等。
图像识别则是将图像中的目标与已知模式进行匹配,通常包括特征提取、特征匹配等步骤。
cv2.imwrite函数的用法一、概述OpenCV(开源计算机视觉库)提供了许多图像处理和计算机视觉功能,其中包括对图像的写入操作。
cv2.imwrite函数是OpenCV中用于将图像写入文件的主要函数之一。
它可以将指定的图像数据保存为指定的文件格式。
二、函数定义cv2.imwrite(filename,img[,args])是cv2库中imwrite函数的基本形式。
filename是要保存的文件名,img是要保存的图像数据,args是一个可选参数,用于指定保存图像时的相关参数。
三、参数说明1.filename:要保存的文件名。
可以是绝对路径或相对路径,但必须是有效的文件名。
2.img:要保存的图像数据。
可以是numpy数组、PIL图像对象或其他可转换为numpy数组的对象。
3.args:可选参数,用于指定保存图像时的相关参数。
可以指定不同的文件格式、压缩质量、写入模式等。
四、使用示例下面是一个简单的使用cv2.imwrite函数的示例代码:```pythonimportcv2importnumpyasnp#创建一个灰度图像img=np.random.randint(0,256,(512,512),dtype=np.uint8)#将图像保存为PNG格式文件cv2.imwrite('output.png',img)#将图像保存为JPEG格式文件,并设置压缩质量为0.95cv2.imwrite('output.jpg',img,{'quality':0.95})```在上面的示例中,我们首先创建了一个随机生成的灰度图像,然后使用cv2.imwrite函数将其保存为PNG和JPEG格式的文件。
在保存JPEG格式文件时,我们通过args参数设置了压缩质量为0.95。
五、注意事项1.在使用cv2.imwrite函数时,确保提供的图像数据是有效的,并且与指定的文件格式兼容。
一、介绍OpenCV是一个开源的计算机视觉库,提供了大量的图像处理和计算机视觉算法,广泛应用于图像处理、模式识别、计算机视觉等领域。
在OpenCV中,BMP(Bitmap)是一种常见的图像文件格式,它以其简单的存储结构和广泛的应用而闻名。
二、BMP格式简介1. BMP图像文件格式是Windows操作系统中最常见的图像文件格式之一。
2. BMP格式的图像数据以像素点阵列存储,每个像素用24位或32位的RGB值表示。
3. BMP格式的文件头包含文件类型、文件大小、图像数据偏移量等信息。
4. BMP格式的图像数据按从左到右、从下到上的顺序排列。
三、OpenCV中的BMP处理1. OpenCV提供了对BMP格式图像文件的读取和写入功能,可以利用OpenCV读取BMP格式的图像文件,并对其进行各种图像处理操作。
2. 通过OpenCV的imread()函数可以读取BMP格式的图像文件,并返回一个Mat对象,方便对图像进行处理。
3. 通过OpenCV的imwrite()函数可以将处理后的图像保存为BMP格式的文件,方便后续的使用和展示。
四、BMP格式的优势1. BMP格式的图像数据存储方式简单,易于理解和处理。
2. BMP格式的图像文件大小相对较小,适合在存储和传输时使用。
3. BMP格式的图像在Windows系统中具有较好的兼容性,可在多种软件和设备中进行展示和使用。
五、BMP格式的局限性1. BMP格式不支持压缩,因此其文件大小相对较大,在存储和传输时可能占用较多的空间和带宽。
2. BMP格式的图像不能包含透明通道信息,无法实现半透明效果。
3. BMP格式不支持多帧图像,无法存储动态图像或视瓶。
六、BMP格式的应用场景1. 由于BMP格式的存储结构简单、易于处理,因此在一些对图像质量要求不高、但对图像处理速度和实时性要求较高的场景中得到广泛应用,如监控摄像头图像处理、工业自动化图像处理等。
2. 由于BMP格式的文件大小相对较小,适合在一些资源受限的环境中进行图像存储和传输,如嵌入式系统、传感器网络等。
OpenCV探索之路(⼗⼋):使⽤imwrite调整保存的图⽚质量近⽇在⽤opencv做⼀些图像处理的操作时,需要对⼀些⾼分辨率的图像进⾏保存。
⽐如,在操作⼀个容量为230M的图像后,并对该图像保存为JPG格式后,发现图像容量变为80M了!针对这个问题,忙了⼤半天,到处翻阅资料,终于知道为什么了。
先举个例⼦说明⾃⼰遇到的问题,为了看出效果,我特意⽤了⼀个⾼分辨率的图⽚做实验。
⽐如我有如下的⼀个233M的图⽚经过下⾯的程序读进内存,再次保存后,图⽚容量就急剧变⼩了!#include<opencv2\opencv.hpp>#include<opencv2\highgui\highgui.hpp>using namespace std;using namespace cv;int main(int argc, char** argv){Mat img = imread("src1.jpg");imwrite("test.jpg", img);return 0;}保存后的图⽚,只剩下126M了!怎么回事!我什么都没做啊,图⽚⼤⼩怎么就⼤⼤缩⽔了呢?通过翻阅⼀些资料才知道,原来是图⽚格式惹得祸。
其实有些图⽚格式是⾃带压缩的,⽐如jpg格式,⽽bmp格式的图⽚是不带任何压缩,这就是每种图⽚的特点,如果对这些知识点不清楚的话,很容易踩坑!平时我们操作的图像⼤⼩⼤多数都以KB为单位,所以经过⼀番“隐形压缩”后我们很难发现图⽚⼤⼩变⼩了,但是,当我们操作⼤图的时候,这种压缩效果⼀下⼦就看出来了。
那么如果我们在使⽤imwrite保存图⽚时想提⾼保存图⽚的质量,该如何操作?要改变保存的图⽚的质量,关键在于imwrite函数的第三个参数。
先看imwrite的声明CV_EXPORTS_W bool imwrite( const String& filename, InputArray img, const std::vector<int>& params = std::vector<int>());第三个参数说明:const std::vector&类型的params,表⽰为特定格式保存的参数编码,它有默认值std::vector(),所以⼀般情况下不需要填写。
数据存储OpenCV提供了一种机制来序列化(serialize)和去序列化(de-serialize)其各种数据类型,可以从磁盘中按YAML或XML格式读/写。
在第4章中,我们将专门介绍存储和调用常见的对象IplImages的函数(cvSaveImage()和cvLoadImage())。
此外,第4章将讨论读/写视频的特有函数:可以从文件或者摄影机中读取数据的函数cvGrabFrame()以及写操作函数cvCreateVideoWriter()和cvWriteFrame()。
本小节将侧重于一般对象的永久存储:读/写矩阵、OpenCV结构、配置与日志文件。
首先,我们从有效且简便的OpenCV矩阵的保存和读取功能函数开始。
函数是cvSave()和cvLoad()。
例3-15展示了如何保存和读取一个5×5的单位矩阵(对角线上是1,其余地方都是0)。
例3-15:存储和读取CvMat1.CvMat A= cvMat( 5, 5, CV_32F, the_matrix_data );2.3.cvSave( "my_matrix.xml", &A );4.. . .5.// to load it then in some other program use …6.CvMat* A1= (CvMat*) cvLoad( "my_matrix.xml" );CxCore参考手册中有整节内容都在讨论数据存储。
首先要知道,在OpenCV中,一般的数据存储要先创建一个CvFileStorage结构(如例3-16)所示,该结构将内存对象存储在一个树形结构中。
然后通过使用CV_STORAGE_READ参数的cvOpenFileStorage()从磁盘读取数据,创建填充该结构,也可以通过使用CV_STORAGE_WRITE的cvOpenFileStorage()创建并打开CvFileStorage写数据,而后使用适当的数据存储函数来填充它。
在磁盘上,数据的存储格式为XML或者YAML。
例3-16:CvFileStorage结构,数据通过CxCore数据存储函数访问1.typedef struct CvFileStorage2.{3.... // hidden fields4.} CvFileStorage;CvFileStorage树内部的数据是一个层次化的数据集合,包括标量、CxCore对象(矩阵、序列和图)以及用户定义的对象。
假如有一个配置文件或日志文件。
配置文件告诉我们视频有多少帧(10),画面大小(320×240)并且将应用一个3×3的色彩转换矩阵。
例3-17展示了如何从磁盘中调出cfg.xml文件。
例3-17:往磁盘上写一个配置文件cfg.xml1.CvFileStorage* fs= cvOpenFileStorage(2."cfg.xml",3.0,4.CV_STORAGE_WRITE5.);6.cvWriteInt( fs, "frame_count", 10 );7.cvStartWriteStruct( fs, "frame_size", CV_NODE_SEQ );8.cvWriteInt( fs, 0, 320 );9.cvWriteInt( fs, 0, 200 );10.cvEndWriteStruct(fs);11.cvWrite( fs, "color_cvt_matrix", cmatrix );12.cvReleaseFileStorage( &fs );请留意这个例子中的一些关键函数。
我们可以定义一个整型变量通过cvWritelnt()向结构中写数据。
我们也可以使用cvStartWriteStruct()来创建任意一个可以任选一个名称(如果无名称请输入0或NULL)的结构。
这个结构有两个未命名的整型变量,使用cvEndWriteStruct()结束编写结构。
如果有更多的结构体,我们用相似的方法来解决;这种结构可以进行任意深度的嵌套。
最后,我们使用cvWrite()编写处色彩转换矩阵。
将这个相对复杂的矩阵程序与例3-15中简单的cvSave()程序进行对比。
便会发现cvSave()是cvWrite()在只保存一个矩阵时的快捷方式。
当写完数据后,使用cvReleaseFileStorage()释放CvFileStorage句柄。
例3-18显示了XML格式的输出内容。
例3-18:磁盘中的cfg.xml文件1.<?xml version="1.0"?>2.<opencv_storage>3.<frame_count>10</frame_count>4.<frame_size>320 200</frame_size>5.<color_cvt_matrix type_id="opencv-matrix">6.<rows>3</rows><cols>3</cols>7.<dt>f</dt>8.<data>...</data></color_cvt_matrix>9.</opencv_storage>我们将会在例3-19中将这个配置文件读入。
例3-19:磁盘中的cfg.xml文件1.CvFileStorage* fs= cvOpenFileStorage(2."cfg.xml",3.0,4.CV_STORAGE_READ5.);6.7.int frame_count= cvReadIntByName(8.fs,9.0,10."frame_count",11. 5 /* default value */12.);13.14.CvSeq* s= cvGetFileNodeByName(fs,0,"frame_size")->data.seq;15.16.int frame_width= cvReadInt(17.(CvFileNode*)cvGetSeqElem(s,0)18.);19.20.int frame_height= cvReadInt(21.(CvFileNode*)cvGetSeqElem(s,1)22.);23.24.CvMat* color_cvt_matrix= (CvMat*) cvReadByName(25.fs,26.0,27."color_cvt_matrix"28.);29.30.cvReleaseFileStorage( &fs );在阅读时,我们像例3-19中那样用cvOpenFileStorage()打开XML配置文件。
然后用cvReadlntByName()来读取frame_count,如果有没有读到的数,则赋一个默认值。
在这个例子中默认的值是5。
然后使用cvGetFileNodeByName()得到结构体frame_size。
在这里我们用cvReadlnt()读两个无名称的整型数据。
随后使用cvReadByName()读出我们已经定义的色彩转换矩阵。
将本例与例3-15中的cvLoad()进行对比。
如果我们只有一个矩阵要读取,那么可以使用cvLoad(),但是如果矩阵是内嵌在一个较大的结构中,必须使用cvRead()。
最后,释放CvFileStorage结构。
数据函数存储与CvFileStorage结构相关的表单列在表3-16中。
想了解更多细节,请查看CxCore手册。
表3-16:数据存储函数续表This line causes the error:> cvWrite(myFileStorage," X,Y,Reflectance", point3DSequence);It is too advanced syntax to be understood by OpenCV writing functions, namely, the tag name could not contain spaces or comma's.If you want to store each point as a structure,you may try the following:cvStartWriteStruct( myFileStorage, "point3DSequence", CV_NODE_SEQ ); for( i = 0; i < point3DSequence->total; i++ ){CvPoint3D32f* pt=(CvPoint3D32f*)cvGetSeqElem(point3DSequence,i); cvStartWriteStruct(myFileStorage, 0, CV_NODE_MAP+CV_NODE_FLOW); cvWriteReal( myFileStorage, "x", pt->x );cvWriteReal( myFileStorage, "y", pt->y );cvWriteReal( myFileStorage, "reflectance", pt->z ); cvEndWriteStruct( myFileStorage );}cvEndWriteStruct( myFileStorage );that will look nice, but a little bit bulky and then you willhave to read the elements manually from the filestorage.Or, if the all the data could be just written as a plain array:x0 y0 refl0 x1 y1 refl1 ...then just use:cvWrite( myFileStorage, "point3DSequence", point3DSequence );。