赞
踩
1. 介绍
OpenCV是一个非常好用的图像处理和分析库,它包括了平面特征提取,3D校准,对象侦查,图像处理,影像分析等功能,几乎可以满足在机器学习中所需要的,对图像的一切功能。同时,这个库和numpy是一样的,在你之前安装anaconda的时候,就已经自动安装。如果没有,在对应环境下,使用pip install opencv-python
命令即可,如下所示:
下载成功以后,如果pycharm找不到它,你就来pycharm的Terminal这里再输入一次:
之后就可以用了,当然我这里还出现了程序可以运行,但是它不会有代码提示的问题,这个时候需要把opecv降级一下,之后就真没问题了:
pip install -i https://pypi.douban.com/simple opencv-python==4.5.3.56
在使用的时候,导入即可,它的库名是cv2,我们习惯叫它cv:
import cv2 as cv
2.读取图像并且显示
只需三行代码即可:
(1)读取:
img = cv.imread('图片的路径')
注意,这个图片如果和代码的.py文件在同一文件夹下,拿直接写名称即可(比如xxx.jpg),如果图片在.py文件同级的一个文件夹里面,则写:文件夹名/下级文件夹/…/xxx.png,如果图片在别处,那就要复制其路径(需要注意的是Windows用的是\,但是python里面\是有意义的,所以要把路径里面的\改成/)。
(2)显示:
cv.imshow('标题',img) # 把刚刚读取的图像扔进去,显示图像
cv.waitKey(0) # 卡住进程
这里要注意,标题一定要写,不然会报错,之后还需要把进程卡住,不然python会快速的执行代码,导致图片一闪而过。
如果出现显示的图片很大或者只显示了一个角落,那么可以使用下面的代码来动态调整图片大小:
img = cv.resize(img, (图片的长,图片的宽))
用我家猫的图片为例:
"""
@FileName:use_cv.py
@Description:OpenCV使用的例子
@Author:段鹏浩
@Time:2023/3/12 23:48
"""
import cv2 as cv
cat = cv.imread('E:/pictures/mycat.jpg')
cat = cv.resize(cat, (500,500)) # 调整大小
cv.imshow('cat', cat)
cv.waitKey(0)
运行结果为:
还有一种等比例的放缩方式:
img = cv.resize(img, None, fx=n, fy=m)
其中,None其实填尺寸的地方,这里不能不填,但是又不需要,所以给个None,n就是x轴方法的比例,m是y轴放大的比例。
因为我这张图很大,所以我将它缩小十倍。
"""
@FileName:use_cv.py
@Description:OpenCV使用的例子
@Author:段鹏浩
@Time:2023/3/12 23:48
"""
import cv2 as cv
cat = cv.imread('E:/pictures/mycat.jpg')
cat = cv.resize(cat, None, fx=0.1, fy=0.1) # 调整大小
cv.imshow('cat', cat)
cv.waitKey(0)
3.图像的压缩原理:插值法
我们如果仔细观察,不难发现,其实上面的两张变换过的图,和原图是不一样的(看猫左边的大腿就可以发现)。这是因为彩色图像其实是一个三维矩阵:
@Author:段鹏浩
@Time:2023/3/12 23:48
"""
import cv2 as cv
cat = cv.imread('E:/pictures/mycat.jpg')
cat = cv.resize(cat, None, fx=0.1, fy=0.1) # 调整大小
print(cat)
我们输出可以看到它是这样的
[[[ 51 55 73] [ 50 57 74] [ 50 59 73] ... [117 122 125] [120 125 128] [122 126 131]] [[ 47 54 73] [ 53 57 76] [ 48 55 72] ... [117 121 126] [119 123 128] [121 125 130]] [[ 48 52 70] [ 49 53 72] [ 50 57 74] ... [116 120 125] [119 124 127] [122 126 131]] ... [[ 48 51 49] [ 47 52 51] [ 51 51 51] ... [193 196 200] [183 186 191] [185 188 193]] [[ 49 51 52] [ 50 49 51] [ 50 52 52] ... [192 196 201] [190 193 198] [180 183 187]] [[ 48 52 53] [ 47 50 54] [ 49 51 52] ... [195 198 202] [194 197 202] [186 187 191]]]
所以对于放大和缩小图片有两种不同的方式:
(1)缩小:缩小图片,也叫对图片进行下采样,其实就是隔一段距离取走几个矩阵,这也就导致了缩小后的图片其实精度是比原图要低的,放大回去会比原图模糊。
(2)放大:放大图片也叫对图片进行上采样,它就要复杂一些,因为放大采用的是插值方法,比如用几个像素矩阵的平均值来填补中间的,或者用中位数等等,opencv已经提供了多个接口,如下:
接口名称 | 方法名称 |
---|---|
cv.INTER_NEAREST | 最邻近插值法 |
cv.INTER_LINEAR | 双线性插值法(默认的方法) |
cv.INTER_AREA | 像素区域关系重采样法 |
cv.INTER_CUBIC | 4X4像素邻域的双三次线性插值法 |
cv.INTER_LANCZOS4 | 8x8像素区域的Lanczos插值法 |
具体每种方法的原理是什么,感兴趣的可以去百度一下图形学,最大池化返回最大值有利于放大的原因也和插值原理相关,但是这和人工智能没有太大关系,不再一一讲解。这些接口的使用很简单:
在cv.resize的interpolation参数里面指定即可,如下:
img = cv,resize(img, (300, 300), interpolation=cv.INTER_AREA)
img2 = cv,resize(img, None,fx=2, fy=2, interpolation=cv.INTER_AREA)
4.图像的色彩转换
我们都知道,彩色图片由RGB三个色道组成,但是现在我们的cv.imread()函数读取到的图片是BGR(因为RGB是一个栈,只能反着从顶部按照顺序一层层地读入)。但是我们在进行图像处理的时候,往往会需要不同的图像色彩进行处理,比如把彩色图片转换成灰度图可以大大的减少输入,因此,我们来介绍一下图像的色彩空间有哪些,以及如何转换。
首先我们要先记住转换的代码:
cv.cvtColor(原图,转换的方法)
(1)灰度图:灰度图就是黑白图像,它把原本的RGB三色的图像转成黑白,维度也降低一维,所以输入的量大大的减少。转换灰度图时,你把图片看作是RGB还是BGR都没有关系,因为原理是对原本的每一个对应的RGB三个色求均值,之后在灰度表(也是0~255)找相应的值对上,这样原本三个矩阵就成了一个。转换接口为
cv.COLOR_RGB2GRAY或者cv.COLOR_BGR2GRAY
举例:
"""
@FileName:use_cv.py
@Description:OpenCV使用的例子
@Author:段鹏浩
@Time:2023/3/12 23:48
"""
import cv2 as cv
cat = cv.imread('E:/pictures/mycat.jpg')
cat = cv.resize(cat, None, fx=0.1, fy=0.1) # 调整大小
cat = cv.cvtColor(cat, cv.COLOR_BGR2GRAY) # 灰度图
cv.imshow("cat", cat)
cv.waitKey(0)
转换结果如下:
现在的矩阵为:
[[ 60 61 62 ... 122 125 127]
[ 59 62 59 ... 122 124 126]
[ 57 58 61 ... 121 124 127]
...
[ 50 51 51 ... 197 187 189]
[ 51 50 52 ... 197 194 184]
[ 52 51 51 ... 199 198 188]]
(2)HSV空间:HSV(Hue, Saturation, Value)是根据颜色的直观特性由A. R. Smith在1978年创建的一种颜色空间, 也称六角锥体模型(Hexcone Model)。
色调H:色彩信息,即所处的光谱颜色的位置。该参数用一角度量来表示,取值范围为0°~360°。若从红色开始按逆时针方向计算,红色为0°,绿色为120°,蓝色为240°。它们的补色是:黄为60°,青色为180°,紫色为300°;
饱和度S:取值范围为0.0~1.0;
亮度V:取值范围为0.0(黑色)~1.0(白色)。
HSV的图像:
转换的代码:cv.COLOR_RGB2HSV
和刚刚一样的例子:
"""
@FileName:use_cv.py
@Description:OpenCV使用的例子
@Author:段鹏浩
@Time:2023/3/12 23:48
"""
import cv2 as cv
cat = cv.imread('E:/pictures/mycat.jpg')
cat = cv.resize(cat, None, fx=0.1, fy=0.1) # 调整大小
cat = cv.cvtColor(cat, cv.COLOR_BGR2HSV)
#
cv.imshow("cat", cat)
cv.waitKey(0)
输出结果很像油画:
它的矩阵维度不变:
[[[ 5 77 73] [ 9 83 74] [ 12 80 73] ... [ 19 16 125] [ 19 16 128] [ 13 18 131]] [[ 8 91 73] [ 5 77 76] [ 9 85 72] ... [ 13 18 126] [ 13 18 128] [ 13 18 130]] [[ 5 80 70] [ 5 81 72] [ 9 83 74] ... [ 13 18 125] [ 19 16 127] [ 13 18 131]] ... [[ 50 15 51] [ 36 25 52] [ 0 0 51] ... [ 13 9 200] [ 11 11 191] [ 11 11 193]] [[ 20 15 52] [165 10 51] [ 30 10 52] ... [ 13 11 201] [ 11 10 198] [ 13 10 187]] [[ 24 24 53] [ 13 33 54] [ 20 15 52] ... [ 13 9 202] [ 11 10 202] [ 6 7 191]]]
(3)HLS空间: 其颜色成分也是色调、光度和饱和度, (色度) 。
色调H 的含义与 HSV 模型相同,不同之处在于此模型中的色调角度为 0 对应于蓝色。 洋红在60岁,红色是120。 与 HSV 模型一样,互补颜色相差 180。
L光度是颜色中黑色或白色的数量。 增加光度会增加白色的色调。 减少光线会向色调添加黑色。
S饱和度是色调的“纯洁度”的度量值。 随着饱和度下降,色调变得更加灰色。 饱和度值为零会导致灰度值。
HLS的图像变成了两个棱锥的拼接,表示的更全了:
转换的代码为:cv.COLOR_BGR2HLS
继续拿刚刚的图举例:
"""
@FileName:use_cv.py
@Description:OpenCV使用的例子
@Author:段鹏浩
@Time:2023/3/12 23:48
"""
import cv2 as cv
cat = cv.imread('E:/pictures/mycat.jpg')
cat = cv.resize(cat, None, fx=0.1, fy=0.1) # 调整大小
cat = cv.cvtColor(cat, cv.COLOR_BGR2HLS)
#
cv.imshow("cat", cat)
cv.waitKey(0)
输出的图片为:
(4)YCrCb空间:YCrCb即YUV,主要用于优化彩色视频信号的传输,使其向后相容老式黑白电视。与RGB视频信号传输相比,它最大的优点在于只需占用极少的频宽(RGB要求三个独立的视频信号同时传输)。其中“Y”表示明亮度(Luminance或Luma),也就是灰阶值;而“U”和“V” 表示的则是色度(Chrominance或Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。“亮度”是透过RGB输入信号来建立的,方法是将RGB信号的特定部分叠加到一起。“色度”则定义了颜色的两个方面─色调与饱和度,分别用Cr和Cb来表示。其中,Cr反映了RGB输入信号红色部分与RGB信号亮度值之间的差异。而Cb反映的是RGB输入信号蓝色部分与RGB信号亮度值之间的差异。
上面这段来自百度百科,说白了,YCrCb也是亮度色调和饱和度组成,他把上面棱锥变成了圆柱:
转换代码是:cv.COLOR_BGR2YCrCb
示例代码:
""" @FileName:use_cv.py @Description:OpenCV使用的例子 @Author:段鹏浩 @Time:2023/3/12 23:48 """ import cv2 as cv cat = cv.imread('E:/pictures/mycat.jpg') cat = cv.resize(cat, None, fx=0.1, fy=0.1) # 调整大小 cat = cv.cvtColor(cat, cv.COLOR_BGR2YCrCb) # cv.imshow("cat", cat) cv.waitKey(0) # print(cat)
输出的图像是:
输出矩阵是:
[[[ 60 137 123] [ 61 137 122] [ 62 136 121] ... [122 130 125] [125 130 125] [127 131 125]] [[ 59 138 121] [ 62 138 123] [ 59 137 122] ... [122 131 125] [124 131 125] [126 131 125]] [[ 57 137 123] [ 58 138 123] [ 61 137 122] ... [121 131 125] [124 130 125] [127 131 125]] ... [[ 50 127 127] [ 51 128 126] [ 51 128 128] ... [197 130 126] [187 131 126] [189 131 126]] [[ 51 129 127] [ 50 129 128] [ 52 128 127] ... [197 131 125] [194 131 126] [184 130 126]] [[ 52 129 126] [ 51 130 126] [ 51 129 127] ... [199 130 126] [198 131 126] [188 130 127]]]
(5)RGB空间:RGB即红黄蓝自然三原色,所以可以用RGB描述所有的颜色,我们平时图片就是这样的。我们前面知道OpneCV读取进来的是BGR图片,我们可以用指令cv.COLOR_BGR2RGB
将其转回来。
举例:
""" @FileName:use_cv.py @Description:OpenCV使用的例子 @Author:段鹏浩 @Time:2023/3/12 23:48 """ import cv2 as cv cat = cv.imread('E:/pictures/mycat.jpg') cat = cv.resize(cat, None, fx=0.1, fy=0.1) # 调整大小 cat = cv.cvtColor(cat, cv.COLOR_BGR2RGB) cv.imshow("cat", cat) cv.waitKey(0) # print(cat)
输出图片为:
原本的暖色调变成了冷色调,而且也不是那么接近原图,所以现转换以后其实还是有数据损失的,但是两者规模一样,图片特征也不会丢失,所以用什么都一样。
(6)指令格式总结:
cv.COLOR_RGB(或是BGR)2转换的色彩空间名称
5.直方图均衡化
直方图均衡化,是一种图像增强技术,它可以提高图像的亮度,让图像的特征轮廓更加突出。这里需要注意的是,只有一维的矩阵可以被均衡化处理,所以如果是彩色图片要先转换成灰度图。当然,我们可以使用我们之前学习的数组切片方法,对BGR图进行切片,分别把B,G,R切出来。这里注意,我们要用Z轴进行切分,像这样,每一处的逗号都不能省:
B = img[:, :,0] # 切出B色道的矩阵
G = img[:, :,1] # 切出G色道的矩阵
R = img[:, :,2] # 切出R色道的矩阵
b, g, r = cv.split(img) # 这个方法可以一次获得b,g,r且和上面的没有什么不同
具体的例子如下,下面例子中用的是第二种方法,如果你只需要某一个通道的就用第一种
""" @FileName:use_cv.py @Description:OpenCV使用的例子 @Author:段鹏浩 @Time:2023/3/12 23:48 """ import cv2 as cv import numpy as np cat = cv.imread('E:/pictures/mycat.jpg') cat = cv.resize(cat, None, fx=0.1, fy=0.1) # 调整大小 b, g, r = cv.split(cat) # 获取b,g,r的另一种方式 allcat = np.hstack((b, g, r)) # 把三个相同规模和维度的矩阵,横着拼一块 cv.imshow("cats", allcat) cv.waitKey(0) cv.destroyAllWindows()
注意代码这里用了np的hstack()函数,它可以把多个矩阵(要用元组装起来)横着拼一起,但是要求矩阵规模必须是一样的,因为图片也是矩阵,可以装一起(注意的是,灰度图和彩图因为维度不一样,所以是不能拼接的),如果要竖着拼接是vstack()。
下面是输出:
我们惊讶的发现全都是灰度图(虽然会有细微差异),这是因为执行的imshow函数时,如果是单一的矩阵,那么原图像三个通道的值都会被修改为相同的,对于BGR图像而言,只要三个通道值相等,那么得到的就是灰度图像(也就是OpenCV 把全部的二维矩阵当作灰度图来显示,把全部的三维当作BGR来显示)。这也是为什么用BGR切片也可以代替灰度图的原因,因为显示出来也是灰度图,灰度图只不过是这三个灰度图的平均值。
现在回到直方图均值化来,只需要一行代码就可以完成,其中原理不明白可以百度一下,现在不细说了:
new_img = cv.equalizeHist(灰度图)
举例:
""" @FileName:use_cv.py @Description:OpenCV使用的例子 @Author:段鹏浩 @Time:2023/3/12 23:48 """ import cv2 as cv import numpy as np cat = cv.imread('E:/pictures/mycat.jpg') cat = cv.resize(cat, None, fx=0.1, fy=0.1) # 调整大小 b, g, r = cv.split(cat) # 获取b,g,r的另一种方式 # 进行直方图均衡化 b = cv.equalizeHist(b) g = cv.equalizeHist(g) r = cv.equalizeHist(r) allcat = np.hstack((b, g, r)) # 把三个相同规模和维度的矩阵,横着拼一块 cv.imshow("cats", allcat) cv.waitKey(0) cv.destroyAllWindows() # print(cat)
输出如下:
和之前做对比:
亮度确实是增加了,这样像第一张图找眼睛会更容易。
6.如何显示真实的RGB通道图片:
虽然如何显示真实的RGB通道图片和人工智能毫不相干,但是读到前面,我觉肯定有人多少会有点好奇,如何不显示灰度值,真的显示红绿蓝三个色道。其实很简单,就是把图片保留成三维矩阵就行,即把其他的色道设为0,只保留想要的色道,这样做:
rimg = copy.copy(cat)# 先做三个副本
gimg = copy.copy(cat)
bimg = copy.copy(cat)
# R色道:
rimg[:,:,0] = 0 # 把B色道设为0
rimg[:,:,1] = 0 # 把G色道设为0
# G色道:
gimg[:,:,0] = 0 # 把B色道设为0
gimg[:,:,2] = 0 # 把R色道设为0
# B色道
bimg[:,:,1] = 0 # 把G设为0
bimg[:,:,2] = 0 # 把R设为0
注意,python很会利用内存,所以像图片这么大内存的东西,我们直接rimg = cat, gimg = cat,这样其实两个图片没有形成副本,你是在同一个图片上操作,等于传递的是C或者C++里面的指针。所以,我们如果要转为真正的副本(在内存形成副本),需要用copy.copy(要复制的对象)。
例子的代码:
""" @FileName:use_cv.py @Description:OpenCV使用的例子 @Author:段鹏浩 @Time:2023/3/12 23:48 """ import copy import cv2 as cv import numpy as np cat = cv.imread('E:/pictures/mycat.jpg') cat = cv.resize(cat, None, fx=0.1, fy=0.1) # 调整大小 rimg = copy.copy(cat)# 先做三个副本 gimg = copy.copy(cat) bimg = copy.copy(cat) # R色道: rimg[:, :, 0] = 0 # 把B色道设为0 rimg[:, :, 1] = 0 # 把G色道设为0 # # G色道: gimg[:, :, 0] = 0 # 把B色道设为0 gimg[:, :, 2] = 0 # 把R色道设为0 # # # B色道 bimg[:, :, 1] = 0 # 把G设为0 bimg[:, :, 2] = 0 # 把R设为0 allcat = np.hstack((rimg, gimg, bimg)) # 把三个相同规模和维度的矩阵,横着拼一块 cv.imshow("cats", allcat) cv.waitKey(0) cv.destroyAllWindows()
输出结果如下:
7.图片保存:
处理好的图片,我们需要把它们保存下来。OpenCV可以把图片保存为多种格式的图片,包括了:Windows位图⽂件 - BMP, DIB;JPEG⽂件 - JPEG, JPG, JPE;便携式⽹络图⽚ - PNG等。保存代码很简单:
cv.imwrite('路径/文件名', 要保存的图片变量)
就拿刚刚的图举个例子,不写路径的话保存在py的同级文件夹下:
""" @FileName:use_cv.py @Description:OpenCV使用的例子 @Author:段鹏浩 @Time:2023/3/12 23:48 """ import copy import cv2 as cv import numpy as np cat = cv.imread('E:/pictures/mycat.jpg') cat = cv.resize(cat, None, fx=0.1, fy=0.1) # 调整大小 rimg = copy.copy(cat)# 先做三个副本 gimg = copy.copy(cat) bimg = copy.copy(cat) # R色道: rimg[:, :, 0] = 0 # 把B色道设为0 rimg[:, :, 1] = 0 # 把G色道设为0 # # G色道: gimg[:, :, 0] = 0 # 把B色道设为0 gimg[:, :, 2] = 0 # 把R色道设为0 # # # B色道 bimg[:, :, 1] = 0 # 把G设为0 bimg[:, :, 2] = 0 # 把R设为0 allcat = np.hstack((rimg, gimg, bimg)) # 把三个相同规模和维度的矩阵,横着拼一块 cv.imwrite('cats.jpg', allcat)
成功:
8.总结:
在这章里我们学习了如何导入图片,显示图片,转换图片颜色空间,以及如何如何分割色道和直方图均衡化,还有图片的保存方法。下一章我们学习如何导入文件和数据集。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。