【OpenCV学习笔记 003】图像的载入、显示和输出
2016-04-11 17:33
639 查看
在OpenCV2.0的时代,对于图像数据的存储逐渐倾向于使用Mat.这比在OpenCV1.0中使用基于 C 语言接口而建的图像存储格式IplImage*更加的简单方便,主要是由于省去了release申请了的内存,不用考虑内存泄露及内存管理的问题,当然在OpenCV2.0中也提供对IplImage*支持以及与Mat之间的转换。下面我们着重介绍一下OpenCV2中图像的载入,显示和输出。
第一个参数,const string&类型的filename,填我们需要载入的图片路径名。
在Windows操作系统下,OpenCV的imread函数支持如下类型的图像载入:
OpenCV中imread函数支持如下类型的图像载入:
Windows位图 - *.bmp, *.dib
JPEG文件 - *.jpeg, *.jpg, *.jpe
JPEG 2000文件- *.jp2
PNG图片 - *.png
便携文件格式- *.pbm, *.pgm, *.ppm
Sun rasters光栅文件 - *.sr, *.ras
TIFF 文件 - *.tiff, *.tif
第二个参数,int类型的flags,为载入标识,它指定一个加载图像的颜色类型。可以看到它自带缺省值1.
可以在OpenCV中标识图像格式的枚举体中取值。通过转到定义,我们可以在higui_c.h中发现这个枚举的定义是这样的:
enum
{
// 8bit, color or not
IMREAD_UNCHANGED =-1,
// 8bit, gray
IMREAD_GRAYSCALE =0,
// ?, color
IMREAD_COLOR =1,
// any depth, ?
IMREAD_ANYDEPTH =2,
// ?, any color
IMREAD_ANYCOLOR =4
};
CV_LOAD_IMAGE_UNCHANGED,这个标识在新版本中被废置了,忽略。
CV_LOAD_IMAGE_ANYDEPTH- 如果取这个标识的话,若载入的图像的深度为16位或者32位,就返回对应深度的图像,
否则,就转换为8位图像再返回。
CV_LOAD_IMAGE_COLOR- 如果取这个标识的话,总是转换图像到彩色一体
CV_LOAD_IMAGE_GRAYSCALE- 如果取这个标识的话,始终将图像转换成灰度1
如果输入有冲突的标志,将采用较小的数字值。比如CV_LOAD_IMAGE_COLOR | CV_LOAD_IMAGE_ANYCOLOR 将载入3通道图。
如果想要载入最真实的图像,选择CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR。
因为flags是int型的变量,如果我们不在这个枚举体中取值的话,还可以这样来:
flags >0返回一个3通道的彩色图像。
flags =0返回灰度图像。
flags <0返回包含Alpha通道的加载的图像。
需要注意的点:输出的图像默认情况下是不载入Alpha通道进来的。如果我们需要载入Alpha通道的话呢,这里就需要取负值。
如果你捣乱,flags取250,也是可以的,这时就表示返回一个3通道的彩色图像。
2 namedWindow( )函数
第一个参数,const string&型的name,即填被用作窗口的标识符的窗口名称。
第二个参数,int 类型的flags ,窗口的标识,可以填如下的值:
WINDOW_NORMAL设置了这个值,用户便可以改变窗口的大小(没有限制)
WINDOW_AUTOSIZE如果设置了这个值,窗口大小会自动调整以适应所显示的图像,并且不能手动改变窗口大小。
WINDOW_OPENGL 如果设置了这个值的话,窗口创建的时候便会支持OpenGL。
函数剖析:
首先需要注意的是,它有默认值WINDOW_AUTOSIZE,所以,一般情况下,这个函数我们填一个变量就行了。namedWindow函数的作用是,通过指定的名字,创建一个可以作为图像和进度条的容器窗口。如果具有相同名称的窗口已经存在,则函数不做任何事情。我们可以调用destroyWindow()或者destroyAllWindows()函数来关闭窗口,并取消之前分配的与窗口相关的所有内存空间。其实对于代码量不大的简单小程序来说,我们完全没有必要手动调用上述的destroyWindow()或者destroyAllWindows()函数,因为在退出时,所有的资源和应用程序的窗口会被操作系统会自动关闭。
第二个参数,InputArray 类型的mat,填需要显示的图像。
imshow 函数详解:
imshow 函数用于在指定的窗口中显示图像。如果窗口是用CV_WINDOW_AUTOSIZE(默认值)标志创建的,那么显示图像原始大小。否则,将图像进行缩放以适合窗口。而imshow 函数缩放图像,取决于图像的深度: 如果载入的图像是8位无符号类型(8-bit unsigned),就显示图像本来的样子。如果图像是16位无符号类型(16-bit unsigned)或32位整型(32-bit integer),便用像素值除以256。也就是说,值的范围是[0,255 x 256]映射到[0,255]。如果图像是32位浮点型(32-bit
floating-point),像素值便要乘以255。也就是说,该值的范围是[0,1]映射到[0,255]。还有一点,若窗口创建(namedWindow函数)的时候,如果设定了支持OpenGL(WINDOW_OPENGL ),那么imshow还支持ogl::Buffer ,ogl::Texture2D以及gpu::GpuMat作为输入。
bool imwrite(const string& filename,InputArray img, const vector<int>& params=vector<int>() );
■第一个参数,const string&类型的filename,填需要写入的文件名就行了,带上后缀,比如,“123.jpg”这样。
■ 第二个参数,InputArray类型的img,一般填一个Mat类型的图像数据就行了。
■ 第三个参数,const vector<int>&类型的params,表示为特定格式保存的参数编码,它有默认值vector<int>(),所以一般情况下不需要填写。而如果要填写的话,有下面这些需要了解的地方:
对于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。
函数解析:
imwrite函数用于将图像保存到指定的文件。图像格式是基于文件扩展名的,可保存的扩展名和imread中可以读取的图像扩展名一样,为了方便查看,我们在这里再列一遍:
Windows位图 - *.bmp, *.dib
JPEG文件 - *.jpeg, *.jpg, *.jpe
JPEG 2000文件- *.jp2
PNG图片 - *.png
便携文件格式- *.pbm, *.pgm, *.ppm
Sun rasters光栅格式 - *.sr, *.ras
TIFF 文件 - *.tiff, *.tif
具体:创建一张透明Alpha值图
接着是载入一张dota2原画和dota2logo图,为图像融合做准备,然后是logo图,最终,经过处理,得到dota2原画+logo的融合,并输出一张名为我喜欢打dota2 by浅墨.jpg的图片到工程目录下,这里大家自己运行一下代码就可以得到效果了。
1 图像的载入、显示和输出
这里我们主要介绍三个函数,imread( ), namedWindow( )以及imshow( );1 imread()函数
Mat imread( const string& filename, int flags=1 );
第一个参数,const string&类型的filename,填我们需要载入的图片路径名。
在Windows操作系统下,OpenCV的imread函数支持如下类型的图像载入:
OpenCV中imread函数支持如下类型的图像载入:
Windows位图 - *.bmp, *.dib
JPEG文件 - *.jpeg, *.jpg, *.jpe
JPEG 2000文件- *.jp2
PNG图片 - *.png
便携文件格式- *.pbm, *.pgm, *.ppm
Sun rasters光栅文件 - *.sr, *.ras
TIFF 文件 - *.tiff, *.tif
第二个参数,int类型的flags,为载入标识,它指定一个加载图像的颜色类型。可以看到它自带缺省值1.
可以在OpenCV中标识图像格式的枚举体中取值。通过转到定义,我们可以在higui_c.h中发现这个枚举的定义是这样的:
enum
{
// 8bit, color or not
IMREAD_UNCHANGED =-1,
// 8bit, gray
IMREAD_GRAYSCALE =0,
// ?, color
IMREAD_COLOR =1,
// any depth, ?
IMREAD_ANYDEPTH =2,
// ?, any color
IMREAD_ANYCOLOR =4
};
CV_LOAD_IMAGE_UNCHANGED,这个标识在新版本中被废置了,忽略。
CV_LOAD_IMAGE_ANYDEPTH- 如果取这个标识的话,若载入的图像的深度为16位或者32位,就返回对应深度的图像,
否则,就转换为8位图像再返回。
CV_LOAD_IMAGE_COLOR- 如果取这个标识的话,总是转换图像到彩色一体
CV_LOAD_IMAGE_GRAYSCALE- 如果取这个标识的话,始终将图像转换成灰度1
如果输入有冲突的标志,将采用较小的数字值。比如CV_LOAD_IMAGE_COLOR | CV_LOAD_IMAGE_ANYCOLOR 将载入3通道图。
如果想要载入最真实的图像,选择CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR。
因为flags是int型的变量,如果我们不在这个枚举体中取值的话,还可以这样来:
flags >0返回一个3通道的彩色图像。
flags =0返回灰度图像。
flags <0返回包含Alpha通道的加载的图像。
需要注意的点:输出的图像默认情况下是不载入Alpha通道进来的。如果我们需要载入Alpha通道的话呢,这里就需要取负值。
如果你捣乱,flags取250,也是可以的,这时就表示返回一个3通道的彩色图像。
2 namedWindow( )函数
void namedWindow(const string& winname, int flags = WINDOW_AUTOSIZE);
第一个参数,const string&型的name,即填被用作窗口的标识符的窗口名称。
第二个参数,int 类型的flags ,窗口的标识,可以填如下的值:
WINDOW_NORMAL设置了这个值,用户便可以改变窗口的大小(没有限制)
WINDOW_AUTOSIZE如果设置了这个值,窗口大小会自动调整以适应所显示的图像,并且不能手动改变窗口大小。
WINDOW_OPENGL 如果设置了这个值的话,窗口创建的时候便会支持OpenGL。
函数剖析:
首先需要注意的是,它有默认值WINDOW_AUTOSIZE,所以,一般情况下,这个函数我们填一个变量就行了。namedWindow函数的作用是,通过指定的名字,创建一个可以作为图像和进度条的容器窗口。如果具有相同名称的窗口已经存在,则函数不做任何事情。我们可以调用destroyWindow()或者destroyAllWindows()函数来关闭窗口,并取消之前分配的与窗口相关的所有内存空间。其实对于代码量不大的简单小程序来说,我们完全没有必要手动调用上述的destroyWindow()或者destroyAllWindows()函数,因为在退出时,所有的资源和应用程序的窗口会被操作系统会自动关闭。
3 imshow( )函数
第一个参数,const string&类型的winname,填需要显示的窗口标识名称。第二个参数,InputArray 类型的mat,填需要显示的图像。
class CV_EXPORTS _InputArray { public: enum { KIND_SHIFT = 16, FIXED_TYPE = 0x8000 << KIND_SHIFT, FIXED_SIZE = 0x4000 << KIND_SHIFT, KIND_MASK = ~(FIXED_TYPE|FIXED_SIZE) - (1 << KIND_SHIFT) + 1, NONE = 0 << KIND_SHIFT, MAT = 1 << KIND_SHIFT, MATX = 2 << KIND_SHIFT, STD_VECTOR = 3 << KIND_SHIFT, STD_VECTOR_VECTOR = 4 << KIND_SHIFT, STD_VECTOR_MAT = 5 << KIND_SHIFT, EXPR = 6 << KIND_SHIFT, OPENGL_BUFFER = 7 << KIND_SHIFT, OPENGL_TEXTURE = 8 << KIND_SHIFT, GPU_MAT = 9 << KIND_SHIFT, OCL_MAT =10 << KIND_SHIFT }; _InputArray(); _InputArray(const Mat& m); _InputArray(const MatExpr& expr); template<typename _Tp> _InputArray(const _Tp* vec, int n); template<typename _Tp> _InputArray(const vector<_Tp>& vec); template<typename _Tp> _InputArray(const vector<vector<_Tp> >& vec); _InputArray(const vector<Mat>& vec); template<typename _Tp> _InputArray(const vector<Mat_<_Tp> >& vec); template<typename _Tp> _InputArray(const Mat_<_Tp>& m); template<typename _Tp, int m, int n> _InputArray(const Matx<_Tp, m, n>& matx); _InputArray(const Scalar& s); _InputArray(const double& val); // < Deprecated _InputArray(const GlBuffer& buf); _InputArray(const GlTexture& tex); // > _InputArray(const gpu::GpuMat& d_mat); _InputArray(const ogl::Buffer& buf); _InputArray(const ogl::Texture2D& tex); virtual Mat getMat(int i=-1) const; virtual void getMatVector(vector<Mat>& mv) const; // < Deprecated virtual GlBuffer getGlBuffer() const; virtual GlTexture getGlTexture() const; // > virtual gpu::GpuMat getGpuMat() const; /*virtual*/ ogl::Buffer getOGlBuffer() const; /*virtual*/ ogl::Texture2D getOGlTexture2D() const; virtual int kind() const; virtual Size size(int i = -1) const; virtual size_t total(int i = -1) const; virtual int type(int i = -1) const; virtual int depth(int i = -1) const; virtual int channels(int i = -1) const; virtual bool empty() const; #ifdef OPENCV_CAN_BREAK_BINARY_COMPATIBILITY virtual ~_InputArray(); #endif int flags; void* obj; Size sz; }; enum { DEPTH_MASK_8U = 1 << CV_8U, DEPTH_MASK_8S = 1 << CV_8S, DEPTH_MASK_16U = 1 << CV_16U, DEPTH_MASK_16S = 1 << CV_16S, DEPTH_MASK_32S = 1 << CV_32S, DEPTH_MASK_32F = 1 << CV_32F, DEPTH_MASK_64F = 1 << CV_64F, DEPTH_MASK_ALL = (DEPTH_MASK_64F << 1) - 1, DEPTH_MASK_ALL_BUT_8S = DEPTH_MASK_ALL & ~DEPTH_MASK_8S, DEPTH_MASK_FLT = DEPTH_MASK_32F + DEPTH_MASK_64F };可以看到,_InputArray类的里面首先定义了一个枚举,然后是各类的模板类型和一些方法。更复杂的我们暂且不挖深讲了,很多时候,遇到函数原型中的InputArray类型,我们把它简单地当做Mat类型就行了。
imshow 函数详解:
imshow 函数用于在指定的窗口中显示图像。如果窗口是用CV_WINDOW_AUTOSIZE(默认值)标志创建的,那么显示图像原始大小。否则,将图像进行缩放以适合窗口。而imshow 函数缩放图像,取决于图像的深度: 如果载入的图像是8位无符号类型(8-bit unsigned),就显示图像本来的样子。如果图像是16位无符号类型(16-bit unsigned)或32位整型(32-bit integer),便用像素值除以256。也就是说,值的范围是[0,255 x 256]映射到[0,255]。如果图像是32位浮点型(32-bit
floating-point),像素值便要乘以255。也就是说,该值的范围是[0,1]映射到[0,255]。还有一点,若窗口创建(namedWindow函数)的时候,如果设定了支持OpenGL(WINDOW_OPENGL ),那么imshow还支持ogl::Buffer ,ogl::Texture2D以及gpu::GpuMat作为输入。
4 imwrite函数
在OpenCV中,输出图像到文件,我们一般都用imwrite函数,它的声明如下:bool imwrite(const string& filename,InputArray img, const vector<int>& params=vector<int>() );
■第一个参数,const string&类型的filename,填需要写入的文件名就行了,带上后缀,比如,“123.jpg”这样。
■ 第二个参数,InputArray类型的img,一般填一个Mat类型的图像数据就行了。
■ 第三个参数,const vector<int>&类型的params,表示为特定格式保存的参数编码,它有默认值vector<int>(),所以一般情况下不需要填写。而如果要填写的话,有下面这些需要了解的地方:
对于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。
函数解析:
imwrite函数用于将图像保存到指定的文件。图像格式是基于文件扩展名的,可保存的扩展名和imread中可以读取的图像扩展名一样,为了方便查看,我们在这里再列一遍:
Windows位图 - *.bmp, *.dib
JPEG文件 - *.jpeg, *.jpg, *.jpe
JPEG 2000文件- *.jp2
PNG图片 - *.png
便携文件格式- *.pbm, *.pgm, *.ppm
Sun rasters光栅格式 - *.sr, *.ras
TIFF 文件 - *.tiff, *.tif
具体:创建一张透明Alpha值图
#include <vector> #include <stdio.h> #include<opencv2/opencv.hpp> using namespace cv; using namespace std; void createAlphaMat(Mat &mat) { for (int i = 0; i < mat.rows; ++i) { for (int j = 0; j < mat.cols; ++j) { Vec4b&rgba = mat.at<Vec4b>(i, j); rgba[0] = UCHAR_MAX; rgba[1] = saturate_cast<uchar>((float(mat.cols - j)) / ((float)mat.cols) *UCHAR_MAX); rgba[2] = saturate_cast<uchar>((float(mat.rows - i)) / ((float)mat.rows) *UCHAR_MAX); rgba[3] = saturate_cast<uchar>(0.5 * (rgba[1] + rgba[2])); } } } int main() { //创建带alpha通道的Mat Mat mat(480, 640, CV_8UC4); createAlphaMat(mat); vector<int>compression_params; compression_params.push_back(CV_IMWRITE_PNG_COMPRESSION); compression_params.push_back(9); try{ imwrite("透明Alpha值图.png", mat, compression_params); } catch (runtime_error& ex) { fprintf(stderr, "图像转换成PNG格式发生错误:%s\n", ex.what()); return 1; } fprintf(stdout, "PNG图片文件的alpha数据保存完毕~\n"); return 0; }
2 综合案例
最后是一个综合示例,载入图像,进行简单图像混合,显示图像,并且输出混合后的图像到jpg。因为opencv图像处理真的很少涉及到设计模式的问题,所以很多时候往往就是main函数中塞满一串串代码打天下,即便是OpenCV官方的示例都是如此。好了,如下就是这篇文章配套综合示例的配套源码,非常的简单明了:#include<opencv2/core/core.hpp> #include<opencv2/highgui/highgui.hpp> using namespace cv; int main() { //-----------------------------------【一、图像的载入和显示】-------------------------------------- // 描述:以下三行代码用于完成图像的载入和显示 //-------------------------------------------------------------------------------------------------- Mat girl = imread("girl.jpg"); //载入图像到Mat namedWindow("【1】动漫图"); //创建一个名为 "【1】动漫图"的窗口 imshow("【1】动漫图", girl);//显示名为 "【1】动漫图"的窗口 //-----------------------------------【二、初级图像混合】-------------------------------------- // 描述:二、初级图像混合 //----------------------------------------------------------------------------------------------- //载入图片 Mat image = imread("dota.jpg", 199); Mat logo = imread("dota_logo.jpg"); //载入后先显示 namedWindow("【2】原画图"); imshow("【2】原画图", image); namedWindow("【3】logo图"); imshow("【3】logo图", logo); //定义一个Mat类型,用于存放,图像的ROI Mat imageROI; //方法一 imageROI = image(Rect(800, 350, logo.cols, logo.rows)); //方法二 //imageROI=image(Range(350,350+logo.rows),Range(800,800+logo.cols)); //将logo加到原图上 addWeighted(imageROI, 0.5, logo, 0.3, 0., imageROI); //显示结果 namedWindow("【4】原画+logo图"); imshow("【4】原画+logo图", image); //-----------------------------------【三、图像的输出】-------------------------------------- // 描述:将一个Mat图像输出到图像文件 //----------------------------------------------------------------------------------------------- //输出一张jpg图片到工程目录下 imwrite("我喜欢打dota2 by浅墨.jpg", image); waitKey(); return 0; }运行这个程序,会弹出四个我们在OpenCV中创建的窗口。首先是图像载入和显示的演示,我们载入了一张动漫人物图:
接着是载入一张dota2原画和dota2logo图,为图像融合做准备,然后是logo图,最终,经过处理,得到dota2原画+logo的融合,并输出一张名为我喜欢打dota2 by浅墨.jpg的图片到工程目录下,这里大家自己运行一下代码就可以得到效果了。
相关文章推荐
- Linux shell 实现多线程
- call to OpenGL ES API with no current context (logged once per thread)
- Pexpect:系统批量运维管理器!!!
- Pexpect:系统批量运维管理器!!!
- 《The C Programming Language--2》Types, Operators, and Expressions
- 【制作最小Linux系统】
- Linux上文件的特殊权限SUID,SGID,SBIT详解
- Linux下vi编辑器的使用
- Sqoop中文手册
- Linux内核分析作业第八周
- Hadoop安装测试简单记录
- 去掉tomcat中appBase默认的ROOT
- centos JDK安装
- 在Debian上配置Apache+MySQL+PHP4
- OpenCV3.1与VS2013配置教程记录(64位win7旗舰版)
- tomcat配置文件server.xml参数说明
- Linux下处理BOM头和^M的简单方法
- Linux下处理BOM头和^M的简单方法
- linux sh 与 ./ 区别
- Centos7 Ansible 配置SSH公钥认证