OpenCV与图像处理学习一——图像基础知识、读入、显示、保存图像、灰度转化、通道分离与合并
- 一、图像基础知识
- 1.1 数字图像的概念
- 1.2 数字图像的应用
- 1.3 OpenCV介绍
- 二、图像属性
- 2.1 图像格式
- 2.2 图像尺寸
- 2.2.1 读入图像
- 2.2.2 显示图像
- 2.2.3 保存图像
- 2.3 图像分辨率和通道数
- 2.3.1 灰度转化
- 2.3.2 RGB与BGR转化
- 2.3.3 通道分离
- 2.3.4 通道合并
图像处理与OpenCV作为CV方向的基础,在正式系统地学习论文之前,有必要对其进行系统的学习。而OpenCV作为使用最为广泛的图像处理工具包,这里将其作为学习的工具,因为较为熟悉python,所以使用OpenCV的python接口来完成代码。
图像处理与OpenCV的学习主要包括五个部分:
- 图像基础知识
- 图像处理
- 图像分割
- 图像特征与目标检测
- 运动目标识别(视频)
ps:OpenCV-python版的官方文档:https://docs.opencv.org/4.1.2/d6/d00/tutorial_py_root.html
一、图像基础知识
1.1 数字图像的概念
数字图像又称为数码图像或数位图像,是二维图像用有限数字数值像素的表示,由数组成矩阵来表示。下图是一个例子:
我们看见的图像在计算机中其实是由一个个像素组成的,每个像素有其具体数值。
也可以理解为一个二维函数 f(x,y),其中x和y是空间(平面)坐标,而在任意坐标处幅值 f 称为图像在该点处的强度或灰度。
1.2 数字图像的应用
图像处理、机器视觉与人工智能的关系:
- 图像处理主要研究二维检测,处理一个图像或一组图像之间的相互转换的过程,包括图像滤波、图像识别、图像分割等问题。
- 机器视觉主要研究映射到单幅或多幅图像上的三维场景,从图像中提取抽象的语义信息,实现图像理解是CV的终极目标。
- 人工智能在计算机视觉上的目标就是解决像素值和语义之间的关系,主要的问题有图片检测、图片识别、图片分割和检索等。
1.3 OpenCV介绍
OpenCV于1999年由Intel建立;是一个开源发行的跨平台计算机视觉库;支持的操作系统有Linux、Windows、Android、macOS。
由C函数与少量C++类构成,支持Python、Java、MATLAB等接口,是数字图像处理和CV领域最常见的工具包,是学习、科研、企业项目的好帮手。
OpenCV的安装(默认python已经安装):
打开命令行,输入以下命令,即可自动下载安装:
pip install opencv-contrib-python
二、图像属性
2.1 图像格式
常见的图像格式如下所示:
- BMP格式:这是Windows系统下的标准位图格式,未经过压缩,一般图像文件会比较大,后缀为.bmp。
- JPEG格式:应用最广泛的图片格式之一,它采用一种特殊的有损压缩算法,达到比较大的压缩比(可达到2:1甚至40:1),后缀名为.jpg或.jpeg。
- GIF格式:不仅可以是一张静图,也可以是动图,并且支持透明背景图像,适用于多种操作系统,“体型”很小,网上很多小动画都是GIF格式。但是其色域不太广,只支持256色。
- PNG格式:与JPG格式类似,压缩比高于GIF,支持图像透明,支持Alpha通道调节图像的透明度。
- TIFF格式:图像格式复杂,存贮信息多,在Mac中广泛使用,非常有利于原稿的复制,很多地方将TIFF格式用于印刷。
2.2 图像尺寸
图像尺寸的长度和宽度是以像素为单位的,比如下面图片的尺寸是240×150,这个数字的单位就是像素。那么像素具体是什么含义?
像素pixel:
像素是数码影像最基本的单位。1.1那张图中数字化后图片变成了一个个小格子组成的大矩阵,每个小格子就是一个像素,它里面会有一个值,灰度像素点的值的范围在0~255之间,0表示黑色,255表示白色,其他值是介于黑白之间的不同灰;
如果是彩色图,会需要用到红、绿、蓝三个通道的二维矩阵来表示,在每个通道中,每个值也介于0~255之间,0表示相应的基色,而255表示相应基色在该像素中取得的最大值。
2.2.1 读入图像
cv2.imread( filename[, flags] )
参数:第一个参数为读入图像的路径;第二个则是读取的方式,常见方式有:
cv2.IMREAD_COLOR
:默认方式,读取彩色图像,也可以用 1 来表示。cv2.IMREAD_GRAYSCALE
:读取图像为灰度图,也可以用 0 来表示。cv2.IMREAD_UNCHANGED
:读取彩色图,并且包括透明度通道,也可以用 -1 来表示。
举例:
# 导入opencv的python版本依赖库cv2
import cv2
# 使用opencv中imread函数读取图片,
# 0代表灰度图形式打开,1代表彩色形式打开
img = cv2.imread('split.jpg', 1)
print(img.shape)
输出为这张图片的尺寸(shape):
(459, 571, 3)
2.2.2 显示图像
cv2.imshow( winname, mat )
参数:第一个参数为窗口的名字(显示图片必须先有一个窗口),第二个参数为图像变量名。
举例:
# 导入opencv的python版本依赖库cv2
import cv2
# 使用opencv中imread函数读取图片,
# 0代表灰度图形式打开,1代表彩色形式打开
img = cv2.imread('split.jpg', 1)
print(img.shape)
# print(img)cv2.imshow('photo', img)
k = cv2.waitKey(0)
if k == 27: # 输入ESC键退出cv2.destroyAllWindows()
elif k == ord('s'): # 输入S键保存图片并退出cv2.imwrite('split_.jpg', img)
cv2.destroyAllWindows()
其中cv2.waitKey()函数是一个键盘绑定函数,单位为毫秒,即程序等待键盘输入多少毫秒,在这等待的时间内从键盘输入的键值会赋给k,然后k去进行下一步程序,如cv2.waitKey(1000)就是等待1s;如果参数值为0,则表示一直等待直到键盘有输入。
另外,cv2.destroyAllWindows()函数表示删除窗口,默认删除所有窗口,参数为待删窗口名。
2.2.3 保存图像
cv2.imwrite( filename, img[, params] )
参数:第一个参数为希望保存成的图像名(包括格式(后缀)),第二个参数为待写入的图像变量名。
2.2.2的代码已经给出了举例。
2.3 图像分辨率和通道数
分辨率是指单位长度中所表达或截取的像素数目。每英寸图像内的像素点数,单位是像素每英寸(ppi)。图像的分辨率越高,像素点密度越高,图像越清晰。
通道数是指图像的位深度,描述图像中每个pixel数值所占的二进制位数。位深度越大则图像能表示的颜色数越多,色彩就越丰富。有以下几种位深度:
- 8位:单通道图像,也就是灰度图,灰度值取值种类为2 ^ 8 = 256种,即0~255。
- 24位:三通道,彩色图像,每个通道都有8位。
- 32位:三通道彩色图像加上透明度Alpha通道。
2.3.1 灰度转化
目的:将彩色图转化为灰度图。
公式:
- 3通道彩图->1通道灰图:GRAY = B * 0.114 + G * 0.587 + R * 0.299
- 1通道灰图->3通道灰图:R = G = B = GRAY;A = 0
函数为:
cv2.cvtColor( src, code[, dst[, dstCn]] )
参数:第一个参数就是待转化的图像变量;第二个参数是转换模式,OpenCV有二百多种模式转换,具体可以通过以下代码查看:
>>> import cv2 as cv
>>> flags = [i for i in dir(cv) if i.startswith('COLOR_')]
>>> print( flags )
输出如下:
['COLOR_BAYER_BG2BGR', 'COLOR_BAYER_BG2BGRA', 'COLOR_BAYER_BG2BGR_EA', 'COLOR_BAYER_BG2BGR_VNG', 'COLOR_BAYER_BG2GRAY', 'COLOR_BAYER_BG2RGB', 'COLOR_BAYER_BG2RGBA', 'COLOR_BAYER_BG2RGB_EA', 'COLOR_BAYER_BG2RGB_VNG', 'COLOR_BAYER_GB2BGR', 'COLOR_BAYER_GB2BGRA', 'COLOR_BAYER_GB2BGR_EA', 'COLOR_BAYER_GB2BGR_VNG', 'COLOR_BAYER_GB2GRAY', 'COLOR_BAYER_GB2RGB', 'COLOR_BAYER_GB2RGBA', 'COLOR_BAYER_GB2RGB_EA', 'COLOR_BAYER_GB2RGB_VNG', 'COLOR_BAYER_GR2BGR', 'COLOR_BAYER_GR2BGRA', 'COLOR_BAYER_GR2BGR_EA', 'COLOR_BAYER_GR2BGR_VNG', 'COLOR_BAYER_GR2GRAY', 'COLOR_BAYER_GR2RGB', 'COLOR_BAYER_GR2RGBA', 'COLOR_BAYER_GR2RGB_EA', 'COLOR_BAYER_GR2RGB_VNG', 'COLOR_BAYER_RG2BGR', 'COLOR_BAYER_RG2BGRA', 'COLOR_BAYER_RG2BGR_EA', 'COLOR_BAYER_RG2BGR_VNG', 'COLOR_BAYER_RG2GRAY', 'COLOR_BAYER_RG2RGB', 'COLOR_BAYER_RG2RGBA', 'COLOR_BAYER_RG2RGB_EA', 'COLOR_BAYER_RG2RGB_VNG', 'COLOR_BGR2BGR555', 'COLOR_BGR2BGR565', 'COLOR_BGR2BGRA', 'COLOR_BGR2GRAY', 'COLOR_BGR2HLS', 'COLOR_BGR2HLS_FULL', 'COLOR_BGR2HSV', 'COLOR_BGR2HSV_FULL', 'COLOR_BGR2LAB', 'COLOR_BGR2LUV', 'COLOR_BGR2Lab', 'COLOR_BGR2Luv', 'COLOR_BGR2RGB', 'COLOR_BGR2RGBA', 'COLOR_BGR2XYZ', 'COLOR_BGR2YCR_CB', 'COLOR_BGR2YCrCb', 'COLOR_BGR2YUV', 'COLOR_BGR2YUV_I420', 'COLOR_BGR2YUV_IYUV', 'COLOR_BGR2YUV_YV12', 'COLOR_BGR5552BGR', 'COLOR_BGR5552BGRA', 'COLOR_BGR5552GRAY', 'COLOR_BGR5552RGB', 'COLOR_BGR5552RGBA', 'COLOR_BGR5652BGR', 'COLOR_BGR5652BGRA', 'COLOR_BGR5652GRAY', 'COLOR_BGR5652RGB', 'COLOR_BGR5652RGBA', 'COLOR_BGRA2BGR', 'COLOR_BGRA2BGR555', 'COLOR_BGRA2BGR565', 'COLOR_BGRA2GRAY', 'COLOR_BGRA2RGB', 'COLOR_BGRA2RGBA', 'COLOR_BGRA2YUV_I420', 'COLOR_BGRA2YUV_IYUV', 'COLOR_BGRA2YUV_YV12', 'COLOR_BayerBG2BGR', 'COLOR_BayerBG2BGRA', 'COLOR_BayerBG2BGR_EA', 'COLOR_BayerBG2BGR_VNG', 'COLOR_BayerBG2GRAY', 'COLOR_BayerBG2RGB', 'COLOR_BayerBG2RGBA', 'COLOR_BayerBG2RGB_EA', 'COLOR_BayerBG2RGB_VNG', 'COLOR_BayerGB2BGR', 'COLOR_BayerGB2BGRA', 'COLOR_BayerGB2BGR_EA', 'COLOR_BayerGB2BGR_VNG', 'COLOR_BayerGB2GRAY', 'COLOR_BayerGB2RGB', 'COLOR_BayerGB2RGBA', 'COLOR_BayerGB2RGB_EA', 'COLOR_BayerGB2RGB_VNG', 'COLOR_BayerGR2BGR', 'COLOR_BayerGR2BGRA', 'COLOR_BayerGR2BGR_EA', 'COLOR_BayerGR2BGR_VNG', 'COLOR_BayerGR2GRAY', 'COLOR_BayerGR2RGB', 'COLOR_BayerGR2RGBA', 'COLOR_BayerGR2RGB_EA', 'COLOR_BayerGR2RGB_VNG', 'COLOR_BayerRG2BGR', 'COLOR_BayerRG2BGRA', 'COLOR_BayerRG2BGR_EA', 'COLOR_BayerRG2BGR_VNG', 'COLOR_BayerRG2GRAY', 'COLOR_BayerRG2RGB', 'COLOR_BayerRG2RGBA', 'COLOR_BayerRG2RGB_EA', 'COLOR_BayerRG2RGB_VNG', 'COLOR_COLORCVT_MAX', 'COLOR_GRAY2BGR', 'COLOR_GRAY2BGR555', 'COLOR_GRAY2BGR565', 'COLOR_GRAY2BGRA', 'COLOR_GRAY2RGB', 'COLOR_GRAY2RGBA', 'COLOR_HLS2BGR', 'COLOR_HLS2BGR_FULL', 'COLOR_HLS2RGB', 'COLOR_HLS2RGB_FULL', 'COLOR_HSV2BGR', 'COLOR_HSV2BGR_FULL', 'COLOR_HSV2RGB', 'COLOR_HSV2RGB_FULL', 'COLOR_LAB2BGR', 'COLOR_LAB2LBGR', 'COLOR_LAB2LRGB', 'COLOR_LAB2RGB', 'COLOR_LBGR2LAB', 'COLOR_LBGR2LUV', 'COLOR_LBGR2Lab', 'COLOR_LBGR2Luv', 'COLOR_LRGB2LAB', 'COLOR_LRGB2LUV', 'COLOR_LRGB2Lab', 'COLOR_LRGB2Luv', 'COLOR_LUV2BGR', 'COLOR_LUV2LBGR', 'COLOR_LUV2LRGB', 'COLOR_LUV2RGB', 'COLOR_Lab2BGR', 'COLOR_Lab2LBGR', 'COLOR_Lab2LRGB', 'COLOR_Lab2RGB', 'COLOR_Luv2BGR', 'COLOR_Luv2LBGR', 'COLOR_Luv2LRGB', 'COLOR_Luv2RGB', 'COLOR_M_RGBA2RGBA', 'COLOR_RGB2BGR', 'COLOR_RGB2BGR555', 'COLOR_RGB2BGR565', 'COLOR_RGB2BGRA', 'COLOR_RGB2GRAY', 'COLOR_RGB2HLS', 'COLOR_RGB2HLS_FULL', 'COLOR_RGB2HSV', 'COLOR_RGB2HSV_FULL', 'COLOR_RGB2LAB', 'COLOR_RGB2LUV', 'COLOR_RGB2Lab', 'COLOR_RGB2Luv', 'COLOR_RGB2RGBA', 'COLOR_RGB2XYZ', 'COLOR_RGB2YCR_CB', 'COLOR_RGB2YCrCb', 'COLOR_RGB2YUV', 'COLOR_RGB2YUV_I420', 'COLOR_RGB2YUV_IYUV', 'COLOR_RGB2YUV_YV12', 'COLOR_RGBA2BGR', 'COLOR_RGBA2BGR555', 'COLOR_RGBA2BGR565', 'COLOR_RGBA2BGRA', 'COLOR_RGBA2GRAY', 'COLOR_RGBA2M_RGBA', 'COLOR_RGBA2RGB', 'COLOR_RGBA2YUV_I420', 'COLOR_RGBA2YUV_IYUV', 'COLOR_RGBA2YUV_YV12', 'COLOR_RGBA2mRGBA', 'COLOR_XYZ2BGR', 'COLOR_XYZ2RGB', 'COLOR_YCR_CB2BGR', 'COLOR_YCR_CB2RGB', 'COLOR_YCrCb2BGR', 'COLOR_YCrCb2RGB', 'COLOR_YUV2BGR', 'COLOR_YUV2BGRA_I420', 'COLOR_YUV2BGRA_IYUV', 'COLOR_YUV2BGRA_NV12', 'COLOR_YUV2BGRA_NV21', 'COLOR_YUV2BGRA_UYNV', 'COLOR_YUV2BGRA_UYVY', 'COLOR_YUV2BGRA_Y422', 'COLOR_YUV2BGRA_YUNV', 'COLOR_YUV2BGRA_YUY2', 'COLOR_YUV2BGRA_YUYV', 'COLOR_YUV2BGRA_YV12', 'COLOR_YUV2BGRA_YVYU', 'COLOR_YUV2BGR_I420', 'COLOR_YUV2BGR_IYUV', 'COLOR_YUV2BGR_NV12', 'COLOR_YUV2BGR_NV21', 'COLOR_YUV2BGR_UYNV', 'COLOR_YUV2BGR_UYVY', 'COLOR_YUV2BGR_Y422', 'COLOR_YUV2BGR_YUNV', 'COLOR_YUV2BGR_YUY2', 'COLOR_YUV2BGR_YUYV', 'COLOR_YUV2BGR_YV12', 'COLOR_YUV2BGR_YVYU', 'COLOR_YUV2GRAY_420', 'COLOR_YUV2GRAY_I420', 'COLOR_YUV2GRAY_IYUV', 'COLOR_YUV2GRAY_NV12', 'COLOR_YUV2GRAY_NV21', 'COLOR_YUV2GRAY_UYNV', 'COLOR_YUV2GRAY_UYVY', 'COLOR_YUV2GRAY_Y422', 'COLOR_YUV2GRAY_YUNV', 'COLOR_YUV2GRAY_YUY2', 'COLOR_YUV2GRAY_YUYV', 'COLOR_YUV2GRAY_YV12', 'COLOR_YUV2GRAY_YVYU', 'COLOR_YUV2RGB', 'COLOR_YUV2RGBA_I420', 'COLOR_YUV2RGBA_IYUV', 'COLOR_YUV2RGBA_NV12', 'COLOR_YUV2RGBA_NV21', 'COLOR_YUV2RGBA_UYNV', 'COLOR_YUV2RGBA_UYVY', 'COLOR_YUV2RGBA_Y422', 'COLOR_YUV2RGBA_YUNV', 'COLOR_YUV2RGBA_YUY2', 'COLOR_YUV2RGBA_YUYV', 'COLOR_YUV2RGBA_YV12', 'COLOR_YUV2RGBA_YVYU', 'COLOR_YUV2RGB_I420', 'COLOR_YUV2RGB_IYUV', 'COLOR_YUV2RGB_NV12', 'COLOR_YUV2RGB_NV21', 'COLOR_YUV2RGB_UYNV', 'COLOR_YUV2RGB_UYVY', 'COLOR_YUV2RGB_Y422', 'COLOR_YUV2RGB_YUNV', 'COLOR_YUV2RGB_YUY2', 'COLOR_YUV2RGB_YUYV', 'COLOR_YUV2RGB_YV12', 'COLOR_YUV2RGB_YVYU', 'COLOR_YUV420P2BGR', 'COLOR_YUV420P2BGRA', 'COLOR_YUV420P2GRAY', 'COLOR_YUV420P2RGB', 'COLOR_YUV420P2RGBA', 'COLOR_YUV420SP2BGR', 'COLOR_YUV420SP2BGRA', 'COLOR_YUV420SP2GRAY', 'COLOR_YUV420SP2RGB', 'COLOR_YUV420SP2RGBA', 'COLOR_YUV420p2BGR', 'COLOR_YUV420p2BGRA', 'COLOR_YUV420p2GRAY', 'COLOR_YUV420p2RGB', 'COLOR_YUV420p2RGBA', 'COLOR_YUV420sp2BGR', 'COLOR_YUV420sp2BGRA', 'COLOR_YUV420sp2GRAY', 'COLOR_YUV420sp2RGB', 'COLOR_YUV420sp2RGBA', 'COLOR_mRGBA2RGBA']
那么这里的灰度转化需要用到的是cv2.COLOR_BGR2GRAY和cv2.COLOR_GRAY2BGR。
举例如下:
# 导入opencv
import cv2
# 读入原始图像,使用cv2.IMREAD_UNCHANGED
img = cv2.imread("girl.jpg", cv2.IMREAD_UNCHANGED)
# 查看打印图像的shape
shape = img.shape
print(shape)
# 判断通道数是否为3通道或4通道
if shape[2] == 3 or shape[2] == 4 :# 将彩色图转化为单通道图img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)cv2.imshow("gray_image", img_gray)
cv2.imshow("image", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
显示出来的原图与灰度化之后的图为:
这里的灰度图是单通道的,若将此时的img_gray 再通过cv2.COLOR_GRAY2BGR转为三通道的图,它将还是灰度图,只是通道数变成了三个,三通道每个像素上的B、G、R值都相等,且等于img_gray 的那个像素,代码如下所示:
# 导入opencv
import cv2
# 读入灰度图
img = cv2.imread("girl_gray.jpg", cv2.IMREAD_UNCHANGED)
# 查看打印图像的shape
shape = img.shape
print(shape)
img_color = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
print(img_color.shape)
cv2.imshow("color_image", img_color)
cv2.imshow("image", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
效果如图所示:
视觉上细看还是有些许不同,我们搞清楚它们在计算机内的区别就行,再看下原图、单通道灰度图、三通道灰度图的尺寸区别:
原图: (500, 500, 3)
单通道灰度图: (500, 500)
三通道灰度图: (500, 500, 3)
2.3.2 RGB与BGR转化
方法一:用OpenCV自带的方法
# 导入opencv
import cv2
# 读入图
img = cv2.imread("dark2.jpg", cv2.IMREAD_COLOR)
cv2.imshow("Origin", img)
img_cv_method = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
cv2.imshow("After transform", img_cv_method)cv2.waitKey(0)
cv2.destroyAllWindows()
方法二:用numpy转换,本质就是互换B和R通道,所以将方法一的代码中的cvtColor函数的那一行替换为
img_cv_method = img[:, :, ::-1]
效果是一样的,得到的原图和转换之后的图的显示如下所示:
2.3.3 通道分离
目的:将彩色图像分成B、G、R三个单通道图像,方便我们对BGR三个通道分别操作。
函数:
cv.split( m[, mv] )
参数:待分离通道的图像。
举例:
# 加载opencv
import cv2
src = cv2.imread('split.jpg')
cv2.imshow('before', src)
# 调用通道分离
b, g, r = cv2.split(src)
# 三通道分别显示
cv2.imshow('blue', b)
cv2.imshow('green', g)
cv2.imshow('red', r)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果如下所示:
分离出来的每个通道都是一个灰度图。如果我们想看它们是对应通道的颜色,可以用下面的代码:
# 导入opencv模块
import numpy as np
import cv2image = cv2.imread("split.jpg") # 读取要处理的图片
cv2.imshow("src", image)
cv2.waitKey(0)
B, G, R = cv2.split(image) # 分离出图片的B,R,G颜色通道zeros = np.zeros(image.shape[:2], dtype="uint8") # 创建与image相同大小的零矩阵
cv2.imshow("BLUE", cv2.merge([B, zeros, zeros])) # 显示 (B,0,0)图像
cv2.imshow("GREEN", cv2.merge([zeros, G, zeros])) # 显示(0,G,0)图像
cv2.imshow("RED", cv2.merge([zeros, zeros, R])) # 显示(0,0,R)图像
cv2.waitKey(0)
cv2.destroyAllWindows()
效果如下所示:
这里我们可以看出,单通道是没有颜色的,只有数值,R、G、B颜色要放在三通道中才能显示出来。
2.3.4 通道合并
目的:三个单独的通道合并为一个彩图。
函数:
cv.merge( mv[, dst] )
参数:待合并的通道数,以list形式输入。
举例:
#加载opencv
import cv2
src=cv2.imread('split.jpg')
cv2.imshow('before',src)
#调用通道分离
b,g,r=cv2.split(src)
#将Blue通道数值修改为0
b[:] = 0
#合并修改后的通道
img_merge=cv2.merge([b,g,r])
cv2.imshow('merge',img_merge)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果如下所示: