C/C++开发,opencv读写图像函数详解

目录

一、cv::imread函数读取图像

        1.1 imread函数

        1.2 imread函数的参数解析

        1.3  imread函数实践案例

        1.4 编译及测试

 二、cv::imwrite函数存储图像

        2.1 cv::imwrite函数

        2.2 imwrite函数参数解析

        2.3 imwrite函数实践案例

        2.4 编译及测试

扫描二维码关注公众号,回复: 15633406 查看本文章

一、cv::imread函数读取图像

        1.1 imread函数

        函数imread从指定的文件中加载图像并返回。如果无法读取图像(因为缺少文件、权限不正确、格式不受支持或无效),该函数将返回一个空矩阵(Mat::data==NULL)。

        imread函数的声明如下:

//imgcodes.hpp

namespace cv
{
CV_EXPORTS_W Mat imread( const String& filename, int flags = IMREAD_COLOR );
};

        1.2 imread函数的参数解析

        cv::imread函数第一个参数(filename)是图片名,该图片名可以是完整路径,也可以是相对路径(以当前路径为基准)。使用cv::imread()从磁盘中读取一张图片时,cv::imread()并不关心文件的拓展名是什么(注:读者可以将图片名后缀去掉,然后再读取,观察imread函数加载图片情况,也可以进一步指定组合flag来进一步验证),而是分析文件中前几个字节(被称为文件的识别标识或者“魔法序列”)来确定图像的编码格式。

        目前,imread函数支持以下文件格式:

-Windows位图-\*.bmp,\*.dib
-JPEG文件-\*.JPEG、\*.jpg、\*.jpe
-JPEG 2000文件-\*.jp2
-可移植网络图形-\*.png
-WebP-\*.WebP
-可移植图像格式-\*.pbm、\*.pgm、\*.ppm\*.pxm、\*.pnm
-PFM文件-\*.PFM
-sr文件-\*.sr,\*.ras
-TIFF文件-\*.TIFF、\*.tif
-OpenEXR图像文件-\*.exr
-Radiance HDR-\*.HDR,\*.pic
-GDAL支持的光栅和矢量地理空间数据

        第二个参数flags可以被设置为下面的任意一个值。默认情况下,flags被设置为Cv::IMREAD_COLOR。

Cv::IMREAD_COLOR		总是读取三通道图像
Cv::IMREAD_GRAYSCALE	总是读取单通道图像 
CV::IMREAD_ANYCOLOR		通道数由文件实际通道数(不超过3)
Cv::IMREAD_ANYDEPTH		允许加载超过8bit深度。
Cv::IMREAD_UNCHANGED	等于将Cv::IMREAD_ANYCOLOR和CV::IMREAD_ANYDEPTH组合了起来。

        这个值表示图片将被以三通道8位的格式读取。在这种情况下,即便原始文件中的图像是灰度图像,读取到内存中的仍然有三通道,每个通道拥有相同数据的图像。如果flags被设置为Cv::IMREAD_GRAYSCALE,那么不管文件内部图像是几通道,图片都以灰度图像的格式加载。flags的另外一个值是Cv::IMREAD_ANYCOLOR。在此种情况下,图片的载入方式取决于其内部图像的具体情况,如果是彩色图像,就以三通道注2的形式载入,如果是灰度图像,则按照单通道的形式载入。

        这些flags的定义来自于ImreadModes枚举类型:

//imgcodes.hpp

