前言
笔记系列
参考书籍:OpenCV3编程入门
作者:毛星云
版权方:电子工业出版社
出版日期:2015-02
笔记仅供本人参考使用,不具备共通性
笔记中代码均是OpenCV+Qt的代码,并非用vs开发,请勿混淆
HighGUI模块为高层GUI图形用户界面模块
它的功能包括
- 媒体的输入输出
- 视频捕捉
- 图像和视频的编码解码
- 图形交互界面的接口
- …
3.1 图形的载入、显示和输出到文件
- OpenCV1.0时代的基于C语言接口而建的图像存储格式
IplImage*
十分不好用 - 进入到2.0时代后,OpenCV采用了Mat类作为数据结构进行图像存取
- 此改进使得OpenCV变得容易上手和用于实际开发
3.1.1 OpenCV的命名空间
-
OpenCV中的C++类和函数都是定义在命名空间cv之内的
-
我们有两种方法可以访问cv
- 其一:在代码开头的适当位置加上
using namespace cv;
这句代码以规定我们的程序位于词命名空间之内 - 其二:在使用OpenCV的每一个类和函数时,都在前面加上
cv::
- 相较而言,显然第一种方法更加方便,推荐使用
- 其一:在代码开头的适当位置加上
平常在写简单的OpenCV程序时,以下三句可以作为标配
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
3.1.2 Mat类简析
-
Mat类
-
是用于保存图像以及其他矩阵数据的数据结构
-
默认情况下Mat类的尺寸为0
- 可以用类似于
cv::Mat pic(320,640,cv::Scalar(100));
的代码来定义一个初始带尺寸的Mat类
- 可以用类似于
-
Mat最基本的用法如下
-
using namespace cv; Mat srcImage = imread("需要加载的图像路径");//路径可以是绝对路径,也可以是相对路径
-
上面的代码表示将一张图片载入到Mat类型的srcImage变量中
- (尽量是jpg或png格式的,其他格式我还没试过,不知道可不可行)
-
代码中的imread()函数,是用于将图片读入Mat类型中,后面会详细讲解
-
-
3.1.3 图像的载入与显示概述
-
图像载入用到的代码
-
imread()
-
-
图像显示用到的代码
-
imshow()
-
3.1.4 图像的载入:imread()函数
-
功能:用于读取文件中的图片到OpenCV中
-
函数的原型如下:
-
enum ImreadModes{ IMREAD_COLOR = 1, //!< If set, always convert image to the 3 channel BGR color image.}; //上面是截取的部分代码,下面是imread()函数的声明 Mat imread( const String& filename, int flags = IMREAD_COLOR ); //参数一:需要载入的图片路径名 参数二:载入标识符
-
第一个参数:const String& filename ---- 我们需要载入的图片路径名
-
在Windows操作系统下,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 = IMREAD_COLOR
-
载入标识符,它指定一个加载图像的颜色类型和图片深度
-
flags默认值为IMREAD_COLOR,也就是1,所以有些时候这个参数在调用时可以忽略,此时表示载入三通道的彩色图图像
-
同时通过上面的代码展示可以看出来,此参数可以在OpenCV中标识图像格式的枚举体中取值
-
让我们转到定义,看看这个枚举体,如下
-
//! Imread flags enum ImreadModes { IMREAD_UNCHANGED = -1, //!< If set, return the loaded image as is (with alpha channel, otherwise it gets cropped). Ignore EXIF orientation. //如果设置,则按原样返回加载的图像(带有Alpha通道,否则将被裁剪)。 忽略EXIF方向 IMREAD_GRAYSCALE = 0, //!< If set, always convert image to the single channel grayscale image (codec internal conversion). //如果设置,则始终将图像转换为单通道灰度图像(编解码器内部转换)。 IMREAD_COLOR = 1, //!< If set, always convert image to the 3 channel BGR color image. //如果设置,则始终将图像转换为3通道BGR彩色图像。 IMREAD_ANYDEPTH = 2, //!< If set, return 16-bit/32-bit image when the input has the corresponding depth, otherwise convert it to 8-bit. //如果设置,则当输入具有相应的深度时返回16位/ 32位图像,否则将其转换为8位。 IMREAD_ANYCOLOR = 4, //!< If set, the image is read in any possible color format. //如果设置,将以任何可能的颜色格式读取图像。 IMREAD_LOAD_GDAL = 8, //!< If set, use the gdal driver for loading the image. //如果已设置,则使用gdal驱动程序加载图像。 IMREAD_REDUCED_GRAYSCALE_2 = 16, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/2. //如果设置,则始终将图像转换为单通道灰度图像,并且图像尺寸减小1/2。 IMREAD_REDUCED_COLOR_2 = 17, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/2. //如果设置,则始终将图像转换为3通道BGR彩色图像,并且图像尺寸减小1/2。 IMREAD_REDUCED_GRAYSCALE_4 = 32, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/4. //如果设置,则始终将图像转换为单通道灰度图像,并且图像尺寸缩小1/4 IMREAD_REDUCED_COLOR_4 = 33, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/4. //如果设置,则始终将图像转换为3通道BGR彩色图像,并且图像尺寸减小1/4。 IMREAD_REDUCED_GRAYSCALE_8 = 64, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/8. //如果设置,则始终将图像转换为单通道灰度图像,并且图像尺寸减小1/8。 IMREAD_REDUCED_COLOR_8 = 65, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/8. //如果设置,则始终将图像转换为3通道BGR彩色图像,并且图像尺寸减小1/8。 IMREAD_IGNORE_ORIENTATION = 128 //!< If set, do not rotate the image according to EXIF's orientation flag. //如果已设置,则不要根据EXIF的方向标志旋转图像。 };
-
上述代码选择解释
-
枚举值 解释说明 IMREAD_UNCHANGED 等价取值为-1,该标识符在新版本中已被废置,忽略 IMREAD_GRAYSCALE 等价取值为0,如果取这个标识的话,会将载入的图像转换成灰度图在返回 IMREAD_COLOR 等价取值为1,若是取这个标识的话,会将图片转换成3通道BGR彩色图像并返回 IMREAD_ANYDEPTH 等价取值为2,若是取这个标识的话,会先检查图像的深度,若图像深度为16位或32位,则返回对应深度的图像,否则,会将图像转换位8位图像再返回 -
注意:
如果输入有冲突的标志,则采用较小的数字值,例如:- 当
flag = IMREAD_COLOR|IMREAD_ANYCOLOR
时,程序将载入三通道图- 这里的IMREAD_COLOR(等价于1)和IMREAD_ANYCOLOR(等价于4)是相互冲突的,因为二者都是对读取图像的颜色的方法做规定
- 而如果想要载入最真实无损的源图像,可以选择
flag = IMREAD_ANYCOLOR|IMREAD_ANYDEPTH
- 此处的IMREAD_ANYCOLOR(等价于4)和IMREAD_ANYDEPTH(等价于2)是不相互冲突的,因为前者是对读取图片的颜色的方面做规定,后者是对读取图片的深度的方面做规定
- 因此,
flag = IMREAD_ANYCOLOR|IMREAD_ANYDEPTH
标识符所代表的意思是以任何可能的颜色格式,任何可能的图像深度来读取图像
- 当
-
-
-
注意:下面的表格并不全对,这只是书上的描述,在最新的OpenCV3的版本中,有些许出入
-
因为flags是int型的变量,若我们不在这个枚举体中去固定的值,可以这样进行
-
flags取值 达到的效果 flags > 0 返回一个3通道的彩色图像,但数值越大,图片就会呗压缩得越厉害! flags = 0 返回灰度图像 flags < 0 返回包含Alpha通道的加载图像 -
输出的图像默认情况下不返回Alpha通道,所以若想载入Alpha通道,这里就需要取负值
-
在书上,作者这样写道:通过表可知,flags = 1999也是可以的,它和flags = 1的效果一样,同样标识返回一个3通道的彩色图像
-
然而,最新的Opencv3的代码已经不太一样了,flag>1时,不一定会返回一个BGR三通道的图像,甚至flag在不同的数字区间中,所返回的图片大小也是不一样的(具体原因看上面的枚举体代码)
-
-
-
imread的一些常见用法
-
Mat image0 = imread("1.jpg",2|4);//载入无损的源图像 Mat image1 = imread("1.jpg",0);//载入灰度图 Mat image2 = imread("1.jpg",1);//载入3通道的彩色图像
-
-
3.1.5 图像的显示:imshow()函数
-
imshow()函数用于在指定的窗口中显示一副图像
-
其函数原型如下
-
void imshow(const String& winname, InputArray mat); //参数一:图像窗口的标识名称 参数二:需要显示的图像
-
第一个参数:const String& winname
- 填写要显示的窗口标识名称(暂时不能打中文,问题未解决)
-
第二个参数: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]
-
此外,若是在窗口创建的时候,程序设定支持OpenGL(WINDOW_OPENGL),那么imshow还支持
olg::Buffer
、olg::Texture2D
和gpu::GpuMat
作为输入,其函数原型如下-
namespace ogl { class CV_EXPORTS Buffer; class CV_EXPORTS Texture2D; class CV_EXPORTS Arrays; } void imshow(const String& winname, const ogl::Texture2D& tex);
-
-
关于imread()和imshow()函数最精简的示例程序,可以参考书本第一章中,1.3.8节的"最终的测试",或者1.4.1中"第一个程序:图像显示"中的代码.
-
3.1.6 关于InputArray类型
找到InputArray类型的定义,再OpenCV 3.4.13版本中,该类型位于...\opencv2\core\mat.hpp
中
typedef const _InputArray& InputArray;
从此处可以看出:此处是一个类型声明引用,亦即_InputArray
和InputArray
是同一个变量,所以我们接着做定义跳转
跳到_InputArray的定义处
class CV_EXPORTS _InputArray
{
public:
enum {
KIND_SHIFT = 16,
FIXED_TYPE = 0x8000 << KIND_SHIFT,
FIXED_SIZE = 0x4000 << KIND_SHIFT,
KIND_MASK = 31 << KIND_SHIFT,
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, //!< removed
OPENGL_BUFFER = 7 << KIND_SHIFT,
CUDA_HOST_MEM = 8 << KIND_SHIFT,
CUDA_GPU_MAT = 9 << KIND_SHIFT,
UMAT =10 << KIND_SHIFT,
STD_VECTOR_UMAT =11 << KIND_SHIFT,
STD_BOOL_VECTOR =12 << KIND_SHIFT,
STD_VECTOR_CUDA_GPU_MAT = 13 << KIND_SHIFT,
STD_ARRAY =14 << KIND_SHIFT,
STD_ARRAY_MAT =15 << KIND_SHIFT
};
_InputArray();
_InputArray(int _flags, void* _obj);
_InputArray(const Mat& m);
_InputArray(const MatExpr& expr);
_InputArray(const std::vector<Mat>& vec);
template<typename _Tp> _InputArray(const Mat_<_Tp>& m);
template<typename _Tp> _InputArray(const std::vector<_Tp>& vec);
_InputArray(const std::vector<bool>& vec);
template<typename _Tp> _InputArray