目录
一、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.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