namespace cv{
//! Imread flags
enum ImreadModes {
IMREAD_UNCHANGED=-1,//按原样返回加载的图像(使用alpha通道,否则会被裁剪)。忽略EXIF方向。

IMREAD_GRAYSCALE=0,//始终将图像转换为单通道灰度图像(编解码器内部转换)。

IMREAD_COLOR=1,//!始终将图像转换为3通道BGR彩色图像。

IMREAD_ANYDEPTH=2,//在输入具有相应深度时返回16位/32位图像,否则将其转换为8位。

IMREAD_ANYCOLOR=4,//以任何可能的颜色格式读取图像。

IMREAD_LOAD_GDAL=8,//使用gdal驱动程序加载图像。

IMREAD_REDUCED_GRAYSCALE_2=16,//始终将图像转换为单通道灰度图像,并将图像大小缩小1/2。

IMREAD_REDUCED_COLOR_2=17,//始终将图像转换为3通道BGR彩色图像,并将图像大小缩小1/2。

IMREAD_REDUCED_GRAYSCALE_4=32,//始终将图像转换为单通道灰度图像,并将图像大小缩小1/4。

IMREAD_REDUCED_COLOR_4=33,//始终将图像转换为3通道BGR彩色图像,并将图像大小缩小1/4。

IMREAD_REDUCED_GRAYSCALE_8=64,//始终将图像转换为单通道灰度图像,并将图像大小缩小1/8。

IMREAD_REDUCED_COLOR_8=65,//始终将图像转换为3通道BGR彩色图像,并将图像大小缩小1/8。

IMREAD_IGNORE_ORIENTATION=128//不要根据EXIF的方向标志旋转图像。 
     };
};

        可以看到ImreadModes是按位定义的一个数值,意味着该参数可以通过"|"组合的方式构建实参。

        1.3  imread函数实践案例

        imread函数的调用很简单,主要就传入文件名及读取flags参数,返回一个mat对象,如果成功该对象非空就表示读取成功。

cv::Mat img = cv::imread(文件名.支持图像后缀,flag1|flag2|...)

        本文编写一个读取.png图片的案例,通过不同的ImreadModes值读取一个png格式图片,创建一个文件目录show_img5,创建文件main.cpp和Makefile文件,其中main.cpp如下,通过不同的flag读取一个图片,并调用HighGUI模块的cv::imshow函数显示图片:

#include "opencv2/opencv.hpp" //Include file for every supported OpenCV function 
#include <iostream>

int main( int argc,char** argv )
{
	cv::Mat img_rgb,img_gry,img_any,img_dep,img_unc;
	cv::namedWindow("Example RGB", cv::WINDOW_AUTOSIZE );
	cv::namedWindow("Example GRY", cv::WINDOW_AUTOSIZE );
	cv::namedWindow("Example ANY", cv::WINDOW_AUTOSIZE );
	cv::namedWindow("Example DEP", cv::WINDOW_AUTOSIZE );
	cv::namedWindow("Example UNC", cv::WINDOW_AUTOSIZE );

	//
	img_rgb=cv::imread( argv[1],cv::IMREAD_COLOR);
	if( !img_rgb.empty() ) 	cv::imshow("Example RGB",img_rgb );
	//
	img_gry=cv::imread( argv[1],cv::IMREAD_GRAYSCALE);
	if( !img_gry.empty() ) 	cv::imshow("Example GRY",img_gry );
	//
	img_any=cv::imread( argv[1],cv::IMREAD_ANYCOLOR);
	if( !img_any.empty() ) 	cv::imshow("Example ANY",img_any );
	//
	img_dep=cv::imread( argv[1],cv::IMREAD_ANYDEPTH);
	if( !img_dep.empty() ) 	cv::imshow("Example DEP",img_dep );
	//
	img_unc=cv::imread( argv[1],cv::IMREAD_UNCHANGED);
	if( !img_unc.empty() ) 	cv::imshow("Example UNC",img_unc );

	cv::waitKey(0);
	return(0);
}

        工程组织Makefile文件如下(本文是采用win下MinGW方式编译的,如何搭建opencv库+MinGW编译的请参考本专栏的opencv库安装编译博文)。

#/bin/sh
CX= g++ 

BIN 		:= ./
TARGET      := show_img5.exe
FLAGS		:= -std=c++11 -static
SRCDIR 		:= ./
#INCLUDES
INCLUDEDIR 	:= -I"../../opencv_MinGW/include" 
#-I"$(SRCDIR)"
staticDir   := ../../opencv_MinGW/x64/mingw/staticlib/
#LIBDIR		:= $(staticDir)/libopencv_world460.a\
#			   $(staticDir)/libade.a \
#			   $(staticDir)/libIlmImf.a \
#			   $(staticDir)/libquirc.a \
#			   $(staticDir)/libzlib.a \
#			   $(wildcard $(staticDir)/liblib*.a) \
#			   -lgdi32 -lComDlg32 -lOleAut32 -lOle32 -luuid 
#opencv_world放弃前,然后是opencv依赖的第三方库,后面的库是MinGW编译工具的库

