1. 图像基础知识
  2. 数字图像
  3. 概念与起源
  4. 常见的成像方式:伽马射线成像、X射线成像、红外线成像、可见光成像等
  5. 图像的属性
  6. 格式、尺寸、分辨率、通道、图像直方图、色彩空间
  7. 图像处理
  8. 绘图&添加文字
  9. 图像几何变换
  10. 图像滤波与增强
  11. 线性滤波、非线性滤波
  12. 图像锐化
  13. 直方图均衡化
  14. gamma变化
  15. 形态学变
  16. 腐蚀、膨胀
  17. 开运算(腐蚀后膨胀)、闭运算(膨胀后腐蚀)
  18. 形态学梯度
  19. 顶帽、黑帽
  20. 图像分割
  21. 阈值分割
  22. 边缘检测
  23. 连通域分析
  24. 图像轮廓
  25. 区域生长
  26. 分水岭算法
  27. 图像特征与目标检测
  28. 图像特征的理解
  29. 形状特征、纹理特征
  30. 模板匹配
  31. 人脸检测&行人检测
  32. 运动目标识别
  33. 帧差法
  34. 光流法
  35. 背景减除法

一、图像基础知识

1.1 数字图像

1.1.1概念与起源

数字图像又被称为数码图像或数位图像,可以理解为用数字对图像进行编码,将其转化为计算机能理解、传输、表示、操作的格式。1921年最早被用在报社。

1.1.2 常见的成像方式

image.png

1.2 图像的属性

  1. import cv2
  2. data = cv2.imread("../test.png", 0)
  3. # imread函数的参数1是待读取图像的(相对或绝对)路径;
  4. # imread函数的参数2是读取方式,0表示读取为灰度图,1表示按原图读取但是忽略alpha通道,-1表示按原图读取保留alpha
  5. print(data.shape) # 返回图像的:高、宽、通道数
  6. cv2.imshow("ori-data", data)
  7. # imshow函数的参数1是图像显示窗口名称;参数2是需要显示图像的变量名称
  8. cv2.waitKey(0) #waitKey函数控制着imshow的持续时间(单位为ms),当该函数传入参数0时表示无限制显示
  9. cv2.destroyAllWindows() # 用于释放显示占用的相关内存。若不调用该函数,程序运行也能成功,只不过需要等程序结束后再释放相关内存。

