目录

一、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 编译及测试


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

1.1 imread函数

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

imread函数的声明如下:

//imgcodes.hppnamespace 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.hppnamespace cv{//! Imread flagsenum 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 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/shCX= g++ BIN := ./TARGET:= show_img5.exeFLAGS:= -std=c++11 -staticSRCDIR := ./#INCLUDESINCLUDEDIR := -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.hppnamespace cv{CV_EXPORTS_W bool imwrite( const String& filename, InputArray img,const std::vector& params = std::vector());};

函数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 args(paramId_1, paramValue_1, paramId_2, paramValue_2, …)

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

//imgcodes.hppnamespace cv{//! Imwrite flagsenum 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::ImwriteEXRTypeFlagsIMWRITE_EXR_COMPRESSION=(3<<4)+1,/*49*//覆盖EXR压缩类型(默认为ZIP_compression=3),见cv::ImwriteEXRCompressionFlagsIMWRITE_WEBP_QUALITY=64,//对于WEBP,它可以是从1到100的质量(越高越好)。默认情况下(没有任何参数),并且对于高于100的质量,使用无损压缩。IMWRITE_PAM_TUPLETYPE=128,//对于PAM,将TUPLETYPE字段设置为为该格式定义的相应字符串值,见cv::ImwritePAMFlagsIMWRITE_TIFF_RESUNIT=256,//对于TIFF,用于指定要设置的DPI分辨率单位;有关有效值,请参阅libtiff文档IMWRITE_TIFF_XDPI=257,//对于TIFF,使用指定X方向DPIIMWRITE_TIFF_YDPI=258,//对于TIFF,使用指定Y方向DPIIMWRITE_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数组容器来设置:

#include "opencv2/opencv.hpp" //Include file for every supported OpenCV function #include 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);//保存图片.jpgif(ret){cout <<"success save 2.jpg"<< endl;}ret = cv::imwrite("3.jpeg",img_rgb);//保存图片.jpegif(ret){cout <<"success save 3.jpeg"<< endl;}ret = cv::imwrite("4.jp2",img_rgb);//保存图片.jp2if(ret){cout <<"success save 4.jp2"<< endl;}ret = cv::imwrite("5.tif",img_rgb);//保存图片.tifif(ret){cout <<"success save 5.tif"<< endl;}ret = cv::imwrite("6.tiff",img_rgb);//保存图片.tiffif(ret){cout <<"success save 6.tiff"<< endl;}ret = cv::imwrite("7.png",img_rgb);//保存图片.pngif(ret){cout <<"success save 7.png"<< endl;}ret = cv::imwrite("8.bmp",img_rgb);//保存图片.bmpif(ret){cout <<"success save 8.bmp"<< endl;}ret = cv::imwrite("9.ppm",img_rgb);//保存图片.ppmif(ret){cout <<"success save 9.ppm"<< endl;}ret = cv::imwrite("10.pbm",img_gry);//保存图片.pbmif(ret){cout <<"success save 10.pbm"<< endl;}vector 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);//保存图片.pbmif(ret){cout <<"success save 10_1.pbm"<< endl;}ret = cv::imwrite("11.pgm",img_gry);//保存图片.pgmif(ret){cout <<"success save 11.pgm"<< endl;}ret = cv::imwrite("11_1.pgm",img_gry,w_args_02);//保存图片.pgmif(ret){cout <<"success save 11_1.pgm"<< endl;}// cv::waitKey(0);return(0);}

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

#/bin/shCX= g++ BIN := ./TARGET:= show_img6.exeFLAGS:= -std=c++11 -staticSRCDIR := ./#INCLUDESINCLUDEDIR := -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