LIBDIR 	    := -L $(staticDir) -lopencv_world460 -lade -lIlmImf -lquirc -lzlib \
				-llibjpeg-turbo -llibopenjp2 -llibpng -llibprotobuf -llibtiff -llibwebp \
				-lgdi32 -lComDlg32 -lOleAut32 -lOle32 -luuid 
source		:= $(wildcard $(SRCDIR)/*.cpp) 

$(TARGET) :
	$(CX) $(FLAGS) $(INCLUDEDIR) $(source)  -o $(BIN)/$(TARGET) $(LIBDIR)

clean:
	rm  $(BIN)/$(TARGET)

        1.4 编译及测试

        进入show_img5目录,make -j*编译案例,如下:

        进入该目录命令行运行编译输出程序

show_img5.exe 1.PNG

 二、cv::imwrite函数存储图像

        2.1 cv::imwrite函数

        cv::imwrite函数与cv::imread函数相对,形成互补关系。

//imgcodes.hpp

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

        函数imwrite将图像保存到指定的文件中。图像格式是根据文件扩展名选择的。通常,使用此功能只能保存8位单通道或3通道(具有“BGR”通道顺序)图像,但以下情况除外:

-在PNG、JPEG 2000和TIFF格式的情况下,可以保存16位无符号(CV_16U)图像

-32位浮点(CV_32F)图像可以保存为PFM、TIFF、OpenEXR和Radiance HDR格式;将使用LogLuv高动态范围编码保存3通道(CV_32FC3)TIFF图像(每个像素4个字节)

-使用此功能可以保存带有alpha通道的PNG图像。要执行此操作,请创建8位(或16位)4通道图像BGRA,其中alpha通道最后到达。完全透明的像素应将alpha设置为0,完全不透明的像素应将alpha设置为255/65535。

-多个图像(Mat的矢量)可以保存为TIFF格式。

        2.2 imwrite函数参数解析

        第一个参数给定了文件名,文件名的拓展名部分用来决定以何种格式保存图像,以下是一些OpenCV支持的常用拓展名:

[1] jpg或者jpeg:以baseline JPEG格式保存;8位数据;单通道或三通道输入;
[2] jp2:JPEG2000;8位或者16位数据;单通道或三通道输入;
[3] tif或者.tiff:TIFF;8位或者16位数据;单通道、三通道或四通道输入
[4] png:PNG;8位或者16位数据;单通道、三通道或四通道输入
[5] bmp:BMP;8位数据;单通道、三通道或四通道输入
[6] ppm,.pgm:NetPBM;8位数据;单通道(PGM)或者三通道(PPM)

        如果不支持图像格式,则图像将转换为8位无符号(CV_8U)并以这种方式保存。如果格式、深度或通道顺序不同,使用Mat::convertTo和cv::cvtColor在保存前进行转换。或者,使用通用FileStorage I/O函数将图像保存为XML或YAML格式。

        第二个参数是待存储的输入图像。

        第三个参数被用作特殊类型文件的写入操作时所需的数据。输入参数为内部为整型数据的一个STL vector,vector中的整型序列的具体内容为:一系列的参数ID,以及与该参数对应的参数值,每个参数ID之后跟着其对应的值,默认为空数组。

params格式化编码为对的特定参数:
vector<int> args(paramId_1, paramValue_1, paramId_2, paramValue_2, …)

        这些写入标记flag是一个枚举值类型:

//imgcodes.hpp

namespace cv
{
//! Imwrite flags
enum ImwriteFlags {
IMWRITE_JPEG_QUALITY=1,//JPEG,它可以是从0到100的质量(越高越好)。默认值为95。

IMWRITE_JPEG_PROGRESSIVE=2,//启用JPEG功能,0或1,默认值为False。

IMWRITE_JPEG_OPTIMIZE=3,//启用JPEG功能,0或1,默认值为False。

IMWRITE_JPEG_RST_INTERVAL=4,//JPEG重新启动间隔,0-65535,默认为0-不重新启动。

IMWRITE_JPEG_LUMA_QUALITY=5,//单独的亮度质量级别,0-100,默认为-1-不使用。

IMWRITE_JPEG_CHROMA_QUALITY=6,//单独的色度质量级别,0-100,默认为-1-不使用。

IMWRITE_JPEG_SAMPLING_FACTOR=7,//对于JPEG,请设置采样因子。见cv::ImwriteJPEGSamplingFactorParams。

IMWRITE_PNG_COMPRESSION=16,//对于PNG,它可以是从0到9的压缩级别。值越高,表示尺寸越小,压缩时间越长。如果指定了策略,则策略将更改为IMWRITE_PNG_TSTRATIY_DEFAULT(Z_DEFAULT_strategy)。默认值为1(最佳速度设置)。

IMWRITE_PNG_STRATEGY=17,//其中一个cv::ImwritePNGFlags,默认为IMWRITE_PNG_STRATEGY_RLE。

IMWRITE_PNG_BILEVEL=18,//二进制级别PNG,0或1,默认值为0。

IMWRITE_PXM_BINARY=32,//对于PPM、PGM或PBM,它可以是二进制格式标志,0或1。默认值为1。

IMWRITE_EXR_TYPE=(3<<4)+0,/*48*//超控EXR存储类型(默认为浮动(FP32)),见cv::ImwriteEXRTypeFlags

IMWRITE_EXR_COMPRESSION=(3<<4)+1,/*49*//覆盖EXR压缩类型(默认为ZIP_compression=3),见cv::ImwriteEXRCompressionFlags

IMWRITE_WEBP_QUALITY=64,//对于WEBP,它可以是从1到100的质量(越高越好)。默认情况下(没有任何参数),并且对于高于100的质量,使用无损压缩。

IMWRITE_PAM_TUPLETYPE=128,//对于PAM,将TUPLETYPE字段设置为为该格式定义的相应字符串值,见cv::ImwritePAMFlags

IMWRITE_TIFF_RESUNIT=256,//对于TIFF,用于指定要设置的DPI分辨率单位;有关有效值,请参阅libtiff文档

IMWRITE_TIFF_XDPI=257,//对于TIFF,使用指定X方向DPI

IMWRITE_TIFF_YDPI=258,//对于TIFF,使用指定Y方向DPI

IMWRITE_TIFF_COMPRESSION=259,//对于TIFF,使用指定图像压缩方案。有关压缩格式对应的整数常量,请参见libtiff。注意,对于深度为CV_32F的图像,仅使用libtiff的SGILOG压缩方案。对于其他支持的深度,可以通过该标志指定压缩方案;LZW压缩是默认设置。

IMWRITE_JPEG2000_compressionx1000=272//对于JPEG2000,使用指定目标压缩率(乘以1000)。该值可以在0到1000之间。默认值为1000。
     };
};

        cv::imwrite()是为图像文件定制的,它非常依赖那些用于处理图像文件的库。这些库通常被叫做codecs。很多的操作系统应该已经拥有很多编码解码库,即使没有全部编解码库,但至少对于常见的格式,每一种类型的图片都应该有一个可以使用的编解码库。
        OpenCV对一些图片格式(例如JPEG、PNG、TIFF等)自带用于编码解码库。对于这些编解码库,可以有以下三种选择:a)不使用这些编解码库;b)使用OpenCV所提供的编解码库(记得与其他OpenCV模块一起编译);c)使用相应的拓展库(例如libjpeg、libpng等)。在Windows系统中,默认是b选项。在OS X/Linux系统上,默认选项是c;如果Cmake无法发现编解码库,就使用选项b。可以显式指定所需要的选项。

        2.3 imwrite函数实践案例

        本文编写一个读取某.png图片,然后按各自图片格式另存该图像数据,创建一个文件目录show_img6,创建文件main.cpp和Makefile文件,其中main.cpp如下,通过不同的图片名后缀来明确存储图片的文件格式,另外可以另行制定写入图片的flag,采用vector<int>数组容器来设置:

