第八章 OpenCV的使用

2.OpenCV的使用

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:段鹏浩
@Time2023/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_CUBIC4X4像素邻域的双三次线性插值法
cv.INTER_LANCZOS48x8像素区域的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的图像:
图片来自网络,侵权请联系1700098233@qq.com

转换的代码: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也是亮度色调和饱和度组成,他把上面棱锥变成了圆柱:图片来自网络,侵权请联系1700098233@qq.com
转换代码是: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.总结:
在这章里我们学习了如何导入图片,显示图片,转换图片颜色空间,以及如何如何分割色道和直方图均衡化,还有图片的保存方法。下一章我们学习如何导入文件和数据集。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值