文章目录
OpenCV库(一)
一、 简介
1、 简介
Opencv(Open Source Computer Vision Library)是一个基于开源发行的跨平台计算机视觉库,它实现了图像处理和计算机视觉方面的很多通用算法,已成为计算机视觉领域最有力的研究工具。在这里我们要区分两个概念:图像处理和计算机视觉的区别:图像处理侧重于“处理”图像–如增强,还原,去噪,分割等等;而计算机视觉重点在于使用计算机来模拟人的视觉,因此模拟才是计算机视觉领域的最终目标
图是物体反射或透射光的分布,像是人的视觉系统所接受的图在人脑中所形成的印象或认识
OpenCV用C++语言编写,它具有C ++,Python,Java和MATLAB接口,并支持Windows,Linux,Android和Mac OS, 如今也提供对于C#、Ch、Ruby,GO的支持
2、 环境配置
2.1 第一种
下载OpenCV:【https://www.lfd.uci.edu/~gohlke/pythonlibs/#opencv】
找到对应版本的OpenCV,下载下来
复制文件的地址:【“D:\Documents\opencv_python-4.5.5-cp39-cp39-win_amd64.whl”】
然后打开终端输入:【pip install "D:\Documents\opencv_python-4.5.5-cp39-cp39-win_amd64.whl"
】
安装完成后
创建一个python文件,在文件中输入
import cv2
print(cv2.__version__)
成功运行代表安装成功
2.2 第二种
直接在终端输入:pip install opencv-python
这种方式安装较慢哦!
注意:运行OpenCV还要有依赖库 numpy
安装 numpy
pip install numpy
3、 运行原理
一般的图像(模拟图像)不能直接用计算机来处理,必须先将图像转化为数字图像。把模拟图像分割成一个个像素,每个像素的亮度或灰度值用一个整数表示——图像的数字化
3.1 灰度图像数字化
所谓的数字化,其实就是化成同行同列的二维数组,而每个坐标存的就是相关的灰度值(0-255)(为什么是0-255?一个字节存放8bit,而图的储存一般都是以uint8类型存放,同时计算机时按照二进制存放数值,也就是2的8次方,也就是256)
3.2 色彩深度和色阶
色彩深度 | 灰阶 |
---|---|
色彩深度(Depth of Color),色彩深度又叫色彩位数。视频画面中红、绿、蓝三个颜色通道中每种颜色为N位,总的色彩位数则为3N,色彩深度也就是视频设备所能辨析的色彩范围。目前有18bit、24bit、30bit、36bit、42bit和48bit位等多种。24位色被称为真彩色,R、G、B各8bit,常说的8bit,色彩总数为1670万,如手机参数,多少万色素就这个概念 | 通常来说,液晶屏幕上人们肉眼所见的一个点,即一个像素,它是由红、绿、蓝(RGB)三原色组成的。每一个基色,其背后的光源都可以显现出不同的亮度级别。而灰阶代表了由最暗到最亮之间不同亮度的层次级别。把三基色每一个颜色从纯色(如纯红)不断变暗到黑的过程中的变化级别划分成为色彩的灰阶,并用数字表示,就是最常见的色彩存储原理。这中间层级越多,所能够呈现的画面效果也就越细腻。以8bit 为例,我们就称之为256灰阶 |
3.3 彩色图像数字化
彩色像数字化原理同灰度图像数字化,只不过彩色图像为三通道图像且可以拆分成三张同等像素的灰度图,由下图可知,每三个BGR就组成了一张图片的一列
数字图像处理的实质就是通过对数字图像中像素数据的判断,依据处理或识别要求,最后逐个像素修改像素的灰度值
二、 基本操作
学习目标:
- 掌握图像的读取和保存方法
- 能够使用OpenCV在图像上绘制几何图像
- 能够访问图像的像素
- 能够获取图像的属性,并进行通道的分离和合并
- 能够实现颜色空间的变换
1、 图像IO操作
1.1 读取图像
语法:cv2.imread(path, mode)
参数:
path
:要读取的图像mode
:读取方式的标志-
cv2.IMREAD_COLOR\1
:以彩色模式加载图像,任何图像的透明度都将忽略,这个默认参数 -
cv2.IMREAD_GRAYSCALE\0
:以灰度模式加载图像 -
cv2.IMREAD_UNCHANGED\-1
:包括alpha通道的加载图像模式注意:
- 可以使用数字代替这些标志,数字在源码中可以查看
-
实例:
# !/usr/bin/python3
# -*- coding: UTF-8 -*-
__author__ = "A.L.Kun"
__file__ = "demo01.py"
__time__ = "2022/7/15 19:30"
import cv2.cv2 as cv2
img = cv2.imread("./img/1.jpg", 0) # 以灰度模式读取图像
cv2.imshow("image", img)
cv2.waitKey(0)
如果图像读取错误,其不会报错,而是会使图像为空值
1.2 显示图像
语法:cv2.imshow(winname, mat)
参数:
winname
:显示图像窗口名称,以字符串类型显示mat
:要加载的图像
要注意:在调用显示图像API后,要调用
cv2.waitKey()
给绘制图像留下时间,否则窗口会出现无响应的情况,并且图像无法显示出来
另外,我们也可以使用matplotlib
对图像进行展示
# !/usr/bin/python3
# -*- coding: UTF-8 -*-
__author__ = "A.L.Kun"
__file__ = "demo01.py"
__time__ = "2022/7/15 19:30"
import cv2.cv2 as cv2
from matplotlib import pyplot as plt
img = cv2.imread("./img/1.jpg")
cv2.imshow("image", img)
cv2.waitKey(0) # 0代表等待足够的时间
cv2.destroyAllWindows() # 摧毁窗口
# 使用matplotlib显示图片
plt.imshow(img[:, :, ::-1]) # 将rgb转换为bgr,数组逆置
# 灰度图的读取模式:plt.imshow(img, cmap=plt.cm.gray)
plt.show()
1.3 保存图像
语法:cv2.imwrite(fielname, img)
参数:
filename
:文件名,路径img
:要保存的图像
代码:
# !/usr/bin/python3
# -*- coding: UTF-8 -*-
__author__ = "A.L.Kun"
__file__ = "demo01.py"
__time__ = "2022/7/15 19:30"
import cv2.cv2 as cv2
import numpy as np
img = cv2.imread("./img/1.jpg")
assert isinstance(img, np.ndarray) # 声明图像数据为numpy的数组
cv2.imwrite("test.jpg", img)
2、 绘制几何图形
2.1 绘制直线
语法:cv2.line(img, start, end, color, thickness)
参数:
img
:要绘制直线的图像Start, End
:起始点、终点color
:直线的颜色thickness
:线条的宽度,为-1时生成闭合图案,并填充颜色
2.2 绘制圆形
语法:cv2.circle(img, centerpoint, r, color, thickness)
参数:
centerpiont
:圆形的坐标r
:圆的半径- 其它参数和绘制直线的参数意义相同
2.3 绘制矩形
语法:cv2.rectangle(img, leftupper, rightdown, color, thickness)
参数:
leftupper
:矩形左上角坐标rightdown
:矩形右下角坐标
2.4 添加文字
语法:cv2.putText(img, text, station, font, fontsize, color, thickness, cv.Line_AA)
参数:
station
:文本放置位置text
:要写入的文本数据font
:字体fontsize
:字体大小
2.5 效果展示
我们生成一个全黑的图像,然后再里面绘制图像并添加文字
# !/usr/bin/python3
# -*- coding: UTF-8 -*-
__author__ = "A.L.Kun"
__file__ = "demo02.py"
__time__ = "2022/7/15 21:36"
import cv2.cv2 as cv2
import numpy as np
import matplotlib.pyplot as plt
# 创建一个空白的图像 1920x1080
img = np.zeros([1080, 1920, 3], np.uint8) # 并且设置数据类型为uint8
# 绘制图形
cv2.line(img, (0, 0), (502, 502), (255, 255, 255), 4)
cv2.rectangle(img, (502, 502), (900, 900), (255, 0, 0), 4)
cv2.circle(img, (800, 700), 100, (0, 255, 0), 4)
# 写入文字
cv2.putText(img, "hello world", (10, 500), cv2.FONT_HERSHEY_COMPLEX_SMALL, 4, (255, 255, 0), 4) # 使用cv2内置的字体
plt.imshow(img[:, :, ::-1]) # 逆置图像
plt.title("test")
plt.show()
3、 操作图片
3.1 修改像素点
我们可以通过行和列的坐标值获取像素值,对于RGB图像,它返回一个rgb的数组,对于灰度图像,仅返回相应的强度值,使用相同的方法对像素值进行修改
# !/usr/bin/python3
# -*- coding: UTF-8 -*-
__author__ = "A.L.Kun"
__file__ = "demo02.py"
__time__ = "2022/7/15 21:36"
import cv2.cv2 as cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread("./img/1.jpg")
# 声明img的类型
assert isinstance(img, np.ndarray)
# 获取对应点的像素强度值
print(img[100, 200])
# 修改某个点的像素值
img[100, 100] = [255, 255, 255]
plt.imshow(img[:, :, ::-1])
plt.show()
3.2 获取图像属性
图像属性包括行数、列数和通道,图像数据类型,像素值等
属性 | API |
---|---|
形状 | img.shape |
图像大小 | img.size |
数据类型 | img.dtype |
3.3 拆分合并
有时需要在B、G、R通道图像上单独工作。在这种情况下,需要将BGR图像分割为单个通道,或者在其他情况下,可能需要将这些单独的通道合并到BGR图像,你可以通过以下方式完成:
# 通道分离
b, g, r = cv2.split(img)
# 通道合并
img = cv2.merge(b, g, r)
实例:
# !/usr/bin/python3
# -*- coding: UTF-8 -*-
__author__ = "A.L.Kun"
__file__ = "demo02.py"
__time__ = "2022/7/15 21:36"
import cv2.cv2 as cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread("./img/1.jpg")
assert isinstance(img, np.ndarray)
plt.imshow(img[:, :, ::-1]) # 进行色道的逆置,转换为bgr
b, g, r = cv2.split(img) # 分离
plt.imshow(b, cmap=plt.cm.gray)
plt.show()
img2 = cv2.merge((b, g, r)) # 返回rgb图像
plt.imshow(img2[:, :, ::-1])
plt.show()
3.4 色道改变
OpenCV中有150多种颜色空间转换方法,最广泛的转换方法有两种,BGR->Gray
和BGR->HSV
语法:cv2.cvtColor(input_image, flag)
参数:
input_image
:进行颜色空间转换的图像flag
:转换类型cv2.COLOR_BGR2GRAY
:BGR->GRAY
cv2.COLOR_BGR2HSV
:BGR->HSV
4、 算术操作
学习目标:
- 了解图像的加法,混合操作
4.1 图像加法
你可以使用OpenCV的cv2.add()
函数把两幅图像相加,或者可以简单通过numpy
操作添加两个图像,如:res = img1 + img2
,两个图像应该具有相同大小和类型,或者第二个图像可以是标量值
注意:OpenCV加法和Numpy加法之间存在差异,OpenCV的加法的饱和操作,而Numpy添加时模运算操作
# !/usr/bin/python3
# -*- coding: UTF-8 -*-
__author__ = "A.L.Kun"
__file__ = "logic.py"
__time__ = "2022/7/16 10:52"
import cv2.cv2 as cv2
import numpy as np
import matplotlib.pyplot as plt
x = np.uint8([250])
y = np.uint8([10]) # unsigned int-8
print(cv2.add(x, y)) # 250 + 10 = 260 -> 255
print(x + y) # 250 + 10 = 260 % 256 = 4
# 实例
# 导入图像
img1 = cv2.imread("./img/1.jpg")
assert isinstance(img1, np.ndarray)
img2 = cv2.imread("./img/2.jpg")
assert isinstance(img2, np.ndarray)
# 对图像进行相加
img3 = cv2.add(img1, img2)
plt.imshow(img3[:, :, ::-1])
plt.show()
img4 = img1 + img2
plt.imshow(img4[:, :, ::-1])
plt.show()
推荐使用OpenCV里面的加法
cv2.add()
和减法cv2.subtract()
4.2 图像混合
图像混合其实也是加法,但是不同的是两幅图像的权重不同,这就会给人一种混合或者透明的感觉,图像混合的计算公式如下:
g ( x ) = ( 1 − α ) ⋅ f 0 ( x ) + α ⋅ f ( x ) g(x)=(1-\alpha) \cdot f_0(x) + \alpha \cdot f(x) g(x)=(1−α)⋅f0(x)+α⋅f(x)
通过修改阿尔法的值,可以实现非常酷的操作
现在我们把两幅图混合在一起,第一幅图的权重是0.7,第二幅图的权重是0.3,函数cv2.addWeight(img1, alpha, img2, beta, gamma)
可以按下面公式对图片进行混合操作
d s t = α ⋅ i m g 1 + β ⋅ i m g 2 + γ dst = \alpha \cdot img_1 + \beta \cdot img_2 + \gamma dst=α⋅img1+β⋅img2+γ
# !/usr/bin/python3
# -*- coding: UTF-8 -*-
__author__ = "A.L.Kun"
__file__ = "logic.py"
__time__ = "2022/7/16 10:52"
import cv2.cv2 as cv2
import numpy as np
import matplotlib.pyplot as plt
img1 = cv2.imread("./img/1.jpg")
assert isinstance(img1, np.ndarray)
img2 = cv2.imread("./img/2.jpg")
assert isinstance(img2, np.ndarray)
img3 = cv2.addWeighted(img1, 0.7, img2, 0.3, 0) # 根据权重混合
plt.imshow(img3[:, :, ::-1])
plt.show()
4.3 图像位运算
OpenCV的逻辑运算——与、或、非、异或
OpenCV中的非:0 反过来是 255
# !/usr/bin/python3
# -*- coding: UTF-8 -*-
__author__ = "A.L.Kun"
__file__ = "demo9.py"
__time__ = "2022/7/18 18:09"
import cv2.cv2 as cv2
import numpy as np
# 读取图像
img = cv2.imread("./img/1.jpg") # 读取黑白效果
assert isinstance(img, np.ndarray)
img_ = np.zeros(img.shape, np.uint8)
# 非操作
img_not = cv2.bitwise_not(img)
# 或操作
img_or = cv2.bitwise_or(img, img_)
# 与操作
img_and = cv2.bitwise_and(img, img_)
# 展示图片
cv2.namedWindow("not", cv2.WINDOW_NORMAL)
cv2.resizeWindow("not", 640, 480)
cv2.imshow("not", np.hstack((img[:640, :480], img_not[:640, :480])))
cv2.namedWindow("and", cv2.WINDOW_NORMAL)
cv2.resizeWindow("and", 640, 480)
cv2.imshow("and", np.hstack((img[:640, :480], img_and[:640, :480])))
cv2.namedWindow("or", cv2.WINDOW_NORMAL)
cv2.resizeWindow("or", 640, 480)
cv2.imshow("or", np.hstack((img[:640, :480], img_or[:640, :480])))
cv2.waitKey(0)
cv2.destroyAllWindows()
三、 滤波器
1、 卷积
1.1 什么是图片卷积
图像卷积就是卷积核在图像上按行滑动遍历像素时不断在相乘求和的过程
基本概念
-
步长
步长就是卷积核在图像上移动的步幅,卷积核可以每次移动一个像素步长或者两个像素步长等
步长一般为1
-
padding
从上面图片中,我们可以看出,卷积之后图片的长宽会变小,如果要保持图片大小不变。我们需要在原始图片周围填充0。padding指的就是填充0的圈数。
1.2 padding
我们如何判断需要补0的圈数呢?
我们可以通过公式计算出需要填充的0的圈数:
-
输入体积大小: H 1 ⋅ W 1 ⋅ D 1 H_1 \cdot W_1 \cdot D_1 H1⋅W1⋅D1
-
四个超参数:
- Filter数量K
- Filter大小F
- 步长S
- 零填充大小P
-
输出体积大小: H 2 ⋅ W 2 ⋅ D 2 H_2 \cdot W_2 \cdot D_2 H2⋅W2⋅D2
H 2 = ( H 1 − F + 2 P ) / S + 1 W 2 = ( W 1 − F + 2 P ) / S + 1 D 2 = K \begin{matrix} H_2 = (H_1 - F + 2P) / S + 1\\ W_2 = (W_1 - F + 2P) / S + 1 \\ D_2 = K \end{matrix} H2=(H1−F+2P)/S+1W2=(W1−F+2P)/S+1D2=K