#include "opencv2/opencv.hpp" //Include file for every supported OpenCV function 
#include <iostream>

using namespace std;

int main( int argc,char** argv )
{
	//图片数据载入
	cv::Mat img_rgb,img_gry;
	img_rgb=cv::imread( argv[1]);
	cv::cvtColor( img_rgb,img_gry,cv::COLOR_BGR2GRAY);//转灰度图
	//
	bool ret = false;
	ret = cv::imwrite("2.jpg",img_rgb);//保存图片.jpg
	if(ret)
	{
		cout <<"success save 2.jpg"<< endl;
	}
	ret = cv::imwrite("3.jpeg",img_rgb);//保存图片.jpeg
	if(ret)
	{
		cout <<"success save 3.jpeg"<< endl;
	}
	ret = cv::imwrite("4.jp2",img_rgb);//保存图片.jp2
	if(ret)
	{
		cout <<"success save 4.jp2"<< endl;
	}
	ret = cv::imwrite("5.tif",img_rgb);//保存图片.tif
	if(ret)
	{
		cout <<"success save 5.tif"<< endl;
	}
	ret = cv::imwrite("6.tiff",img_rgb);//保存图片.tiff
	if(ret)
	{
		cout <<"success save 6.tiff"<< endl;
	}
	ret = cv::imwrite("7.png",img_rgb);//保存图片.png
	if(ret)
	{
		cout <<"success save 7.png"<< endl;
	}
	ret = cv::imwrite("8.bmp",img_rgb);//保存图片.bmp
	if(ret)
	{
		cout <<"success save 8.bmp"<< endl;
	}
	ret = cv::imwrite("9.ppm",img_rgb);//保存图片.ppm
	if(ret)
	{
		cout <<"success save 9.ppm"<< endl;
	}

	ret = cv::imwrite("10.pbm",img_gry);//保存图片.pbm
	if(ret)
	{
		cout <<"success save 10.pbm"<< endl;
	}
	vector<int> w_args_02; 
	w_args_02.push_back(cv::IMWRITE_PXM_BINARY);
	w_args_02.push_back(0);
	ret = cv::imwrite("10_1.pbm",img_gry,w_args_02);//保存图片.pbm
	if(ret)
	{
		cout <<"success save 10_1.pbm"<< endl;
	}
	ret = cv::imwrite("11.pgm",img_gry);//保存图片.pgm
	if(ret)
	{
		cout <<"success save 11.pgm"<< endl;
	}
	ret = cv::imwrite("11_1.pgm",img_gry,w_args_02);//保存图片.pgm
	if(ret)
	{
		cout <<"success save 11_1.pgm"<< endl;
	}
	// cv::waitKey(0);
	return(0);
}

        工程组织Makefile文件和前面读取图片的案例几乎一致,仅仅改动了输出功能名,如下(本文是采用win下MinGW方式编译的,如何搭建opencv库+MinGW编译的请参考本专栏的opencv库安装编译博文)。

