【OpenCV学习笔记 003】图像的载入、显示和输出

47 篇文章 37 订阅 ¥9.90 ¥99.00
25 篇文章 9 订阅 ¥9.90 ¥99.00
本文介绍了OpenCV中图像的载入、显示和输出,重点讲解了imread()、namedWindow()、imshow()和imwrite()函数的使用方法。通过示例代码展示了如何加载图像、创建窗口显示图像以及保存图像到文件。
摘要由CSDN通过智能技术生成

    在OpenCV2.0的时代,对于图像数据的存储逐渐倾向于使用Mat.这比在OpenCV1.0中使用基于 语言接口而建的图像存储格式IplImage*更加的简单方便,主要是由于省去了release申请了的内存,不用考虑内存泄露及内存管理的问题,当然在OpenCV2.0中也提供对IplImage*支持以及与Mat之间的转换。下面我们着重介绍一下OpenCV2中图像的载入,显示和输出。

一、图像的载入、显示和输出

这里我们主要介绍三个函数,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;
}

二、综合案例

最后是一个综合示例,载入图像,进行简单图像混合,显示图像,并且输出混合后的图像到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的图片到工程目录下,这里大家自己运行一下代码就可以得到效果了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值