目录
一、前言
上一篇文章我们讲了安装和配置,这节课我们还是了解几个最基本的操作,包括图像的读取、图像的显示、图像的修改、图像的保存。
如果你已经有了解过OpenCV,那对这些概念可能比较清楚,如果你是一个小白,想入门学习OpenCV4.3.0,那先不要想太多,先跟我一起读懂每一个API,跟我一起学着写代码。
我们这一系列文章,会讲解API,API的功能、API调参、API的原理,但是我们不会讲API的实现细节,如果你对具体实现细节有兴趣,你可以查看源码以及数字图像处理原理。
二、图像基本操作
图像基本操作包括加载,修改,显示,保存。
0、啥是API
从今天这篇文章开始往后,我们会经常讲到API,所以我们要介绍一下,什么是API?
API的定义如下:
API(Application Programming Interface,应用程序接口)是一些预先定义的函数,或指软件系统不同组成部分衔接的约定。目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问原码,或理解内部工作机制的细节。
通过定义,我们就很好理解了,API其实就是利用类,结构体,函数等将一些我们要使用的功能封装起来,学过面向对象的应该对封装很了解,如果没有学过也么有关系,封装很好理解,比如你玩游戏,你按键,游戏中的角色就会有动作,你不需要管,为什么按键角色就会动,不用管具体怎么实现这个功能,只要知道按哪个键,会有什么动作就可以啦。就像你调用别人写的函数,你不用管别人怎么实现的这个函数,你只需要知道函数实现什么功能,需要什么参数,得到什么输出就可以了。
理解了API,我们就可以继续往下学习了。
1、加载图像CV :: imread
1.加载图像是什么?
加载图象就是将图像进行读取,获取图像的信息,并存到一个Mat对象中,方便后续操作。
2.API
加载图像的API是imread,函数原型是:
Mat imread( const String& filename, int flags = IMREAD_COLOR );
函数参数含义如下:
(1)const String类型的filename,要加载的图像的文件名,可以包括路径。
(2)int类型的flags,加载图像的方式,默认是IMREAD_COLOR,也就是原图展示。
对于第二个参数,我们有如下不同的可取值:
//! 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.
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.
IMREAD_ANYDEPTH = 2, //!< If set, return 16-bit/32-bit image when the input has the corresponding depth, otherwise convert it to 8-bit.
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.
IMREAD_REDUCED_GRAYSCALE_2 = 16, //!< If set, always convert image to the single channel grayscale image and the image size reduced 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.
IMREAD_REDUCED_GRAYSCALE_4 = 32, //!< If set, always convert image to the single channel grayscale image and the image size reduced 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.
IMREAD_REDUCED_GRAYSCALE_8 = 64, //!< If set, always convert image to the single channel grayscale image and the image size reduced 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.
IMREAD_IGNORE_ORIENTATION = 128 //!< If set, do not rotate the image according to EXIF's orientation flag.
};
不同取值含义如下:
(1)IMREAD_UNCHANGED:按原样返回加载的图像
(2)IMREAD_GRAYSCALE:将图像转换为单通道灰度图像输出
(3)IMREAD_COLOR:将图像转换为3通道BGR彩色图像
(4)IMREAD_ANYDEPTH:输入具有相应深度时返回16位/32位图像,否则将其转换为8位
(5)IMREAD_ANYCOLOR:以任何可能的颜色格式读取图像
(6)IMREAD_LOAD_GDAL:使用gdal驱动程序加载图像
(7)IMREAD_REDUCED_GRAYSCALE_2:图像转换为单通道灰度图像,图像大小减小1/2
(8)IMREAD_REDUCED_COLOR_2:将图像转换为3通道BGR彩色图像,图像大小减小1/2
(9)IMREAD_REDUCED_GRAYSCALE_4:将图像转换为单通道灰度图像,图像大小减小1/4
(10)IMREAD_REDUCED_COLOR_4:图像转换为3通道BGR彩色图像,图像大小减小1/4
(11)IMREAD_REDUCED_GRAYSCALE_8:将图像转换为单通道灰度图像,图像大小减小1/8
(12)IMREAD_REDUCED_COLOR_8:将图像转换为3通道BGR彩色图像,图像大小减小1/8
(13)IMREAD_IGNORE_ORIENTATION:不要根据EXIF的方向标志旋转图像
在这里我们看到几个重要的新概念:单通道,三通道,彩图,灰度图。不要担心,在后面我们会讲到,如果你渴望现在就能看到他,那你可以点击传送门:
注:一般情况下,我们都默认调用一个参数,后面他默认调用参数IMREAD_COLOR,即原图加载。
如下面这个例子:
Mat src = imread("E:/image/circle.bmp");
2、创建窗口cv::namedWindow
1.创建窗口是什么?
在显示之前,我们首先需要创建一个窗口,用以显示图像,我们使用的是 namedWindow 这个 API,功能是创建一个OpenCV窗口,它是由OpenCV自动创建与释放,你无需取销毁它。
2.API
创建窗口的API是namedWindow,函数原型是:
void namedWindow(const String& winname, int flags = WINDOW_AUTOSIZE);
函数参数含义如下:
(1)const String类型的winname,要创建的窗口名称。
(2)int类型的flags,创建窗口类型,默认是WINDOW_AUTOSIZE,也就是自动尺寸,会根据图像本身的大小来确定窗口的大小。
对于第二个参数,我们有如下不同的可取值:
//! Flags for cv::namedWindow
enum WindowFlags {
WINDOW_NORMAL = 0x00000000, //!< the user can resize the window (no constraint) / also use to switch a fullscreen window to a normal size.
WINDOW_AUTOSIZE = 0x00000001, //!< the user cannot resize the window, the size is constrainted by the image displayed.
WINDOW_OPENGL = 0x00001000, //!< window with opengl support.
WINDOW_FULLSCREEN = 1, //!< change the window to fullscreen.
WINDOW_FREERATIO = 0x00000100, //!< the image expends as much as it can (no ratio constraint).
WINDOW_KEEPRATIO = 0x00000000, //!< the ratio of the image is respected.
WINDOW_GUI_EXPANDED=0x00000000, //!< status bar and tool bar
WINDOW_GUI_NORMAL = 0x00000010, //!< old fashious way
};
不同取值含义如下:
(1)WINDOW_NORMAL:用户可以调整窗口大小
(2)WINDOW_AUTOSIZE:加载图像大小
(3)WINDOW_OPENGL:支持opengl的窗口
(4)WINDOW_FULLSCREEN:窗口为全屏
(5)WINDOW_FREERATIO:图像尽可能地扩展
(6)WINDOW_KEEPRATIO:尊重图像的比率
(7)WINDOW_GUI_EXPANDED:状态栏和工具栏
(8)WINDOW_GUI_NORMAL:过时的方式
注:一般情况下,我们都默认调用一个参数,后面他默认调用一个参数,即原图大小加载。
如下面这个例子:
namedWindow("input image", CV_WINDOW_AUTOSIZE);
或者这样:
#define INPUT_TITLE "input image" // 宏定义,原始图片
namedWindow(INPUT_TITLE, CV_WINDOW_AUTOSIZE);
目前这个函数也支持,直接用一来代替后面的参数,我们看一个示例吧!
namedWindow("src1", 1);
3.它是必要的吗?
如果我们不使用这个功能,我们还能显示图像吗?
答案是肯定的,图像的展示,其实不依赖于这个API,即使你不创建窗口,依然可以显示图像,但是在一些代码中,创建窗口是必要的,比如我们要在窗口中添加一些东西,我们只有先创建这个窗口,才能添加。
3、显示图像CV :: imshow
1.显示图像是什么?
显示图像就是将图像在黑窗体展现出来,让我们能够更加直观的看到我们读取到的图像及其处理后的效果。
2.API
显示图像的API是imshow,函数原型是:
void imshow(const String& winname, InputArray mat);
函数参数含义如下:
(1)const String类型的winname,图像展示的窗口名称。
(2)InputArray类型的mat,要展示的图像。
例如下面这个例子:
imshow("src1", src1);
上面这个代码,我们发现,我们在显示图像的时候,直接给窗口赋值就可以了,与之前是否创建窗口没有关系。这也就说明,如果只是单纯的展示图片,是不需要创建窗口代码的,在展示的时候,就会自动创建了。
4、修改图像 (cv::cvtColor)
1.修改图像是什么?
修改图像就是对图像进行一系列像素操作,把图像从一个色彩空间转换到另外一个色彩空间。
2.API
修改图像的API是cvtColor,函数原型是:
void cvtColor( InputArray src, OutputArray dst, int code, int dstCn = 0 );
函数参数含义如下:
(1)InputArray类型的src,输入图像。
(2)OutputArray类型的dst,修改后的图像,图像尺寸和深度与输入图像一致。
(3)int类型的code,图像修改方式,取值于:ColorConversionCodes。
(4)int类型的dstCn,目标图像中的通道数;如果参数为0,通道数将自动从src和code获得。
对于第三个参数,取值于ColorConversionCodes:
/** the color conversion codes
@see @ref imgproc_color_conversions
@ingroup imgproc_color_conversions
*/
enum ColorConversionCodes {
COLOR_BGR2BGRA = 0, //!< add alpha channel to RGB or BGR image
COLOR_RGB2RGBA = COLOR_BGR2BGRA,
COLOR_BGRA2BGR = 1, //!< remove alpha channel from RGB or BGR image
COLOR_RGBA2RGB = COLOR_BGRA2BGR,
COLOR_BGR2RGBA = 2, //!< convert between RGB and BGR color spaces (with or without alpha channel)
COLOR_RGB2BGRA = COLOR_BGR2RGBA,
COLOR_RGBA2BGR = 3,
COLOR_BGRA2RGB = COLOR_RGBA2BGR,
COLOR_BGR2RGB = 4,
COLOR_RGB2BGR = COLOR_BGR2RGB,
COLOR_BGRA2RGBA = 5,
COLOR_RGBA2BGRA = COLOR_BGRA2RGBA,
COLOR_BGR2GRAY = 6, //!< convert between RGB/BGR and grayscale, @ref color_convert_rgb_gray "color conversions"
COLOR_RGB2GRAY = 7,
COLOR_GRAY2BGR = 8,
COLOR_GRAY2RGB = COLOR_GRAY2BGR,
COLOR_GRAY2BGRA = 9,
COLOR_GRAY2RGBA = COLOR_GRAY2BGRA,
COLOR_BGRA2GRAY = 10,
COLOR_RGBA2GRAY = 11,
COLOR_BGR2BGR565 = 12, //!< convert between RGB/BGR and BGR565 (16-bit images)
COLOR_RGB2BGR565 = 13,
COLOR_BGR5652BGR = 14,
COLOR_BGR5652RGB = 15,
COLOR_BGRA2BGR565 = 16,
COLOR_RGBA2BGR565 = 17,
COLOR_BGR5652BGRA = 18,
COLOR_BGR5652RGBA = 19,
COLOR_GRAY2BGR565 = 20, //!< convert between grayscale to BGR565 (16-bit images)
COLOR_BGR5652GRAY = 21,
COLOR_BGR2BGR555 = 22, //!< convert between RGB/BGR and BGR555 (16-bit images)
COLOR_RGB2BGR555 = 23,
COLOR_BGR5552BGR = 24,
COLOR_BGR5552RGB = 25,
COLOR_BGRA2BGR555 = 26,
COLOR_RGBA2BGR555 = 27,
COLOR_BGR5552BGRA = 28,
COLOR_BGR5552RGBA = 29,
COLOR_GRAY2BGR555 = 30, //!< convert between grayscale and BGR555 (16-bit images)
COLOR_BGR5552GRAY = 31,
COLOR_BGR2XYZ = 32, //!< convert RGB/BGR to CIE XYZ, @ref color_convert_rgb_xyz "color conversions"
COLOR_RGB2XYZ = 33,
COLOR_XYZ2BGR = 34,
COLOR_XYZ2RGB = 35,
COLOR_BGR2YCrCb = 36, //!< convert RGB/BGR to luma-chroma (aka YCC), @ref color_convert_rgb_ycrcb "color conversions"
COLOR_RGB2YCrCb = 37,
COLOR_YCrCb2BGR = 38,
COLOR_YCrCb2RGB = 39,
COLOR_BGR2HSV = 40, //!< convert RGB/BGR to HSV (hue saturation value), @ref color_convert_rgb_hsv "color conversions"
COLOR_RGB2HSV = 41,
COLOR_BGR2Lab = 44, //!< convert RGB/BGR to CIE Lab, @ref color_convert_rgb_lab "color conversions"
COLOR_RGB2Lab = 45,
COLOR_BGR2Luv = 50, //!< convert RGB/BGR to CIE Luv, @ref color_convert_rgb_luv "color conversions"
COLOR_RGB2Luv = 51,
COLOR_BGR2HLS = 52, //!< convert RGB/BGR to HLS (hue lightness saturation), @ref color_convert_rgb_hls "color conversions"
COLOR_RGB2HLS = 53,
COLOR_HSV2BGR = 54, //!< backward conversions to RGB/BGR
COLOR_HSV2RGB = 55,
COLOR_Lab2BGR = 56,
COLOR_Lab2RGB = 57,
COLOR_Luv2BGR = 58,
COLOR_Luv2RGB = 59,
COLOR_HLS2BGR = 60,
COLOR_HLS2RGB = 61,
COLOR_BGR2HSV_FULL = 66,
COLOR_RGB2HSV_FULL = 67,
COLOR_BGR2HLS_FULL = 68,
COLOR_RGB2HLS_FULL = 69,
COLOR_HSV2BGR_FULL = 70,
COLOR_HSV2RGB_FULL = 71,
COLOR_HLS2BGR_FULL = 72,
COLOR_HLS2RGB_FULL = 73,
COLOR_LBGR2Lab = 74,
COLOR_LRGB2Lab = 75,
COLOR_LBGR2Luv = 76,
COLOR_LRGB2Luv = 77,
COLOR_Lab2LBGR = 78,
COLOR_Lab2LRGB = 79,
COLOR_Luv2LBGR = 80,
COLOR_Luv2LRGB = 81,
COLOR_BGR2YUV = 82, //!< convert between RGB/BGR and YUV
COLOR_RGB2YUV = 83,
COLOR_YUV2BGR = 84,
COLOR_YUV2RGB = 85,
//! YUV 4:2:0 family to RGB
COLOR_YUV2RGB_NV12 = 90,
COLOR_YUV2BGR_NV12 = 91,
COLOR_YUV2RGB_NV21 = 92,
COLOR_YUV2BGR_NV21 = 93,
COLOR_YUV420sp2RGB = COLOR_YUV2RGB_NV21,
COLOR_YUV420sp2BGR = COLOR_YUV2BGR_NV21,
COLOR_YUV2RGBA_NV12 = 94,
COLOR_YUV2BGRA_NV12 = 95,
COLOR_YUV2RGBA_NV21 = 96,
COLOR_YUV2BGRA_NV21 = 97,
COLOR_YUV420sp2RGBA = COLOR_YUV2RGBA_NV21,
COLOR_YUV420sp2BGRA = COLOR_YUV2BGRA_NV21,
COLOR_YUV2RGB_YV12 = 98,
COLOR_YUV2BGR_YV12 = 99,
COLOR_YUV2RGB_IYUV = 100,
COLOR_YUV2BGR_IYUV = 101,
COLOR_YUV2RGB_I420 = COLOR_YUV2RGB_IYUV,
COLOR_YUV2BGR_I420 = COLOR_YUV2BGR_IYUV,
COLOR_YUV420p2RGB = COLOR_YUV2RGB_YV12,
COLOR_YUV420p2BGR = COLOR_YUV2BGR_YV12,
COLOR_YUV2RGBA_YV12 = 102,
COLOR_YUV2BGRA_YV12 = 103,
COLOR_YUV2RGBA_IYUV = 104,
COLOR_YUV2BGRA_IYUV = 105,
COLOR_YUV2RGBA_I420 = COLOR_YUV2RGBA_IYUV,
COLOR_YUV2BGRA_I420 = COLOR_YUV2BGRA_IYUV,
COLOR_YUV420p2RGBA = COLOR_YUV2RGBA_YV12,
COLOR_YUV420p2BGRA = COLOR_YUV2BGRA_YV12,
COLOR_YUV2GRAY_420 = 106,
COLOR_YUV2GRAY_NV21 = COLOR_YUV2GRAY_420,
COLOR_YUV2GRAY_NV12 = COLOR_YUV2GRAY_420,
COLOR_YUV2GRAY_YV12 = COLOR_YUV2GRAY_420,
COLOR_YUV2GRAY_IYUV = COLOR_YUV2GRAY_420,
COLOR_YUV2GRAY_I420 = COLOR_YUV2GRAY_420,
COLOR_YUV420sp2GRAY = COLOR_YUV2GRAY_420,
COLOR_YUV420p2GRAY = COLOR_YUV2GRAY_420,
//! YUV 4:2:2 family to RGB
COLOR_YUV2RGB_UYVY = 107,
COLOR_YUV2BGR_UYVY = 108,
//COLOR_YUV2RGB_VYUY = 109,
//COLOR_YUV2BGR_VYUY = 110,
COLOR_YUV2RGB_Y422 = COLOR_YUV2RGB_UYVY,
COLOR_YUV2BGR_Y422 = COLOR_YUV2BGR_UYVY,
COLOR_YUV2RGB_UYNV = COLOR_YUV2RGB_UYVY,
COLOR_YUV2BGR_UYNV = COLOR_YUV2BGR_UYVY,
COLOR_YUV2RGBA_UYVY = 111,
COLOR_YUV2BGRA_UYVY = 112,
//COLOR_YUV2RGBA_VYUY = 113,
//COLOR_YUV2BGRA_VYUY = 114,
COLOR_YUV2RGBA_Y422 = COLOR_YUV2RGBA_UYVY,
COLOR_YUV2BGRA_Y422 = COLOR_YUV2BGRA_UYVY,
COLOR_YUV2RGBA_UYNV = COLOR_YUV2RGBA_UYVY,
COLOR_YUV2BGRA_UYNV = COLOR_YUV2BGRA_UYVY,
COLOR_YUV2RGB_YUY2 = 115,
COLOR_YUV2BGR_YUY2 = 116,
COLOR_YUV2RGB_YVYU = 117,
COLOR_YUV2BGR_YVYU = 118,
COLOR_YUV2RGB_YUYV = COLOR_YUV2RGB_YUY2,
COLOR_YUV2BGR_YUYV = COLOR_YUV2BGR_YUY2,
COLOR_YUV2RGB_YUNV = COLOR_YUV2RGB_YUY2,
COLOR_YUV2BGR_YUNV = COLOR_YUV2BGR_YUY2,
COLOR_YUV2RGBA_YUY2 = 119,
COLOR_YUV2BGRA_YUY2 = 120,
COLOR_YUV2RGBA_YVYU = 121,
COLOR_YUV2BGRA_YVYU = 122,
COLOR_YUV2RGBA_YUYV = COLOR_YUV2RGBA_YUY2,
COLOR_YUV2BGRA_YUYV = COLOR_YUV2BGRA_YUY2,
COLOR_YUV2RGBA_YUNV = COLOR_YUV2RGBA_YUY2,
COLOR_YUV2BGRA_YUNV = COLOR_YUV2BGRA_YUY2,
COLOR_YUV2GRAY_UYVY = 123,
COLOR_YUV2GRAY_YUY2 = 124,
//CV_YUV2GRAY_VYUY = CV_YUV2GRAY_UYVY,
COLOR_YUV2GRAY_Y422 = COLOR_YUV2GRAY_UYVY,
COLOR_YUV2GRAY_UYNV = COLOR_YUV2GRAY_UYVY,
COLOR_YUV2GRAY_YVYU = COLOR_YUV2GRAY_YUY2,
COLOR_YUV2GRAY_YUYV = COLOR_YUV2GRAY_YUY2,
COLOR_YUV2GRAY_YUNV = COLOR_YUV2GRAY_YUY2,
//! alpha premultiplication
COLOR_RGBA2mRGBA = 125,
COLOR_mRGBA2RGBA = 126,
//! RGB to YUV 4:2:0 family
COLOR_RGB2YUV_I420 = 127,
COLOR_BGR2YUV_I420 = 128,
COLOR_RGB2YUV_IYUV = COLOR_RGB2YUV_I420,
COLOR_BGR2YUV_IYUV = COLOR_BGR2YUV_I420,
COLOR_RGBA2YUV_I420 = 129,
COLOR_BGRA2YUV_I420 = 130,
COLOR_RGBA2YUV_IYUV = COLOR_RGBA2YUV_I420,
COLOR_BGRA2YUV_IYUV = COLOR_BGRA2YUV_I420,
COLOR_RGB2YUV_YV12 = 131,
COLOR_BGR2YUV_YV12 = 132,
COLOR_RGBA2YUV_YV12 = 133,
COLOR_BGRA2YUV_YV12 = 134,
//! Demosaicing
COLOR_BayerBG2BGR = 46,
COLOR_BayerGB2BGR = 47,
COLOR_BayerRG2BGR = 48,
COLOR_BayerGR2BGR = 49,
COLOR_BayerBG2RGB = COLOR_BayerRG2BGR,
COLOR_BayerGB2RGB = COLOR_BayerGR2BGR,
COLOR_BayerRG2RGB = COLOR_BayerBG2BGR,
COLOR_BayerGR2RGB = COLOR_BayerGB2BGR,
COLOR_BayerBG2GRAY = 86,
COLOR_BayerGB2GRAY = 87,
COLOR_BayerRG2GRAY = 88,
COLOR_BayerGR2GRAY = 89,
//! Demosaicing using Variable Number of Gradients
COLOR_BayerBG2BGR_VNG = 62,
COLOR_BayerGB2BGR_VNG = 63,
COLOR_BayerRG2BGR_VNG = 64,
COLOR_BayerGR2BGR_VNG = 65,
COLOR_BayerBG2RGB_VNG = COLOR_BayerRG2BGR_VNG,
COLOR_BayerGB2RGB_VNG = COLOR_BayerGR2BGR_VNG,
COLOR_BayerRG2RGB_VNG = COLOR_BayerBG2BGR_VNG,
COLOR_BayerGR2RGB_VNG = COLOR_BayerGB2BGR_VNG,
//! Edge-Aware Demosaicing
COLOR_BayerBG2BGR_EA = 135,
COLOR_BayerGB2BGR_EA = 136,
COLOR_BayerRG2BGR_EA = 137,
COLOR_BayerGR2BGR_EA = 138,
COLOR_BayerBG2RGB_EA = COLOR_BayerRG2BGR_EA,
COLOR_BayerGB2RGB_EA = COLOR_BayerGR2BGR_EA,
COLOR_BayerRG2RGB_EA = COLOR_BayerBG2BGR_EA,
COLOR_BayerGR2RGB_EA = COLOR_BayerGB2BGR_EA,
//! Demosaicing with alpha channel
COLOR_BayerBG2BGRA = 139,
COLOR_BayerGB2BGRA = 140,
COLOR_BayerRG2BGRA = 141,
COLOR_BayerGR2BGRA = 142,
COLOR_BayerBG2RGBA = COLOR_BayerRG2BGRA,
COLOR_BayerGB2RGBA = COLOR_BayerGR2BGRA,
COLOR_BayerRG2RGBA = COLOR_BayerBG2BGRA,
COLOR_BayerGR2RGBA = COLOR_BayerGB2BGRA,
COLOR_COLORCVT_MAX = 143
};
我们发现,这些图像修改方式的格式都是固定的:COLOR_(类型1)2(类型2)
COLOR我们可以理解为图像色彩的变化,2和to谐音,就是从类型1转化到类型2,最常用的类型主要有如下几个:
BGR,RGB,BGRA,RGBA:B指的是blue蓝色,G指的是green绿色,R指的是red红色,A指的是alpha通道,表示图像的透明度。
GRAY:灰度图像。
HSV:hue saturation value,分别是色调(H),饱和度(S),明度(V)。
使用方法如下面这个例子:
cvtColor(src1, src2, CV_RGB2GRAY);
5、保存图像 (cv::imwrite)
1.保存图像是什么?
保存图像文件到指定目录路径,但是有要求,只有8位、16位的PNG、JPG、Tiff文件格式而且是单通道或者三通道的BGR的图像才可以通过这种方式保存。而且,保存PNG格式的时候可以保存透明通道的图片。
2.API
保存图像的API是imwrite,函数原型是:
bool imwrite( const String& filename, InputArray img, const std::vector<int>& params = std::vector<int>());
函数参数含义如下:
(1)const String类型的filename,图像输出名称,如果没有路径,就保存在代码同文件夹下。
(2)InputArray类型的img,要输出为文件的图像。
(3)const std::vector<int>,表示特定格式的图像编码。参见cv::ImwriteFlags
对于参数3,具体的类型要参见cv::ImwriteFlags:
//! Imwrite flags
enum ImwriteFlags {
IMWRITE_JPEG_QUALITY = 1, //!< For JPEG, it can be a quality from 0 to 100 (the higher is the better). Default value is 95.
IMWRITE_JPEG_PROGRESSIVE = 2, //!< Enable JPEG features, 0 or 1, default is False.
IMWRITE_JPEG_OPTIMIZE = 3, //!< Enable JPEG features, 0 or 1, default is False.
IMWRITE_JPEG_RST_INTERVAL = 4, //!< JPEG restart interval, 0 - 65535, default is 0 - no restart.
IMWRITE_JPEG_LUMA_QUALITY = 5, //!< Separate luma quality level, 0 - 100, default is 0 - don't use.
IMWRITE_JPEG_CHROMA_QUALITY = 6, //!< Separate chroma quality level, 0 - 100, default is 0 - don't use.
IMWRITE_PNG_COMPRESSION = 16, //!< For PNG, it can be the compression level from 0 to 9. A higher value means a smaller size and longer compression time. If specified, strategy is changed to IMWRITE_PNG_STRATEGY_DEFAULT (Z_DEFAULT_STRATEGY). Default value is 1 (best speed setting).
IMWRITE_PNG_STRATEGY = 17, //!< One of cv::ImwritePNGFlags, default is IMWRITE_PNG_STRATEGY_RLE.
IMWRITE_PNG_BILEVEL = 18, //!< Binary level PNG, 0 or 1, default is 0.
IMWRITE_PXM_BINARY = 32, //!< For PPM, PGM, or PBM, it can be a binary format flag, 0 or 1. Default value is 1.
IMWRITE_EXR_TYPE = (3 << 4) + 0, /* 48 */ //!< override EXR storage type (FLOAT (FP32) is default)
IMWRITE_WEBP_QUALITY = 64, //!< For WEBP, it can be a quality from 1 to 100 (the higher is the better). By default (without any parameter) and for quality above 100 the lossless compression is used.
IMWRITE_PAM_TUPLETYPE = 128,//!< For PAM, sets the TUPLETYPE field to the corresponding string value that is defined for the format
IMWRITE_TIFF_RESUNIT = 256,//!< For TIFF, use to specify which DPI resolution unit to set; see libtiff documentation for valid values
IMWRITE_TIFF_XDPI = 257,//!< For TIFF, use to specify the X direction DPI
IMWRITE_TIFF_YDPI = 258, //!< For TIFF, use to specify the Y direction DPI
IMWRITE_TIFF_COMPRESSION = 259, //!< For TIFF, use to specify the image compression scheme. See libtiff for integer constants corresponding to compression formats. Note, for images whose depth is CV_32F, only libtiff's SGILOG compression scheme is used. For other supported depths, the compression scheme can be specified by this flag; LZW compression is the default.
IMWRITE_JPEG2000_COMPRESSION_X1000 = 272 //!< For JPEG2000, use to specify the target compression rate (multiplied by 1000). The value can be from 0 to 1000. Default is 1000.
};
不同取值含义如下:
(1)IMWRITE_JPEG_QUALITY:对于JPEG,可以是0到100之间的质量(越高越好)。默认值为95。
(2)IMWRITE_JPEG_PROGRESSIVE:启用JPEG功能,0或1,默认为False。
(3)IMWRITE_JPEG_OPTIMIZE:启用JPEG功能,0或1,默认为False。
(4)IMWRITE_JPEG_RST_INTERVAL:JPEG重新启动间隔,0-65535,默认值为0-不重新启动。
(5)IMWRITE_JPEG_LUMA_QUALITY:单独的亮度质量等级,0 - 100,默认为0 -不使用。
(6)IMWRITE_JPEG_CHROMA_QUALITY:单独的色度质量等级,0 - 100,缺省值为0 -不要使用。
(7)IMWRITE_PNG_COMPRESSION:对于PNG,可以是0到9之间的压缩级别。较高的值意味着较小的大小和较长的压缩时间。如果指定,策略将更改为IMWRITE_PNG_strategy_DEFAULT(Z_DEFAULT_strategy)。默认值为1(最佳速度设置)
(8)IMWRITE_PNG_STRATEGY:默认为IMWRITE_PNG_STRATEGY_RLE。
(9)IMWRITE_PNG_BILEVEL:二进制级别PNG,0或1,默认值为0。
(10)IMWRITE_PXM_BINARY:对于PPM、PGM或PBM,它可以是二进制格式标志0或1。默认值为1。
(11)IMWRITE_EXR_TYPE:重写EXR存储类型(默认为浮点(FP32))
(12)IMWRITE_WEBP_QUALITY:对于WEBP,它可以是1到100的质量(越高越好)。默认情况下(不带任何参数),对于质量高于100的情况,使用无损压缩。
(13)IMWRITE_PAM_TUPLETYPE:对于PAM,将TUPLETYPE字段设置为为格式定义的相应字符串值。
(14)IMWRITE_TIFF_RESUNIT:对于TIFF,用于指定要设置的DPI分辨率单位;有关有效值,请参阅libtiff文档
(15)IMWRITE_TIFF_XDPI:对于TIFF,用于指定X方向DPI
(16)IMWRITE_TIFF_YDPI:对于TIFF,用于指定Y方向DPI。
(17)IMWRITE_TIFF_COMPRESSION:对于TIFF,用于指定图像压缩方案。有关与压缩格式对应的整数常量,请参见libtiff。注意,对于深度为CV f的图像,仅使用libtiff的SGILOG压缩方案。对于其他支持的深度,可以使用此标志指定压缩方案;默认为LZW压缩。
(18)IMWRITE_JPEG2000_COMPRESSION_X1000:对于JPEG2000,用于指定目标压缩率(乘以1000)。该值可以从0到1000。默认值为1000。
在实际学习中,我们涉及不到这么复杂的图像存储格式,一般我们第三个参数默认不写,这里我们要举例子说明一下第一个参数,如果我们在图像名称中不写入路径。如下面这个例子:
imwrite("src2.jpg", src2);
这会默认保存到与cpp相同的路径下,如果想指定路径,可以在第一个参数中加上路径,比如保存到D盘中的某个文件夹下:
imwrite("D:/image/src2.jpg", src2);
如果想保存到相对路径,可以用 ./ 的方式,如下:
imwrite("./image/src2.jpg", src2);
三、全部代码及结果展示
1、代码
/*
作者:水亦心
内容:图像基本操作:图像读取,显示,修改,保存。
时间:2020年5月8日
*/
#define INPUT_TITLE "input image"
#define OUTPUT_TITLE_GRAY "output_image_gray"
#define OUTPUT_TITLE_HSV "output_image_HSV"
#include<iostream>
#include<opencv2\opencv.hpp>
using namespace std;
using namespace cv;
int main() {
Mat src, dst_gray,dst_HSV;
src = imread("./image/cat.jpg");
if (!src.data)
{
cout << "ERROR : could not load image.\n";
waitKey(0);
return -1;
}
namedWindow(INPUT_TITLE, WINDOW_AUTOSIZE);
imshow(INPUT_TITLE, src);
//转为灰度图
cvtColor(src, dst_gray, COLOR_BGR2GRAY);
imshow(OUTPUT_TITLE_GRAY, dst_gray);
imwrite("./image/cat_gray.jpg", dst_gray);
//转为HSV空间图
cvtColor(src, dst_HSV, COLOR_BGR2HSV);
imshow(OUTPUT_TITLE_HSV, dst_HSV);
imwrite("./image/cat_HSV.jpg", dst_HSV);
waitKey(0);
return 0;
}
2、运行效果图
五、几个图像基本概念
前面我们说到了图像的几个基本概念,包括单通道,多通道,灰度图,彩图。
我不知道看我博客的小朋友有没有看到过黑白电视,那个时候,只有黑色白色和不同程度的灰色,那个图就是灰度图。现在我们看的各种类型的电视,图像都是带有五颜六色的,这个图是彩图。
灰度图比较简单,它只有一个空间来存储颜色,颜色的取值为[0,255],如果为0,那就是纯黑色图像,如果为255,就是纯白色图像。数值越大,颜色越淡,灰度越小。所以我们说,灰度图是单通道的图像。
彩图有三个空间,分别来存储红蓝绿,也就是RGB,这三个空间就是三通道,这三个颜色也是光学三原色,我们可以利用三个颜色不同的比例,配制出各种各样的颜色。
今天的内容就讲到这里啦,有什么问题,大家可以在下面留言哦!
来源:oschina
链接:https://my.oschina.net/u/4406182/blog/4274794