#/bin/sh
CX= g++ 

BIN 		:= ./
TARGET      := show_img6.exe
FLAGS		:= -std=c++11 -static
SRCDIR 		:= ./
#INCLUDES
INCLUDEDIR 	:= -I"../../opencv_MinGW/include" 
#-I"$(SRCDIR)"
staticDir   := ../../opencv_MinGW/x64/mingw/staticlib/
#LIBDIR		:= $(staticDir)/libopencv_world460.a\
#			   $(staticDir)/libade.a \
#			   $(staticDir)/libIlmImf.a \
#			   $(staticDir)/libquirc.a \
#			   $(staticDir)/libzlib.a \
#			   $(wildcard $(staticDir)/liblib*.a) \
#			   -lgdi32 -lComDlg32 -lOleAut32 -lOle32 -luuid 
#opencv_world放弃前,然后是opencv依赖的第三方库,后面的库是MinGW编译工具的库

LIBDIR 	    := -L $(staticDir) -lopencv_world460 -lade -lIlmImf -lquirc -lzlib \
				-llibjpeg-turbo -llibopenjp2 -llibpng -llibprotobuf -llibtiff -llibwebp \
				-lgdi32 -lComDlg32 -lOleAut32 -lOle32 -luuid 
source		:= $(wildcard $(SRCDIR)/*.cpp) 

$(TARGET) :
	$(CX) $(FLAGS) $(INCLUDEDIR) $(source)  -o $(BIN)/$(TARGET) $(LIBDIR)

clean:
	rm  $(BIN)/$(TARGET)

        2.4 编译及测试

        进入show_img6目录,make -j*编译案例,如下:

         进入该目录命令行运行编译输出程序:

show_img6.exe 1.PNG

猜你喜欢

转载自blog.csdn.net/py8105/article/details/131031375