image.png
注意: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表示相应的基色在改像素中取得最大值。
    注意:

    • uint8:无符号的整型,范围是2^8=256(0~256),因此一般用于表示像素取值。
    • int8:有符号整型,范围是2^8=256(-127,127)。

      1.2.3 分辨率和通道

  • 分辨率:单位长度中所表达或截取的像素数目。

    • 每英寸图像内的像素点数,单位是像素每英寸(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()

  1. 效果图: ![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. - 练习2:进行图像的通道顺序转化(即RGBBGR之间的转化)
  3. - 目的:解决OpenCV与其他包(如matplotlib)读取的通道方式不一样
  4. - 解决方式:OpenCV自带**cvtColor函数**、或者numpy
  5. ```python
  6. import cv2
  7. import matplotlib.pyplot as plt
  8. data = cv2.imread("../test.png")
  9. cv2.imshow("ori-data", data)
  10. cv2.waitKey(0)
  11. data_cv = cv2.cvtColor(data, cv2.COLOR_BGR2RGB)
  12. data_gray = cv2.cvtColor(data, cv2.COLOR_BGR2GRAY) # 转为灰度图,但是在plt中是非灰度的
  13. data_np = data[:, :, ::-1] # numpy自带的数据通道转换
  14. cv2.imshow("rgb-data", data_cv)
  15. cv2.waitKey(0)
  16. plt.subplot(2,2,1)
  17. plt.imshow(data)
  18. plt.subplot(2,2,2)
  19. plt.imshow(data_cv)
  20. plt.subplot(2,2,3)
  21. plt.imshow(data_np)
  22. plt.subplot(2,2,4)
  23. plt.imshow(data_gray) # 单通道灰度图再plt中显示为有颜色(黄紫)的图像
  24. plt.show()
  25. cv2.destroyAllWindows()
  • 效果图:image.pngimage.pngimage.png
  • 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()

  1. 效果图:![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)
  2. <a name="cMAiN"></a>
  3. ### 1.2.4 图像直方图
  4. - **直方图**:统计图像中每个像素强度出现的次数或频率。可用于图像的二值分割或者均衡化。
  5. - 灰度图的直方图实现:
  6. - **cv2.calcHist函数**介绍:参数1是需要计算直方图的图像(支持彩色图像和灰度图),但是需要在图像外面加一个list升维;参数2是通道索引;参数3是函数传入的mask,无mask需要传入none;参数4表示直方图的份数(bins);参数5表示需要统计的像素值范围。
  7. ```python
  8. import cv2
  9. import matplotlib.pyplot as plt
  10. data = cv2.imread("../task1.png")
  11. data_gray = cv2.cvtColor(data, cv2.COLOR_BGR2GRAY)
  12. plt.imshow(data_gray, cmap=plt.cm.gray)
  13. hist = cv2.calcHist([data_gray], [0], None, [256], [0,256])
  14. # 对data_gray图像的第0通道计算【0,256】像素值的直方图,并将结果分为256份进行显示。计算过程中未使用mask
  15. plt.figure()
  16. plt.title("grayscale histogram")
  17. plt.xlabel("bins")
  18. plt.ylabel("the number of pixels")
  19. plt.plot(hist)
  20. plt.xlim([-1, 256])
  21. plt.show()

效果图:image.pngimage.png

  • 彩色图像的直方图实现:需要将彩色图下个传入cv2.calcHist函数中,再修改传入的通道数索引即可

    1.2.5 色彩空间

  • 色彩空间分为:RGB空间、HSV空间、HSI空间、CMYK空间

    • ① 在RGB空间中,我们会使用一个三维向量表示一个像素的颜色。(最常用)
      • 该空间可以用一个正方体表示:正方体的六个顶点分别为——黑白、红绿蓝、黄(红+绿)、青(蓝+绿)、紫(红+蓝)。其中黑白顶点的这条对角线被称为灰度线,上面所有分量的值是一样的。
      • image.png
    • ② HSV:根据色调、饱和度和明度表示图像。
      • 该空间可以用一个倒放的圆锥体表示。其中:
        • h(hue)表示色调、色彩。其中0度表示红色、120度表示绿色、240度表示蓝色;
        • s(saturation)表示饱和度,取值范围为0~100%,值越大,颜色越饱和。可以理解为圆的半径;
        • v(value)明暗,数值越高,越明亮。0(暗)~100%(明)。可以理解为圆锥的高。

image.png

  1. import cv2
  2. import matplotlib.pyplot as plt
  3. data = cv2.imread("../test.png")
  4. hsv = cv2.cvtColor(data, cv2.COLOR_BGR2HSV)
  5. cv2.imshow("hsv", hsv)
  6. cv2.waitKey(0)
  7. cv2.destroyAllWindws()
  1. - 效果图(左边是原图,右边是转换后的效果图)![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:反应人类视觉系统感知彩色的方式,以色调、饱和度和强度来感知颜色。
    • 该空间可以用纺锤体表示。

image.png

  1. - [HSIHSV之间的区别](https://zhidao.baidu.com/question/155499261.html)为:HSV颜色模型中,色调H用角度度量取值范围为0°~360°,饱和度S取值范围为0%~100%,明度V取值范围为0%(黑)到100%(白)。HSI颜色模型双六棱锥表示中,色调H的角度范围为[0,2π],饱和度S是颜色空间任一点距I轴的距离。
  2. - HSI的优点:
  3. - 可仅对分量i进行处理,结果不改变原图像中的色彩种类;
  4. - 与人感知颜色的结果一一对应
  • ④ CMYK:主要应用于印刷工业、通过青(c)、品(m)、黄(y)三原色油墨的不同网点面积率的叠印来表现丰富的颜色和阶调
    image.png

二、图像处理

2.1 绘图&添加文字(6种)

  1. 直线cv2.line(图像、起点(x,y)、终点(x,y)、线段颜色、线宽(线宽或者进行填充-1)、直线类型(默认为8型,还有一种AA型可选))
  2. 矩形cv2.rectangle(图像、左上角坐标(x,y)、右下角坐标(x,y)、线段颜色、线宽(线宽或者进行填充-1)、线段类型)
  3. cv2.circle(图像、圆心(x,y)、半径、线段颜色、线宽(线宽或者进行填充-1)、线段类型)
  4. 椭圆cv2.ellipse(图像、椭圆圆心(x,y)、长短轴(长, 短)、旋转角angle、椭圆的起始角度、椭圆的结束角度、线段颜色、线宽(线宽或者进行填充-1)、线段类型)
    • 角度解析:当椭圆的长轴与x轴平行时,认为其旋转角为0;当其长轴与y轴平行时,认为其旋转角为90;角度会从x轴开始顺时针旋转。
  5. 多边形cv2.polylines(图像、点对(x,y)、isClosed(线段是否闭合)、线段颜色、线宽(线宽或者进行填充-1)、线段类型)
    • isClosed解析:True为将点对的首尾相连,返回一个闭合的形状;False为不需要将首尾相连,可能会返回一个非闭合的折现线段(是否闭合取决于给定线段的收尾坐标是否相等)。
  6. 添加文字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)

cv2.imshow(“plot”, data) cv2.waitKey(0) cv2.destroyAllWindows()

  1. 效果:![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)
  2. <a name="aiwVX"></a>
  3. ## 2.2 图像几何变换
  4. 常见的图像图像几何变换有:缩放、平移、旋转、仿射变换、透视变换。[参考链接1](https://zoucz.com/blog/2019/02/26/67267d60-39cf-11e9-9e7f-cf581750e42a/);[参考链接2](https://blog.csdn.net/mzpmzk/article/details/64919093)
  5. <a name="vjeCP"></a>
  6. ### 2.2.1 缩放(scaling)
  7. - 缩放的相关定义:
  8. - 下采样(subsampled,或降采样downsampled):缩小图像
  9. - 上采样(upsampled):放大图像,以得到更高分辨率的图像。
  10. - 上下采样是用更多或者更少的点去表示一个区域(一个物体)。它是在同样视野中的图像上进行的。
  11. - 相关函数:`cv2.resize(src,dsize=None,fx,fy,interpolation)`
  12. - 参数分别表示:src原图、dsize目标图像大小(与比例因子二选一)、沿x轴的比例因子、y轴的比例因子、interpolation差值方式
  13. - **差值方式介绍**:
  14. 1. 最近邻差值。不需要计算,直接将距离最近的相邻元素的像素值赋给待求像素。
  15. - **公式:**目标矩阵上的像素取值 = 目标矩阵上像素值的位置 * (当前矩阵到目标矩阵的缩放比)
  16. ![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)
  17. - **示例**:将3个像素点的 矩阵差值为4个像素点的矩阵。
  18. - 因此在新矩阵上第0个元素的位置为为0,用第0个像素表示;
  19. - 新矩阵上第一个元素的位置为0.75,用旧矩阵上第一个像素表示;
  20. - 新矩阵上第二个元素为1.5,用用旧矩阵上第二个元素表示;
  21. - 第三个元素为2.25,还是用旧矩阵上的第二个元素表示
  22. ![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)
  23. 2. 双线性差值。可以理解为在两个方向(水平和垂直)上进行线性差值,将目标点附近的四个像素点的值按比例赋值目标像素。
  24. - 公式:目标矩阵上的元素取值,是先在水平方向上进行两次一阶线性差值,再对差值的结果做一次垂直方向上的差值。
  25. ![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)
  26. - 示例:R1Q21之间的比重*Q11 + R1Q11之间的比重*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)
  27. ```python
  28. import cv2
  29. data = cv2.imread("../test.png")
  30. res1 = cv2.resize(data, None, fx=2, fy=2, interpolation=cv2.INTER_LINEAR)
  31. # 注意,利用fx和fy做图像的缩放时,需要令dsize=None。
  32. h, w = data.shape[:2]
  33. res2 = cv2.resize(data, (int(w*0.8), int(h*0.8)), interpolation=cv2.INTER_AREA)
  34. # 注意,在使用dsize做图像缩放时,需要传入tuple类型的目标图像大小。其中tuple的元素必须是int类型
  35. print(data.shape, res1.shape, res2.shape)
  36. # (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可选如下:可以看到除了指定常量的方式之外,其他方法都是利用图像本身的像素点进行边界填充。
        image.png ```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]

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()

  1. 实现效果:![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)
  2. <a name="GTjXC"></a>
  3. ### 2.2.3 旋转(rotation)
  4. **定义**:以固定点(一般是图像中心)为中心,将图像上所有像素点都统一旋转一定角度。
  5. - 注意:
  6. - 图像旋转之后,中间会出现很多空洞点。一般是利用**差值法**对这些点进行处理,避免它们影响画面效果。
  7. - 旋转后,在图像宽高之外的区域会被裁剪掉,边缘以外(图像宽高内部)的区域可以用指定颜色填充。
  8. - 公式(在极坐标上进行旋转变换):
  9. ![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)
  10. - 函数:利用` cv2.getRotationMatrix2D`(图片的旋转中心, 旋转角度, 缩放比例(正为逆时针,负为顺时针))得到一个变换矩阵,再通过仿射变化`warpAffine`函数做图像进行变换操作。
  11. ```python
  12. import cv2
  13. import numpy as np
  14. data = cv2.imread("../task1.png")
  15. h,w = data.shape[:2]
  16. M = cv2.getRotationMatrix2D((float(w/2), float(h/2)), 45, -1)
  17. # 图像旋转中心点支持float类型的数据,坐标也是(X,Y)。
  18. dst = cv2.warpAffine(data, M, (h, w)) # 旋转的目标图像尺寸也是指定宽高,而非高宽(与图像属性shape的顺序不一样)
  19. cv2.imshow("ori", data)
  20. cv2.imshow("new", dst)
  21. cv2.waitKey(0)
  22. cv2.destroyAllWindows()

效果:image.png

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进行翻转。

  1. 效果图:![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)
  2. <a name="Fw9mI"></a>
  3. ### 2.2.5 仿射变换()
  4. [仿射变换](https://baike.baidu.com/item/%E4%BB%BF%E5%B0%84%E5%8F%98%E6%8D%A2/4289056?fr=aladdin):又称仿射映射,是指在几何中,一个向量空间进行**一次线性变换**并**接上一个平移**,变换为另一个向量空间。变换前后
  5. - 注意:线性变化前后的图像上线性性保持不变;直线的比例保持不变
  6. - 作用:对图像进行平移、旋转、缩放(等比例缩放)、翻转、斜切等操作。
  7. ![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)
  8. - 函数:`M = cv2.getAffineTransform(pos1,pos2)`pos1,pos2分别代表变换前后的3个点的位置(x,y)。通过指定的点实现拉伸和平移、旋转等操作。
  9. ```python
  10. import cv2
  11. import numpy as np
  12. data = cv2.imread("../task1.png")
  13. h,w = data.shape[:2]
  14. # 在二维图像上,两个点确定一条直线,三个点确定一个平面
  15. p1 = np.float32([[50,50], [200,50], [50,200]])
  16. p2 = np.float32([[10,100], [200,50], [100,250]])
  17. M = cv2.getAffineTransform(p1, p2)
  18. dst = cv2.warpAffine(data, M, (w, h))
  19. cv2.imshow("ori", data)
  20. cv2.imshow("new", dst)
  21. cv2.waitKey(0)
  22. cv2.destroyAllWindows()

效果:image.png
应用:用于人脸位姿的矫正

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() ``` 效果:image.png

2.2.7 图像几何变换应用

图像的几何变换应用 比较广泛,如

  • 图像矫正:用于对人脸图像进行矫正,OCR前处理(文档的矫正)等。
  • 数据增广:用于深度学习中增加数据规模及数据多样性。

待补充知识点:

  • 图像差值方式(除最近邻插值、双线性差值之外)