○ 图像基础知识
■ 数字图像
● 概念与起源
● 常见的成像方式:伽马射线成像、X射线成像、红外线成像、可见光成像等
■ 图像的属性
● 格式、尺寸、分辨率、通道、图像直方图、色彩空间
○ 图像处理
■ 绘图&添加文字
■ 图像几何变换
■ 图像滤波与增强
● 线性滤波、非线性滤波
● 图像锐化
● 直方图均衡化
● gamma变化
■ 形态学变
● 腐蚀、膨胀
● 开运算(腐蚀后膨胀)、闭运算(膨胀后腐蚀)
● 形态学梯度
● 顶帽、黑帽
○ 图像分割
■ 阈值分割
■ 边缘检测
■ 连通域分析
■ 图像轮廓
■ 区域生长
■ 分水岭算法
○ 图像特征与目标检测
■ 图像特征的理解
■ 形状特征、纹理特征
■ 模板匹配
■ 人脸检测&行人检测
○ 运动目标识别
■ 帧差法
■ 光流法
■ 背景减除法
一、图像基础知识
1.1 数字图像
1.1.1概念与起源
数字图像又被称为数码图像或数位图像,可以理解为用数字对图像进行编码,将其转化为计算机能理解、传输、表示、操作的格式。1921年最早被用在报社。
1.1.2 常见的成像方式
1.2 图像的属性
import cv2
data = cv2.imread("../test.png", 0)
# imread函数的参数1是待读取图像的(相对或绝对)路径;
# imread函数的参数2是读取方式,0表示读取为灰度图,1表示按原图读取但是忽略alpha通道,-1表示按原图读取保留alpha
print(data.shape) # 返回图像的:高、宽、通道数
cv2.imshow("ori-data", data)
# imshow函数的参数1是图像显示窗口名称;参数2是需要显示图像的变量名称
cv2.waitKey(0) #waitKey函数控制着imshow的持续时间(单位为ms),当该函数传入参数0时表示无限制显示
cv2.destroyAllWindows() # 用于释放显示占用的相关内存。若不调用该函数,程序运行也能成功,只不过需要等程序结束后再释放相关内存。
注意:OpenCV的函数常用小驼峰命名法。即首个单词的首字母小写,此后的每个单词的首字母都为大写。
1.2.1 图像格式
- BMP:Windows下的标准位图格式,未经过压缩,占用内存较大。(如工业相机成像)
- JPEG:具有较大压缩比(2:1~40:1),使用广泛。
- GIF:可静可动、支持透明背景;内存占用小,但是色域不广,只支持256种颜色。(如表情包)
- PNG:与JPEG类似,压缩比高于GIF,支持透明图层(通过alpha通道跳接图像的透明度)。
TIFF:图像格式复杂,存储信息多,在mac中广泛使用(利用原稿的复制)。(如卫星地图数据标注)
1.2.2 图像尺寸
图像尺寸的长宽都是以像素为单位。像素可以理解为一个点,也可以理解为一个小区域的颜色值。
像素取值在[0,255]之间 。其中灰度图中0表示黑色、255表示白色;彩色图像用红绿蓝三通道的二维矩阵来表示,0表示相应的基色,255表示相应的基色在改像素中取得最大值。
注意:分辨率:单位长度中所表达或截取的像素数目。
- 每英寸图像内的像素点数,单位是像素每英寸(PPI:Pixels Per Inch)。图像分辨率越高,像素点密度越高,图像越清晰。
- 通道数:图像的位深,指描述图像中每个pixel数值所占的二进制位数。
- 位深度越大则图像能表示的颜色就越多,色彩越丰富。
- 8位:单通道-灰度图,灰度值范围为2^8=256
- 24位:三通道3*8=24
- 32位:三通道加透明alpha通道,alpha通道中0是全透明,255是不透明
- 练习1:利用cvtColor函数进行图像的通道降维或升维
- 通道降维(彩色图转灰度图)公式:Gray = B0.299 + G0.587 + R*0.114
- 通道升维(灰度图转彩色图)公式:B = G = R = Gray = 0; A = 0 ```python import cv2 data = cv2.imread(“../test.png”) print(data.shape) # (768, 1024, 3) cv2.imshow(“ori-data”, data) # 彩色图像 cv2.waitKey(0)
data_gray = cv2.cvtColor(data, cv2.COLOR_BGR2GRAY) print(data_gray.shape) # (768, 1024) cv2.imshow(“gray-data”, data_gray) # 灰度图 cv2.waitKey(0)
data_bgr = cv2.cvtColor(data_gray, cv2.COLOR_GRAY2BGR) print(data_bgr.shape) # (768, 1024, 3) cv2.imshow(“bgr-data”, data_bgr) # 彩色图像,但是效果与转化前的灰度图一样。 cv2.waitKey(0) cv2.destroyAllWindows()
效果图: ![image.png](https://cdn.nlark.com/yuque/0/2022/png/12845815/1652013318096-4661bcbc-9960-4a76-9af9-e4d3899b6658.png#clientId=uac43b5ea-c574-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=85&id=u2c828e54&margin=%5Bobject%20Object%5D&name=image.png&originHeight=1214&originWidth=1563&originalType=binary&ratio=1&rotation=0&showTitle=false&size=71978&status=done&style=none&taskId=u56092f16-04e4-4333-b181-9af6eb12894&title=&width=109)![image.png](https://cdn.nlark.com/yuque/0/2022/png/12845815/1652013328680-43392b4f-a091-4c7b-8977-4d2f85d4a9b6.png#clientId=uac43b5ea-c574-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=88&id=u8533868d&margin=%5Bobject%20Object%5D&name=image.png&originHeight=1214&originWidth=1563&originalType=binary&ratio=1&rotation=0&showTitle=false&size=74472&status=done&style=none&taskId=u2ce73219-e257-412c-9f56-8930bcbfa98&title=&width=113)![image.png](https://cdn.nlark.com/yuque/0/2022/png/12845815/1652013338702-bcb8b3de-a71a-4ddc-8bb0-5f3a40294f45.png#clientId=uac43b5ea-c574-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=85&id=u473814f5&margin=%5Bobject%20Object%5D&name=image.png&originHeight=1214&originWidth=1563&originalType=binary&ratio=1&rotation=0&showTitle=false&size=68097&status=done&style=none&taskId=udc541374-d365-4ae4-9dee-02810016168&title=&width=110)
- 练习2:进行图像的通道顺序转化(即RGB与BGR之间的转化)
- 目的:解决OpenCV与其他包(如matplotlib)读取的通道方式不一样
- 解决方式:OpenCV自带**cvtColor函数**、或者numpy
```python
import cv2
import matplotlib.pyplot as plt
data = cv2.imread("../test.png")
cv2.imshow("ori-data", data)
cv2.waitKey(0)
data_cv = cv2.cvtColor(data, cv2.COLOR_BGR2RGB)
data_gray = cv2.cvtColor(data, cv2.COLOR_BGR2GRAY) # 转为灰度图,但是在plt中是非灰度的
data_np = data[:, :, ::-1] # numpy自带的数据通道转换
cv2.imshow("rgb-data", data_cv)
cv2.waitKey(0)
plt.subplot(2,2,1)
plt.imshow(data)
plt.subplot(2,2,2)
plt.imshow(data_cv)
plt.subplot(2,2,3)
plt.imshow(data_np)
plt.subplot(2,2,4)
plt.imshow(data_gray) # 单通道灰度图再plt中显示为有颜色(黄紫)的图像
plt.show()
cv2.destroyAllWindows()
- 效果图:
- Note:练习2中用matplotlib进行多图像展示,这里简单说一下它的使用语法。
- plt.subplot(1,2,1)表示新建一个1行2列的画布,本次的图像在第一个位置上显示。
- 再结合plt.show进行显示;
- 如果需要保存图像的话需要用到plt.savefig(保存的路径 +图像名称),保存操作需要在show之前做完。
- 练习3:图像通道的合并与分离
- 目的:如果想针对图像中某类特定颜色的对象进行处理,就可以先通道将不同的颜色分离出来;也可以是对图像添加彩色滤镜(针对某一图层*比例系数)。
- 解决方式:OpenCV自带split函数与merge函数 ```python import cv2 data = cv2.imread(“../task1.jpg”) b,g,r = cv2.split(data) cv2.imshow(“b”, b) # 蓝色通道 cv2.imshow(“g”, g) # 绿色通道 cv2.imshow(“r”, r) # 红色通道 cv2.waitKey(0)
data_merge = cv2.merge([b, g, r*0]) # 将红色通道置为0之后的效果 cv2.imshow(“merge-data”, data_merge) cv2.waitKey(0) cv2.destroyAllWindows()
效果图:![image.png](https://cdn.nlark.com/yuque/0/2022/png/12845815/1652015787966-40f466a3-06d0-4907-9f0b-8a74fb3d2974.png#clientId=uac43b5ea-c574-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=145&id=u529c4ff5&margin=%5Bobject%20Object%5D&name=image.png&originHeight=361&originWidth=273&originalType=binary&ratio=1&rotation=0&showTitle=false&size=70348&status=done&style=none&taskId=u0dcfd828-fd3d-4b35-b62d-2f23e16760f&title=&width=110)![image.png](https://cdn.nlark.com/yuque/0/2022/png/12845815/1652015634309-bc0f3df0-2fe7-4931-ab6b-ecd2b5e7424d.png#clientId=uac43b5ea-c574-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=145&id=u46977b5d&margin=%5Bobject%20Object%5D&name=image.png&originHeight=570&originWidth=392&originalType=binary&ratio=1&rotation=0&showTitle=false&size=84717&status=done&style=none&taskId=u2e59c622-f11b-4a1c-a0f0-1281fae3412&title=&width=100)![image.png](https://cdn.nlark.com/yuque/0/2022/png/12845815/1652015642888-f693e9ba-8eab-48ca-bab1-0c43edca5bc2.png#clientId=uac43b5ea-c574-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=145&id=ua8af21a0&margin=%5Bobject%20Object%5D&name=image.png&originHeight=570&originWidth=392&originalType=binary&ratio=1&rotation=0&showTitle=false&size=92754&status=done&style=none&taskId=ubae90235-4354-4689-98bb-c3c176ce1b8&title=&width=100)![image.png](https://cdn.nlark.com/yuque/0/2022/png/12845815/1652015744390-7b7daee6-c320-4c61-9c6f-1998c0b7425f.png#clientId=uac43b5ea-c574-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=145&id=ud3b7852f&margin=%5Bobject%20Object%5D&name=image.png&originHeight=554&originWidth=382&originalType=binary&ratio=1&rotation=0&showTitle=false&size=78245&status=done&style=none&taskId=u8f033b1e-a572-4eac-a846-50bbcd4c79f&title=&width=100)![image.png](https://cdn.nlark.com/yuque/0/2022/png/12845815/1652015758217-2add2d55-dd28-43a2-a040-31db6b1790a5.png#clientId=uac43b5ea-c574-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=145&id=ue79dcad8&margin=%5Bobject%20Object%5D&name=image.png&originHeight=550&originWidth=376&originalType=binary&ratio=1&rotation=0&showTitle=false&size=112914&status=done&style=none&taskId=u4fd23c21-7d0d-436e-a22f-df7f59aa7d0&title=&width=99)
<a name="cMAiN"></a>
### 1.2.4 图像直方图
- **直方图**:统计图像中每个像素强度出现的次数或频率。可用于图像的二值分割或者均衡化。
- 灰度图的直方图实现:
- **cv2.calcHist函数**介绍:参数1是需要计算直方图的图像(支持彩色图像和灰度图),但是需要在图像外面加一个list升维;参数2是通道索引;参数3是函数传入的mask,无mask需要传入none;参数4表示直方图的份数(bins);参数5表示需要统计的像素值范围。
```python
import cv2
import matplotlib.pyplot as plt
data = cv2.imread("../task1.png")
data_gray = cv2.cvtColor(data, cv2.COLOR_BGR2GRAY)
plt.imshow(data_gray, cmap=plt.cm.gray)
hist = cv2.calcHist([data_gray], [0], None, [256], [0,256])
# 对data_gray图像的第0通道计算【0,256】像素值的直方图,并将结果分为256份进行显示。计算过程中未使用mask
plt.figure()
plt.title("grayscale histogram")
plt.xlabel("bins")
plt.ylabel("the number of pixels")
plt.plot(hist)
plt.xlim([-1, 256])
plt.show()
效果图:
彩色图像的直方图实现:需要将彩色图下个传入cv2.calcHist函数中,再修改传入的通道数索引即可
1.2.5 色彩空间
色彩空间分为:RGB空间、HSV空间、HSI空间、CMYK空间
- ① 在RGB空间中,我们会使用一个三维向量表示一个像素的颜色。(最常用)
- 该空间可以用一个正方体表示:正方体的六个顶点分别为——黑白、红绿蓝、黄(红+绿)、青(蓝+绿)、紫(红+蓝)。其中黑白顶点的这条对角线被称为灰度线,上面所有分量的值是一样的。
- ② HSV:根据色调、饱和度和明度表示图像。
- 该空间可以用一个倒放的圆锥体表示。其中:
- h(hue)表示色调、色彩。其中0度表示红色、120度表示绿色、240度表示蓝色;
- s(saturation)表示饱和度,取值范围为0~100%,值越大,颜色越饱和。可以理解为圆的半径;
- v(value)明暗,数值越高,越明亮。0(暗)~100%(明)。可以理解为圆锥的高。
- 该空间可以用一个倒放的圆锥体表示。其中:
- ① 在RGB空间中,我们会使用一个三维向量表示一个像素的颜色。(最常用)
import cv2
import matplotlib.pyplot as plt
data = cv2.imread("../test.png")
hsv = cv2.cvtColor(data, cv2.COLOR_BGR2HSV)
cv2.imshow("hsv", hsv)
cv2.waitKey(0)
cv2.destroyAllWindws()
- 效果图(左边是原图,右边是转换后的效果图)![image.png](https://cdn.nlark.com/yuque/0/2022/png/12845815/1652015787966-40f466a3-06d0-4907-9f0b-8a74fb3d2974.png#clientId=uac43b5ea-c574-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=116&id=ixJSB&margin=%5Bobject%20Object%5D&name=image.png&originHeight=361&originWidth=273&originalType=binary&ratio=1&rotation=0&showTitle=false&size=70348&status=done&style=none&taskId=u0dcfd828-fd3d-4b35-b62d-2f23e16760f&title=&width=88)![image.png](https://cdn.nlark.com/yuque/0/2022/png/12845815/1652941181305-d7239389-390c-48d6-aac4-59ca7eb708c0.png#clientId=u7cac5b4a-1e66-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=117&id=ud718c504&margin=%5Bobject%20Object%5D&name=image.png&originHeight=570&originWidth=384&originalType=binary&ratio=1&rotation=0&showTitle=false&size=157577&status=done&style=none&taskId=u44bdf5c6-af76-4e4d-ba22-979e3627134&title=&width=79)
- ③ HSI:反应人类视觉系统感知彩色的方式,以色调、饱和度和强度来感知颜色。
- 该空间可以用纺锤体表示。
- [HSI与HSV之间的区别](https://zhidao.baidu.com/question/155499261.html)为:HSV颜色模型中,色调H用角度度量取值范围为0°~360°,饱和度S取值范围为0%~100%,明度V取值范围为0%(黑)到100%(白)。HSI颜色模型双六棱锥表示中,色调H的角度范围为[0,2π],饱和度S是颜色空间任一点距I轴的距离。
- HSI的优点:
- 可仅对分量i进行处理,结果不改变原图像中的色彩种类;
- 与人感知颜色的结果一一对应
- ④ CMYK:主要应用于印刷工业、通过青(c)、品(m)、黄(y)三原色油墨的不同网点面积率的叠印来表现丰富的颜色和阶调
二、图像处理
2.1 绘图&添加文字(6种)
- 直线:
cv2.line
(图像、起点(x,y)、终点(x,y)、线段颜色、线宽(线宽或者进行填充-1)、直线类型(默认为8型,还有一种AA型可选)) - 矩形:
cv2.rectangle
(图像、左上角坐标(x,y)、右下角坐标(x,y)、线段颜色、线宽(线宽或者进行填充-1)、线段类型) - 圆:
cv2.circle
(图像、圆心(x,y)、半径、线段颜色、线宽(线宽或者进行填充-1)、线段类型) - 椭圆:
cv2.ellipse
(图像、椭圆圆心(x,y)、长短轴(长, 短)、旋转角angle、椭圆的起始角度、椭圆的结束角度、线段颜色、线宽(线宽或者进行填充-1)、线段类型)- 角度解析:当椭圆的长轴与x轴平行时,认为其旋转角为0;当其长轴与y轴平行时,认为其旋转角为90;角度会从x轴开始顺时针旋转。
- 多边形:
cv2.polylines
(图像、点对(x,y)、isClosed(线段是否闭合)、线段颜色、线宽(线宽或者进行填充-1)、线段类型)- isClosed解析:True为将点对的首尾相连,返回一个闭合的形状;False为不需要将首尾相连,可能会返回一个非闭合的折现线段(是否闭合取决于给定线段的收尾坐标是否相等)。
- 添加文字:
cv2.putText
(图像、str文字、文字起点(左下角)、字体、文字大小(缩放比例)、字体颜色、线宽、线段类型)- 文字大小(缩放比例),即该字体可能会有一个基础的大小。并不是指字体的像素宽度
```python
import cv2
import numpy as np
data = cv2.imread(“../test.png”)
cv2.line(data, (0,0), (200, 200), (0,255,255), 5)
cv2.rectangle(data, (0,0), (200, 200), (255, 255, 0), 5)
cv2.ellipse(data, (100, 100), (100, 50), 0, 50, 180, (255, 0, 0), -1)
多边形
pts = np.array([[10,5], [50, 20], [70,30],[20,50],[15, 70]]) cv2.polylines(data, [pts], True, (0,0,255))写字
font = cv2.FONT_HERSHEY_SIMPLEX cv2.putText(data, “test”, (0, 300), font, 4, (255,255,255), cv2.LINE_AA)
- 文字大小(缩放比例),即该字体可能会有一个基础的大小。并不是指字体的像素宽度
```python
import cv2
import numpy as np
data = cv2.imread(“../test.png”)
cv2.line(data, (0,0), (200, 200), (0,255,255), 5)
cv2.rectangle(data, (0,0), (200, 200), (255, 255, 0), 5)
cv2.ellipse(data, (100, 100), (100, 50), 0, 50, 180, (255, 0, 0), -1)
cv2.imshow(“plot”, data) cv2.waitKey(0) cv2.destroyAllWindows()
效果:![image.png](https://cdn.nlark.com/yuque/0/2022/png/12845815/1652946117143-003ffcb3-5893-4fcf-98d5-b3ac0e32b495.png#clientId=u7cac5b4a-1e66-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=166&id=u4044f3ec&margin=%5Bobject%20Object%5D&name=image.png&originHeight=570&originWidth=392&originalType=binary&ratio=1&rotation=0&showTitle=false&size=139670&status=done&style=none&taskId=ueae15af3-1787-43bd-a724-3d6d9a44399&title=&width=114.33334350585938)
<a name="aiwVX"></a>
## 2.2 图像几何变换
常见的图像图像几何变换有:缩放、平移、旋转、仿射变换、透视变换。[参考链接1](https://zoucz.com/blog/2019/02/26/67267d60-39cf-11e9-9e7f-cf581750e42a/);[参考链接2](https://blog.csdn.net/mzpmzk/article/details/64919093)
<a name="vjeCP"></a>
### 2.2.1 缩放(scaling)
- 缩放的相关定义:
- 下采样(subsampled,或降采样downsampled):缩小图像 ;
- 上采样(upsampled):放大图像,以得到更高分辨率的图像。
- 上下采样是用更多或者更少的点去表示一个区域(一个物体)。它是在同样视野中的图像上进行的。
- 相关函数:`cv2.resize(src,dsize=None,fx,fy,interpolation)`
- 参数分别表示:src原图、dsize目标图像大小(与比例因子二选一)、沿x轴的比例因子、y轴的比例因子、interpolation差值方式
- **差值方式介绍**:
1. 最近邻差值。不需要计算,直接将距离最近的相邻元素的像素值赋给待求像素。
- **公式:**目标矩阵上的像素取值 = 目标矩阵上像素值的位置 * (当前矩阵到目标矩阵的缩放比)
![image.png](https://cdn.nlark.com/yuque/0/2022/png/12845815/1652947427929-c8c33597-1a6d-4354-94a2-bd0646a52f57.png#clientId=u7cac5b4a-1e66-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=126&id=u60b43179&margin=%5Bobject%20Object%5D&name=image.png&originHeight=229&originWidth=534&originalType=url&ratio=1&rotation=0&showTitle=false&size=56547&status=done&style=none&taskId=u8fef3d54-931e-4a4c-91a9-69f35ef6350&title=&width=293)
- **示例**:将3个像素点的 矩阵差值为4个像素点的矩阵。
- 因此在新矩阵上第0个元素的位置为为0,用第0个像素表示;
- 新矩阵上第一个元素的位置为0.75,用旧矩阵上第一个像素表示;
- 新矩阵上第二个元素为1.5,用用旧矩阵上第二个元素表示;
- 第三个元素为2.25,还是用旧矩阵上的第二个元素表示
![image.png](https://cdn.nlark.com/yuque/0/2022/png/12845815/1652947427890-59f85c9e-37b8-4f48-a12a-f0f3ce15b9be.png#clientId=u7cac5b4a-1e66-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=249&id=ub0e50726&margin=%5Bobject%20Object%5D&name=image.png&originHeight=530&originWidth=546&originalType=url&ratio=1&rotation=0&showTitle=false&size=78430&status=done&style=none&taskId=u83622390-c72b-4d03-b8d1-c52e4a20bd5&title=&width=257)
2. 双线性差值。可以理解为在两个方向(水平和垂直)上进行线性差值,将目标点附近的四个像素点的值按比例赋值目标像素。
- 公式:目标矩阵上的元素取值,是先在水平方向上进行两次一阶线性差值,再对差值的结果做一次垂直方向上的差值。
![image.png](https://cdn.nlark.com/yuque/0/2022/png/12845815/1652947919581-d82ce168-e39d-4be6-ba9b-d96f807016f4.png#clientId=u7cac5b4a-1e66-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=250&id=u55437494&margin=%5Bobject%20Object%5D&name=image.png&originHeight=453&originWidth=686&originalType=url&ratio=1&rotation=0&showTitle=false&size=121110&status=done&style=none&taskId=u3195ec2b-e875-4706-a429-4c533d875b2&title=&width=379)
- 示例:R1和Q21之间的比重*Q11) + (R1和Q11之间的比重*Q21)得到R1的像素值,同理可求得R2的像素值。<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/12845815/1652948269455-0bde2e84-e76c-4af8-a55e-a9a499ab6691.png#clientId=u7cac5b4a-1e66-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=137&id=uc525e73a&margin=%5Bobject%20Object%5D&name=image.png&originHeight=451&originWidth=490&originalType=url&ratio=1&rotation=0&showTitle=false&size=83655&status=done&style=none&taskId=ua4e1a585-30d7-4727-85fc-a310795ebc2&title=&width=149)
```python
import cv2
data = cv2.imread("../test.png")
res1 = cv2.resize(data, None, fx=2, fy=2, interpolation=cv2.INTER_LINEAR)
# 注意,利用fx和fy做图像的缩放时,需要令dsize=None。
h, w = data.shape[:2]
res2 = cv2.resize(data, (int(w*0.8), int(h*0.8)), interpolation=cv2.INTER_AREA)
# 注意,在使用dsize做图像缩放时,需要传入tuple类型的目标图像大小。其中tuple的元素必须是int类型
print(data.shape, res1.shape, res2.shape)
# (339, 243, 3) (678, 486, 3) (271, 194, 3)
2.2.2 平移(shifting)
平移可以理解为分别在x、y轴方向上移动指定长度的偏移量。设(x0, y0)、(x1, y1)分别是平移前/后的坐标点,那么有x1 = x0+△x、y1 = y0+△y。
- 相关函数:
cv2.warpAffine(src, M, dsize, flags,borderMode, borderValue)
- 参数分别表示:src原图、M变换矩阵、dsize目标图像大小、flags差值方法的组合、borderMode边界像素模式(默认为BORDER_CONSTANT,即用指定常量进行填充)、borderValue 边界填充值;(默认情况下为0)。
- M作为仿射变换矩阵,一般反映平移或旋转的关系,为InputArray类型的2×3的变换矩阵。
- flages表示插值方式,默认为flags=cv2.INTER_LINEAR,表示线性插值,此外还有:
- cv2.INTER_NEAREST(最近邻插值)
- cv2.INTER_AREA (区域插值)
- cv2.INTER_CUBIC(三次样条插值)
- cv2.INTER_LANCZOS4(Lanczos插值)
- borderMode可选如下:可以看到除了指定常量的方式之外,其他方法都是利用图像本身的像素点进行边界填充。
```python import cv2 import numpy as np data = cv2.imread(“../task1.png”)手动构造一个平移矩阵,其中x轴移动100个像素,y轴移动25个像素。图像边默认用0填充
M = np.float32([[1,0,100], [0,1,25]]) h,w = data.shape[:2]
- 参数分别表示:src原图、M变换矩阵、dsize目标图像大小、flags差值方法的组合、borderMode边界像素模式(默认为BORDER_CONSTANT,即用指定常量进行填充)、borderValue 边界填充值;(默认情况下为0)。
res1 = cv2.warpAffine(data, M, (w, h)) #平移后的图像大小和 原图相同 res2 = cv2.warpAffine(data, M, (w + 100, h + 25)) # 平移后,将图像shape分别增加各方向平移的量,使结果中的原图不被裁剪。 cv2.imshow(“ori”, data) cv2.imshow(“new”, res1) cv2.imshow(“new2”, res2) cv2.waitKey(0) cv2.destroyAllWindows()
实现效果:![image.png](https://cdn.nlark.com/yuque/0/2022/png/12845815/1652951659629-0072d81f-1dda-48aa-bf9b-898bf54267f2.png#clientId=u7cac5b4a-1e66-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=146&id=ufa819f34&margin=%5Bobject%20Object%5D&name=image.png&originHeight=589&originWidth=1259&originalType=binary&ratio=1&rotation=0&showTitle=false&size=373834&status=done&style=none&taskId=u9610a008-8b5b-4701-af0a-c6dc114e961&title=&width=312)
<a name="GTjXC"></a>
### 2.2.3 旋转(rotation)
**定义**:以固定点(一般是图像中心)为中心,将图像上所有像素点都统一旋转一定角度。
- 注意:
- ① 图像旋转之后,中间会出现很多空洞点。一般是利用**差值法**对这些点进行处理,避免它们影响画面效果。
- ② 旋转后,在图像宽高之外的区域会被裁剪掉,边缘以外(图像宽高内部)的区域可以用指定颜色填充。
- 公式(在极坐标上进行旋转变换):
![image.png](https://cdn.nlark.com/yuque/0/2022/png/12845815/1652956706625-57c9da00-630e-4fe0-a8dc-1a0d526690e4.png#clientId=udd236a7f-1da8-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=57&id=ufbff0048&margin=%5Bobject%20Object%5D&name=image.png&originHeight=94&originWidth=551&originalType=url&ratio=1&rotation=0&showTitle=false&size=28475&status=done&style=none&taskId=u828838c0-ab9b-4f5f-bc52-ff769a6b15e&title=&width=332)![image.png](https://cdn.nlark.com/yuque/0/2022/png/12845815/1652956706682-d90bd0e3-1903-4a85-903b-f31197428532.png#clientId=udd236a7f-1da8-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=46&id=u2be68eb0&margin=%5Bobject%20Object%5D&name=image.png&originHeight=102&originWidth=767&originalType=url&ratio=1&rotation=0&showTitle=false&size=51466&status=done&style=none&taskId=u92f7621e-7bd6-47f8-8a69-26ba8ffd8fc&title=&width=343)
- 函数:利用` cv2.getRotationMatrix2D`(图片的旋转中心, 旋转角度, 缩放比例(正为逆时针,负为顺时针))得到一个变换矩阵,再通过仿射变化`warpAffine`函数做图像进行变换操作。
```python
import cv2
import numpy as np
data = cv2.imread("../task1.png")
h,w = data.shape[:2]
M = cv2.getRotationMatrix2D((float(w/2), float(h/2)), 45, -1)
# 图像旋转中心点支持float类型的数据,坐标也是(X,Y)。
dst = cv2.warpAffine(data, M, (h, w)) # 旋转的目标图像尺寸也是指定宽高,而非高宽(与图像属性shape的顺序不一样)
cv2.imshow("ori", data)
cv2.imshow("new", dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
2.2.4 翻转(flip)
翻转(也被称为镜像),是指图像围绕翻转轴进行空间180°运动 。翻转后的图像看起来与原图关于对称轴对称。
- 翻转与旋转的差异:
- 翻转操作不需要做额外的差值和裁剪,得到的结果图像和原图大小一致。但是物体之前的相对位置可能会发生变化(如左右互换)
- 旋转过程中需要做差值和padding操作,得到的结果图像大小需要指定。图形的整体都发生了角度变化 ,图像上各元素之间的相对位置未发生改变。
- 函数:
cv2.flip(filename, flipcode)
。flipcode的取值分别有:0 垂直翻转, 1 水平翻转,-1水平垂直翻转。 ```python import cv2 import numpy as np data = cv2.imread(“../task1.png”) h,w = data.shape[:2]
dst = cv2.flip(data, 1) # 沿x=w轴进行的镜面翻转 dst2 = cv2.flip(data, 0) # 沿y=h轴进行的镜面翻转 dst3 = cv2.flip(data, -1) cv2.imshow(“ori”, data) cv2.imshow(“new”, dst) cv2.imshow(“new2”, dst2) cv2.imshow(“new3”, dst3) cv2.waitKey(0) cv2.destroyAllWindows()
利用np进行翻转。
效果图:![image.png](https://cdn.nlark.com/yuque/0/2022/png/12845815/1652961604375-40adc635-0fba-4a76-8ad3-932b94897ee2.png#clientId=udd236a7f-1da8-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=194&id=u4ecf0024&margin=%5Bobject%20Object%5D&name=image.png&originHeight=1129&originWidth=762&originalType=binary&ratio=1&rotation=0&showTitle=false&size=358744&status=done&style=none&taskId=u077afc34-f3ab-4a89-a6ea-77ed54ee9b3&title=&width=131)
<a name="Fw9mI"></a>
### 2.2.5 仿射变换()
[仿射变换](https://baike.baidu.com/item/%E4%BB%BF%E5%B0%84%E5%8F%98%E6%8D%A2/4289056?fr=aladdin):又称仿射映射,是指在几何中,一个向量空间进行**一次线性变换**并**接上一个平移**,变换为另一个向量空间。变换前后
- 注意:线性变化前后的图像上线性性保持不变;直线的比例保持不变
- 作用:对图像进行平移、旋转、缩放(等比例缩放)、翻转、斜切等操作。
![image.png](https://cdn.nlark.com/yuque/0/2022/png/12845815/1652958688705-4cedf23a-d0b2-430f-9874-2683c7a608cf.png#clientId=udd236a7f-1da8-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=210&id=u0160b276&margin=%5Bobject%20Object%5D&name=image.png&originHeight=525&originWidth=744&originalType=binary&ratio=1&rotation=0&showTitle=false&size=298581&status=done&style=none&taskId=u6bb9cc50-f75e-4d45-b2e1-69560dc6d84&title=&width=298)
- 函数:`M = cv2.getAffineTransform(pos1,pos2)`。pos1,pos2分别代表变换前后的3个点的位置(x,y)。通过指定的点实现拉伸和平移、旋转等操作。
```python
import cv2
import numpy as np
data = cv2.imread("../task1.png")
h,w = data.shape[:2]
# 在二维图像上,两个点确定一条直线,三个点确定一个平面
p1 = np.float32([[50,50], [200,50], [50,200]])
p2 = np.float32([[10,100], [200,50], [100,250]])
M = cv2.getAffineTransform(p1, p2)
dst = cv2.warpAffine(data, M, (w, h))
cv2.imshow("ori", data)
cv2.imshow("new", dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
2.2.6 透视变换
透视变换的物理意义:用一个光源照射到你需要处理的图像上,将其投影到另一个平面上的样子。(如皮影戏)
- 和仿射变换的相同点在于:同样存在平移、缩放、拉伸(拉伸通过斜切实现)等。
- 和仿射变换的区别在于:透视变化是将一个图像投影到另一个平面上的操作;而前面的平移、旋转、仿射变换等都是在一个图像上的操作。
- 函数:
M = cv2.getPerspectiveTransform(pos1, pos2)
。pos1、pos2表示透视变换前、后的4个点对应位置cv2.warpPerspective(src,M,(cols,rows))
。src表示原始图像、M表示透视变换矩阵、(rows,cols)表示变换后的图像大小,rows表示行数,cols表示列数 ```python import cv2 import numpy as np data = cv2.imread(“../task1.png”) h,w = data.shape[:2]
p1 = np.float32([[114,82], [288,150], [8,100],[143,182]]) p2 = np.float32([[0,0], [100,0], [0,250], [188,160]]) M = cv2.getPerspectiveTransform(p1, p2) dst = cv2.warpPerspective(data, M, (w, h)) cv2.imshow(“ori”, data) cv2.imshow(“new”, dst) cv2.waitKey(0) cv2.destroyAllWindows() ``` 效果:
2.2.7 图像几何变换应用
图像的几何变换应用 比较广泛,如
- 图像矫正:用于对人脸图像进行矫正,OCR前处理(文档的矫正)等。
- 数据增广:用于深度学习中增加数据规模及数据多样性。
待补充知识点:
- 图像差值方式(除最近邻插值、双线性差值之外)