10.图像的读取与显示
1、图像读取函数imread()
代码清单2-24 imread()函数的原型 cv::Mat cv::imread(const String & filename, int flags=IMREAD_COLOR )
-
filename:需要读取图像的文件名称,包含图像地址、名称和图像文件扩展名
-
flags:读取图像形式的标志,如将彩色图像按照灰度图读取,默认参数是按照彩色图像格式读取,可选参数在表2-3给出。
函数用于读取指定的图像并将其返回给一个Mat类变量,如果图像文件不存在、破损或者格式不受支持时,则无法读取图像,此时函数返回一个空矩阵,因此可以通过判断返回矩阵的data属性是否为空或者empty()函数是否为真来判断是否成功读取图像,如果读取图像失败,data属性返回值为0,empty()函数返回值为1。函数能够读取多种格式的图像文件,但是在不同操作系统由于使用的编解码器不同,因此在某个系统中能够读取的图像文件可能在其他系统中就无法读取。无论在哪个系统中,bmp文件和dib文件都是始终可以读取的,在Windows和Mac系统中,默认情况下使用OpenCV自带的编解码器(libjpeg,libpng,libtiff和libjasper),因此可以读取JPEG(jpg、jpeg、jpe),PNG,TIFF(tiff、tif)文件,在Linux系统中需要自行安装这些编解码器,安装后同样可以读取这些类型的文件。不过需要说明的是,该函数能否读取文件数据与扩展名无关,而是通过文件的内容确定图像的类型,例如将一个扩展名由png修改成exe时,该函数一样可以读取该图像,但是将扩展名exe改成png,该函数不能加载该文件。
该函数第一个参数以字符串形式给出待读取图像的地址,第二个函数是设置读取图像的形式,默认的参数是以彩色图的形式读取,针对不同需求可以更改参数,在OpenCV 4.1中给出了13种模式读取图像的形式,总结起来分别是以原样式读取、灰度图读取、彩色图读取、多位数读取、在读取时将图像缩小一定尺寸等形式读取,具体可选择的参数及作用在表2-3种给出,这里需要指出的是,将彩色图像转成灰度图通过编解码器内部转换,可能会与OpenCV程序中将彩色图像转成灰度图的结果存在差异。这些标志参数在功能不冲突的前提下可以同时声明多个,不同参数之间用“|”隔开。
表2-3 imread()函数读取图像形式参数
标志参数 |
简记 |
作用 |
IMREAD_UNCHANGED |
-1 |
按照图像原样读取,保留Alpha通道(第4通道) |
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,可以更改最后一位数字实现缩小1/4(最后一位改为4)和1/8(最后一位改为8) |
IMREAD_REDUCED_COLOR_2 |
17 |
将图像转成3通道彩色图像,尺寸缩小1/2,可以更改最后一位数字实现缩小1/4(最后一位改为4)和1/8(最后一位改为8) |
IMREAD_IGNORE_ORIENTATION |
128 |
不以EXIF的方向旋转图像 |
2、图像窗口函数namedWindow()
在我们之前的程序中并没有见到窗口函数,因为我们在显示图像时如果没有主动定义图像窗口,程序会自动生成一个窗口用于显示图像,然而有时我们需要在显示图像之前对图像窗口进行操作,例如添加滑动条,此时就需要提前创建图像窗口。代码清单2-25中给出了创建窗口函数的原型。
代码清单2-25 namedWindow()函数的原型 void cv::namedWindow(const String & winname,int flags = WINDOW_AUTOSIZE)
-
winname:窗口名称,用作窗口的标识符
-
flags:窗口属性设置标志
该函数会创建一个窗口变量,用于显示图像和滑动条,通过窗口的名称引用该窗口,如果在创建窗口时已经存在具有相同名称的窗口,则该函数不会执行任何操作。创建一个窗口需要占用部分内存资源,因此通过该函数创建窗口后,在不需要窗口时需要关闭窗口来释放内存资源。OpenCV提供了两个关闭窗口资源的函数,分别是cv::destroyWindow()函数和cv :: destroyAllWindows(),通过名称我们可以知道前一个函数是用于关闭一个指定名称的窗口,即在括号内输入窗口名称的字符串即可将对应窗口关闭,后一个函数是关闭程序中所有的窗口,一般用于程序的最后。不过事实上,在一个简单的程序里,我们并不需要调用这些函数,因为程序退出时会自动关闭应用程序的所有资源和窗口。虽然不主动释放窗口也会在程序结束时释放窗口资源,但是OpenCV 4.0版本在结束时会报出没有释放窗口的错误,而OpenCV 4.1版本则不会报错。
该函数的第一个参数是声明窗口的名称,用于窗口的唯一识别,第二个参数是声明窗口的属性,主要用于设置窗口的大小是否可调、显示的图像是否填充满窗口等,具体可选择的参数及含义在表2-4中给出,默认情况下,函数加载的标志参数为“WINDOW_AUTOSIZE | WINDOW_KEEPRATIO | WINDOW_GUI_EXPANDED”。
表2-4 namedWindow()函数窗口属性标志参数
标志参数 |
简记 |
作用 |
WINDOW_NORMAL |
0x00000000 |
显示图像后,允许用户随意调整窗口大小 |
WINDOW_AUTOSIZE |
0x00000001 |
根据图像大小显示窗口,不允许用户调整大小 |
WINDOW_OPENGL |
0x00001000 |
创建窗口的时候会支持OpenGL |
WINDOW_FULLSCREEN |
1 |
全屏显示窗口 |
WINDOW_FREERATIO |
0x00000100 |
调整图像尺寸以充满窗口 |
WINDOW_KEEPRATIO |
0x00000000 |
保持图像的比例 |
WINDOW_GUI_EXPANDED |
0x00000000 |
创建的窗口允许添加工具栏和状态栏 |
WINDOW_GUI_NORMAL |
0x00000010 |
创建没有状态栏和工具栏的窗口 |
3、图像显示函数imshow()
代码清单2-26 imshow()函数的原型 void cv::imshow(const String & winname, InputArray mat )
-
winname:要显示图像的窗口的名字,用字符串形式赋值
-
mat:要显示的图像矩阵
该函数会在指定的窗口中显示图像,如果在此函数之前没有创建同名的图像窗口,就会以WINDOW_AUTOSIZE标志创建一个窗口,显示图像的原始大小,如果创建了图像窗口,则会缩放图像以适应窗口属性。该函数会根据图像的深度将其缩放,具体缩放规则为:
-
如果图像是8位无符号类型,则按照原样显示
-
如果图像是16位无符号类型或者32位整数类型,则会将像素除以256,将范围由[0,255*256]映射到[0,255]
-
如果图像是32位或64位浮点类型,则将像素乘以255,即将范围由[0,1]映射到[0,255]
函数中第一个参数为图像显示窗口的名称,第二个参数是需要显示的图像Mat类矩阵。这里需要特殊说明的是,我们看到第二个参数并不是常见的Mat类,而是InputArray,这个是OpenCV定义的一个类型声明引用,用作输入参数的标识,我们在遇到它时可以认为是需要输入一个Mat类数据。同样,OpenCV对输出也定义了OutputArray类型,我们同样可以认为是输出一个Mat类数据。