文档中涉及到的opencv版本为:opencv-python 4.5.1.48

  • 安装命令为 pip install opencv-python==4.5.1.48
  • 我没有装opencv-contrib-python

安装之后我们再安装matplotlib与numpy,这两个是配合opencv使用的库,我们会使用其中的几个功能,之后我们导入这三个库

python 图片 moviepy 移动 python图像移动_像素点

%matplotlib inline 是在jupyter notebook 中独有的用法,在下面课程中我不做使用,下面所介绍的每一个方法都是导入了这三个库之后再输入相应代码的结果

我们在查看cv2库中的函数时会经常看到两种参数

  • src source 源图像
  • dst destination 目标图像

目录

1  读取图像 imread()

1.1  图像array的读取方式

1.1.1  读取1*1像素的图片

1.1.2  读取2*1像素的图像

1.1.3  读取2*2像素的图像

2  opencv使用窗口显示图像 imshow()

3  查看图像 shape

4  将图片转化为灰度图

5  图像保存 imwrite()

6  显示像素点个数 size

7  显示数据类型 dtype

8  截取部分图像 img[h,w]

9  颜色通道提取 split()与merge()

9.1  R(只保留红色)

9.2  G(只保留绿色通道)

9.3  B(只保留蓝色通道)

10  边界扩充 copyMakeBorder()

11  数值计算

11.1  加号运算

11.2  add运算 add()

12  图像融合 addWeighted()

13  图像拉伸 resize()

14  阈值处理 threshold(sec,thresh,maxval,type)

15  图像平滑

15.1  均值滤波 blur()

15.2  方框滤波 boxFilter()

15.2.1  做归一化

15.2.2  不做归一化

15.3  高斯滤波 GaussianBlur()

15.4  中值滤波 medianBlur()

16  腐蚀操作 erode()

16.1  第一个例子

16.2  第二个例子

17  膨胀操作 dilate()

18  开运算与闭运算

18.1  开运算 morphologyEx(cv2.MORPH_OPEN)

18.2  闭运算 morphologyEx(cv2.MORPH_CLOSE)

19  梯度运算 morphologyEx(cv2.MORPH_GRADIENT)

20  礼帽与黑帽

20.1  礼帽 morphologyEx(cv2.MORPH_TOPHAT)

20.2  黑帽 morphologyEx(cv2.MORPH_BLACKHAT)

21  图像复制 copy()

22  图像翻转 flip()

22.1  上下翻

22.2  左右翻

22.3  上下翻加左右翻

23  图像逆时针旋转90度 transpose()

24  图像任意角度旋转 getRotationMatrix2D()与warpAffine()

25  图像画矩形框 rectangle()

26  图像写文字 putText()

26.1 写英文

26.2 写汉字

27  图像与运算 bitwise_and()

28  图像或运算 bitwise_or()

29  图像非运算 bitwise_not()

30  图像异或运算 bitwise_xor()

31  图像画圈 circle()

32  图像绘制有颜色填充的多边形 fillConvexPoly()与fillPoly()

32.1  fillConvexPoly()

32.2  fillPoly()

33  图像上绘制一条线 line()

34  颜色通道转换 cvtColor()

34.1  BGR转灰度图

34.2  BGR转RGB

34.3  RGB转BGR

35  拼接多张图像

35.1  横向拼接 hconcat()

35.2  纵向拼接 vconcat()


1  读取图像 imread()

首先我要在路径下有这样一个图片文件,我的图像文件位test.png

python 图片 moviepy 移动 python图像移动_卷积核_02

读取图像,然后打印出来看一下

python 图片 moviepy 移动 python图像移动_python_03

python 图片 moviepy 移动 python图像移动_归一化_04

  • 注:当dtype=uint8时(默认的dtype为uint8),所有像素点取值范围为0-255

我们此时查看一下变量类型

python 图片 moviepy 移动 python图像移动_像素点_05

img的变量类型为numpy.ndarray

python 图片 moviepy 移动 python图像移动_归一化_06

  • 注:opencv默认读取图片格式为BGR

1.1  图像array的读取方式

opencv中的array是这样读的,现在我们把原图搞为1*1像素的照片,这个改变图像大小的方法到后面会提到

1.1.1  读取1*1像素的图片

python 图片 moviepy 移动 python图像移动_opencv_07

python 图片 moviepy 移动 python图像移动_像素点_08

三个中括号内的值分别为1*1像素的R,G,B三个值

1.1.2  读取2*1像素的图像

我们现在再将图像变为2*1

python 图片 moviepy 移动 python图像移动_opencv_09

这一次显示的结果就在两个中括号中,但他们还是同一行,也就是说第一行第一个的RGB值是[232,230,230],第二个RGB值是[231,229,229],由于是同一行,所以没进入第二个中括号

python 图片 moviepy 移动 python图像移动_归一化_10

1.1.3  读取2*2像素的图像

现在我们改成2*2像素的图片

python 图片 moviepy 移动 python图像移动_python_11

python 图片 moviepy 移动 python图像移动_python_12

我们可以从中得出一个结论

我们最内的中括号是我们单一像素点的BGR的三个值,第二个中括号是一行内的所有像素点值,第三个中括号是我们的整个图

python 图片 moviepy 移动 python图像移动_python_13

2  opencv使用窗口显示图像 imshow()

python 图片 moviepy 移动 python图像移动_opencv_14

其中第三行的waitKey后的参数0为无限等待用户按键,按下任意键终止,如改为1000,则该窗口显示1000ms后

运行结果

python 图片 moviepy 移动 python图像移动_像素点_15

我们可以定义下面这个彩色显示图像函数,name为窗口名称,img为图片路径

def cv_show(name,img):
    img = cv2.imread(img)
    cv2.imshow(name,img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

使用方法

cv_show('img','test.png')

3  查看图像 shape

python 图片 moviepy 移动 python图像移动_像素点_16

python 图片 moviepy 移动 python图像移动_归一化_17

元组中的三个值含义分别为图像高为456像素,宽为823像素,图像有BGR三通道

我之前遇到一个问题,由于shape的位置不对,所以最终无法显示出来

python 图片 moviepy 移动 python图像移动_opencv_18

下面这张图的第一行是无法显示的shape,我使用了numpy中的traspose的方法,把新shape中的第0位的值置为老shape中第1位的值,新第1位的值置为老第二位的值,新第2位的值置为老第0位的值

python 图片 moviepy 移动 python图像移动_卷积核_19

这样就能改变shape以达到我们的要求

4  将图片转化为灰度图

python 图片 moviepy 移动 python图像移动_像素点_20

python 图片 moviepy 移动 python图像移动_python_21

箭头处的参数可以换为

  • cv2.IMREAD_COLOR 彩色图像
  • cv2.IMREAD_GRAYSCALE 灰度图像

python 图片 moviepy 移动 python图像移动_像素点_22

查看图像的shape可以看出图像大小不变,通道转化为单通道

python 图片 moviepy 移动 python图像移动_归一化_23

python 图片 moviepy 移动 python图像移动_卷积核_24

5  图像保存 imwrite()

  • 注:opencv使用图像保存时,不能有中文路径

python 图片 moviepy 移动 python图像移动_像素点_25

python 图片 moviepy 移动 python图像移动_python_26

6  显示像素点个数 size

python 图片 moviepy 移动 python图像移动_像素点_27

这个其实就是shape元组中三个值的乘积,我们把shape拿出来看一下

python 图片 moviepy 移动 python图像移动_像素点_28

python 图片 moviepy 移动 python图像移动_卷积核_29

1125864 = 456 * 823 * 3

7  显示数据类型 dtype

python 图片 moviepy 移动 python图像移动_像素点_30

python 图片 moviepy 移动 python图像移动_opencv_31

8  截取部分图像 img[h,w]

我们截取图像高的0-300,宽的0-200部分

python 图片 moviepy 移动 python图像移动_卷积核_32

python 图片 moviepy 移动 python图像移动_opencv_33

9  颜色通道提取 split()与merge()

首先读取图片,然后把三个通道拆分出来,分别赋值给b,g,r三个变量

python 图片 moviepy 移动 python图像移动_像素点_34

我们分别看一下b,g,r以及他们的shape

python 图片 moviepy 移动 python图像移动_opencv_35

  • b

python 图片 moviepy 移动 python图像移动_归一化_36

  • g

python 图片 moviepy 移动 python图像移动_归一化_37

  • r

python 图片 moviepy 移动 python图像移动_归一化_38

  • 注:在这里可以看出bgr的矩阵是不一样的,但是如果通过cv.imshow()来看的话,展示bgr都是灰度图

我们可以使用merge把分离的bgr三个矩阵合到一起

python 图片 moviepy 移动 python图像移动_归一化_39

python 图片 moviepy 移动 python图像移动_卷积核_40

可以看出合成的图像具有三个通道

我们如果要单独显示BGR可以这样搞

我们让其余两个通道的所有值赋值为0

9.1  R(只保留红色)

我们将B通道与G通道所有值置为0

python 图片 moviepy 移动 python图像移动_像素点_41

python 图片 moviepy 移动 python图像移动_像素点_42

9.2  G(只保留绿色通道)

我们将B通道与R通道所有值置为0

python 图片 moviepy 移动 python图像移动_像素点_43

python 图片 moviepy 移动 python图像移动_opencv_44

9.3  B(只保留蓝色通道)

将G和R通道的值置为0

python 图片 moviepy 移动 python图像移动_归一化_45

python 图片 moviepy 移动 python图像移动_卷积核_46

我之前项目中遇到三通道颜色读取有问题的,最终使用的是拆分然后和一的方法解决的

python 图片 moviepy 移动 python图像移动_归一化_47

10  边界扩充 copyMakeBorder()

10.边界填充中介绍的方法为copyMakeBorder涉及到的int含义分别为上边距,下边距,左边距,右边距

python 图片 moviepy 移动 python图像移动_像素点_48

参数borderType有5个可选参数

  • BORDER_REPLICATE 复制法,复制指定边距的像素
  • 比如原图最右侧的三个像素为1,2,3,使用方法后(|后为扩充的像素) 1,2,3 | 3,3,3
  • BORDER_REFLECT 反射法
  • 比如原图最右侧的三个像素为1,2,3,使用方法后(|后为扩充的像素) 1,2,3 | 3,2,1
  • BORDER_REFLECT_101 101反射法,反射时不会复制自身
  • 比如原图最右侧的三个像素为1,2,3,使用方法后(|后为扩充的像素) 1,2,3 | 2,1
  • BORDER_WRAP 外包装法(整体复制法)
  • 比如原图最右侧的三个像素为1,2,3,使用方法后(|后为扩充的像素) 1,2,3 | 1,2,3
  • BORDER_CONSTANT 常量法,后接一个参数为灰度值
  • 比如原图最右侧的三个像素为1,2,3,使用方法后(|后为扩充的像素) 1,2,3 | 指定灰度值,指定灰度值,指定灰度值

读取图片之后使用不同的扩充方式

python 图片 moviepy 移动 python图像移动_像素点_49

将以上5个变量绘制出来

python 图片 moviepy 移动 python图像移动_归一化_50

python 图片 moviepy 移动 python图像移动_像素点_51

11  数值计算

11.1  加号运算

读一张图后打印原有的img和+50后的img

python 图片 moviepy 移动 python图像移动_像素点_52

  • 结果之间加一条横线能便于我们区分加之前与加之后的img

加之前

python 图片 moviepy 移动 python图像移动_像素点_53

加之后

python 图片 moviepy 移动 python图像移动_卷积核_54

图像做加法时,如果加入的值超过255,则该值减去256为结果数值

我们现在看一下+50后的img变成了什么样子

python 图片 moviepy 移动 python图像移动_像素点_55

python 图片 moviepy 移动 python图像移动_opencv_56

由于好多像素点已经超过了255,所以我们加和之后会变小,当一个值越小时会变得越黑,越大就会变得越白,0是完全的黑,255是完全的白

11.2  add运算 add()

我们现在换一种方式加和

python 图片 moviepy 移动 python图像移动_python_57

  • 加和前

python 图片 moviepy 移动 python图像移动_opencv_58

  • 加和后

python 图片 moviepy 移动 python图像移动_像素点_59

从第一行的值我们不太能看出来有什么区别,我们现在直接看一下这张图

python 图片 moviepy 移动 python图像移动_归一化_60

python 图片 moviepy 移动 python图像移动_opencv_61

很明显是与上面的结果有不同,这样我们得出一个结论,如果使用cv2.add则不会减去256,当有值超过255时,就将超出值置为255

12  图像融合 addWeighted()

读取两张图片

python 图片 moviepy 移动 python图像移动_python_62

test1

python 图片 moviepy 移动 python图像移动_像素点_63

test2

python 图片 moviepy 移动 python图像移动_像素点_64

首先我们将一张图片与另一张图片大小搞成一样的

这里我们先看一眼img的shape

python 图片 moviepy 移动 python图像移动_归一化_65

之后我们resize另一张,这里我们注意,resize的参数和shape的数值是相反的

python 图片 moviepy 移动 python图像移动_python_66

之后融合

python 图片 moviepy 移动 python图像移动_归一化_67

这里有一个公式,我直接以上面这个代码举例

img 0.4 + img1 0.6 + 0

img占0.4,img1占0.6,最后的0是一个常数

python 图片 moviepy 移动 python图像移动_python_68

13  图像拉伸 resize()

原图

python 图片 moviepy 移动 python图像移动_opencv_69

横向拉伸2倍,纵向不变

python 图片 moviepy 移动 python图像移动_opencv_70

python 图片 moviepy 移动 python图像移动_卷积核_71

从这里看好像纵向变短了,实际上我用截图软件量了一下,确实没变

只有在第二个参数为0的时候,后面输入fx,fy才有效

也可以直接使用resize调整大小

python 图片 moviepy 移动 python图像移动_归一化_72

  • 上面括号内的参数第一个200是宽,第二个200是高,与我们img.shape的顺序相反,img.shape[0]是高,img.shape[1]是宽

python 图片 moviepy 移动 python图像移动_像素点_73

如果我们当前机器的显示设置不为100%,我们截图时看到的大小会与resize的大小有区别

14  阈值处理 threshold(sec,thresh,maxval,type)

这个方法的参数如下

python 图片 moviepy 移动 python图像移动_卷积核_74

  • sec 输入图
  • thresh 阈值
  • maxval 当超出阈值(或小于阈值,根据type决定),所赋予的值
  • type 处理类型,可选值如下
  • cv2.THRESH_BINARY 超出阈值将值改为maxval,否则取0
  • cv2.THRESH_BINARY_INV 小于阈值将值改为maxval,否则取0
  • cv2.THRESH_TRUNC 大于阈值部分设为阈值,否则不变
  • cv2.THRESH_TOZERO 大于阈值部分不改变,否则改为0
  • cv2.THRESH_TOZERO_INV 小于阈值部分不改变,否则改为0

这个方法有两个返回值,第一个返回值为阈值,第二个返回值为阈值操作后的图像

我们把这五个type都用用一遍,然后展示出来

python 图片 moviepy 移动 python图像移动_opencv_75

python 图片 moviepy 移动 python图像移动_归一化_76

15  图像平滑

减轻图像中的噪点

15.1  均值滤波 blur()

python 图片 moviepy 移动 python图像移动_像素点_77

下面我们使用布尔滤波,然后把图片展示出来

python 图片 moviepy 移动 python图像移动_像素点_78

python 图片 moviepy 移动 python图像移动_卷积核_79

  • 由于我原有的图像没有什么噪点所以看起来差不多,如果改成有噪点的图像会显得平滑一些

第一个参数为要滤波的图片,第二个参数为执行滤波运算的矩阵范围(卷积核)

我们当前设置的范围为3*3

比如我们当前的像素点为1-9




1

2

3

4

5

6

7

8

9

通过3*3矩阵,我们将范围内的平均值代替所有值,运行后的结果是下面这样的

  • 我们要对每一个像素点进行计算,计算过程中把该点当作卷积核的中心点,运算出来的结果替代掉原值之后不影响下一个点计算的结果
  • 以下运算没考虑到边界填充问题,根据不同的边界填充方案,结果会略有不同




(1+2+4+5)/4=3

(1+2+3+4+5+6)/6=3.5

(2+3+5+6)/4=4

(1+2+4+5+7+8)/6=4.5

(1+2+3+4+5+6+7+8+9)/9=5

(2+3+5+6+8+9)/6=5.5

(4+5+7+8)/4=6

(4+5+6+7+8+9)/6=6.5

(5+6+8+9)/4=7

我们得出来的结果是这样的,如果交给计算机运算它会取浮点数的整形部分,有时进有时舍,与实际结果不会相差1的值




3

3.5

4

4.5

5

5.5

6

6.5

7

下面涉及到原理例子了,我们直接在jupyter notebook中运行,导入库后读取灰度图片

python 图片 moviepy 移动 python图像移动_python_80

转换之后我们取横向的三个像素点与纵向的三个像素点

python 图片 moviepy 移动 python图像移动_卷积核_81

我们拿到矩阵之后先自己计算一下结果



(84+84+80+79)/4=81.75

(84+84+83+80+79+79)/6=81.5

(84+83+79+79)/4=81.25

(84+84+80+79+76+76)/6=79.833

(84+84+83+80+79+79+76+76+76)/9=79.666

(84+83+79+79+76+76)/6=79.5

(80+79+76+76)/4=77.75

(80+79+79+76+76+76)/6=77.66

(79+79+76+76)=77.5

我们现在只显示计算出来的结果



81.75

81.5

81.25

79.833

79.666

79.5

77.75

77.66

77.5

现在我们使用布尔滤波看一下结果

python 图片 moviepy 移动 python图像移动_归一化_82

发现于我们运算的结果相差不过1

为了避免巧合我们计算本张图的另外一个5*5的矩阵

python 图片 moviepy 移动 python图像移动_归一化_83

python 图片 moviepy 移动 python图像移动_像素点_84

同样我们使用方法之前先自己计算一下



(77+76+79+78)/4=77.5

(77+76+76+79+78+78)/6=77.333

(76+76+78+78+78+81)/6=77.83

(76+78+78+78+81+81)/6=78.667

(78+78+81+81)/4=79.5

(77+78+79+78+83+82)/6=79.5

(77+76+76+79+78+78+83+82+81)/9=78.88

(76+76+78+78+78+81+82+81+83)/9=79.222

(76+78+78+78+81+81+81+83+83)/9=79.8889

(78+78+81+81+83+83)/6=80.667

(79+78+83+82+89+89)/6=83.333

(79+78+78+83+82+81+89+89+88)/9=83

(78+78+81+82+81+83+89+88+89)/9=83.2223

(78+81+81+81+83+83+88+89+89)/9=83.667

(81+81+83+83+89+89)/6=84.333

(83+82+89+89+92+92)/6=87.833

(83+82+81+89+89+88+92+92+91)/9=87.44

(82+81+83+89+88+89+92+91+91)/9=87.333

(81+83+83+88+89+89+91+91+91)/9=87.333

(83+83+89+89+91+91)/6=87.667

(89+89+92+92)/4=90.5

(89+89+88+92+92+91)/6=90.1667

(89+88+89+92+91+91)/6=90

(88+89+89+91+91+91)/6=89.8333

(89+89+91+91)/4=90

我们整理一下只保留结果



77.5

77.333

77.83

78.667

79.5

79.5

78.88

79.222

79.8889

80.667

83.333

83

83.2223

83.667

84.333

87.833

87.44

87.333

87.333

87.667

90.5

90.1667

90

89.8333

90

现在我们看一下布尔滤波后的结果

python 图片 moviepy 移动 python图像移动_像素点_85

如果卷积核为两个偶数则没有中心点,我也不知道是怎么计算的,使用偶数卷积核滤波的效果并不好,实际中也很少有人使用,我们下面几种滤波方式也都不考虑偶数卷积核的情况

15.2  方框滤波 boxFilter()

方框滤波于均值滤波的算法相同

有两个新增的参数,-1表示和原始图片的通道一致,normalize如果为True则执行归一化,如果为False则不执行

  • 在这里归一化指的就是将卷积核中的所有值加起来除数量,如果是不执行归一化就只加起来,不除数量

15.2.1  做归一化

python 图片 moviepy 移动 python图像移动_python_86

python 图片 moviepy 移动 python图像移动_像素点_87

之后我们已然使用灰度图分析做归一化的方框滤波是如何运算的

python 图片 moviepy 移动 python图像移动_像素点_88

我们可以发现做归一化的方框滤波与均值滤波的计算结果相同,我们在网上查阅一些资料,发现归一化方框滤波与均值滤波的计算方式相同

python 图片 moviepy 移动 python图像移动_像素点_89

15.2.2  不做归一化

python 图片 moviepy 移动 python图像移动_卷积核_90

python 图片 moviepy 移动 python图像移动_归一化_91

不做归一化后,将卷积核内的值加在一起会导致越界,越界后使用255替代卷积核内的值,所以上面这个图大部分为白色

我们可以通过改变卷积核大小让这个图能大概看出来是什么东西

python 图片 moviepy 移动 python图像移动_像素点_92

python 图片 moviepy 移动 python图像移动_归一化_93

接下来我们来探究不做归一化是如何搞的

python 图片 moviepy 移动 python图像移动_卷积核_94

我们结合上面的图(归一化与不归一化的核的区别)不难发现,最终的结果是这样得来的



84+84+80+79

84+84+83+80+79+79

84+83+79+79

84+84+80+79+76+76

84+84+83+80+79+76+76+76

84+83+79+79+76+76

80+79+76+76

80+79+79+76+76+76

79+79+76+76

我就不对结果进行运算了,结果全都大于255,当大于255时,不归一化的方框滤波将值置为255,像我们减小卷积核方框滤波的图片能看出来图的大概的原因时,减小卷积核后,部分像素点加和小于255,所以会产生颜色的区别

15.3  高斯滤波 GaussianBlur()

python 图片 moviepy 移动 python图像移动_python_95

python 图片 moviepy 移动 python图像移动_opencv_96

它的计算方式大概是这样的

python 图片 moviepy 移动 python图像移动_卷积核_97

它会根据高斯函数给卷积核内的每个值一个权重,卷积核内的中值就是1,距离中值越近的权重就越高,反之则越低,然后它把每个值和权重乘一下,然后加一下,然后把最终的值给该像素点

中间的204是高斯函数中间的峰值对应y值为1,y值就个每个像素的权重,比如说我有个点为24,它的权重对应就是x,我们再找一个比204更大的数235,它这个点对应的y值就是235的权重

python 图片 moviepy 移动 python图像移动_python_98

这个函数服从一维高斯分布,这个计算起来就比较麻烦了,我就不做计算了

python 图片 moviepy 移动 python图像移动_像素点_99

python 图片 moviepy 移动 python图像移动_像素点_100

最后我们再说一下必选的三个参数

  • img:要进行滤波的图像
  • (5,5):高斯滤波核的大小
  • 1:X方向上的高斯核标准差

15.4  中值滤波 medianBlur()

用中值代替卷积核中心的像素值

python 图片 moviepy 移动 python图像移动_像素点_101

python 图片 moviepy 移动 python图像移动_像素点_102

中智滤波顾名思义就是使用核内的中间值作为该像素点的值,由于有可能是偶数个值,所以核内中值有可能是浮点数,计算机运算出来的结果与实际运算结果相差不会过1

python 图片 moviepy 移动 python图像移动_opencv_103

我们不考虑边界问题,只对中心的79做出验证,上面九个值按顺序排列为

76 76 76 79 79 80 83 83 84

中值为79

我们现在把所有的图像展示一下

python 图片 moviepy 移动 python图像移动_python_104

python 图片 moviepy 移动 python图像移动_像素点_105

  • 这里介绍一个事儿,np.hstack()是把指定的图像横着拼在一起,np.vstack()是把指定的图像竖着拼在一起

python 图片 moviepy 移动 python图像移动_卷积核_106

python 图片 moviepy 移动 python图像移动_归一化_107

16  腐蚀操作 erode()

16.1  第一个例子

我们为了更好体验效果换一张图片

python 图片 moviepy 移动 python图像移动_像素点_108

是这样的一个图,一个数字2,在数字2周围有几根触须

然后我们进行腐蚀操作,首先定义一个5*5,核内数值全部为1的核,然后使用erode方法,使用kernel对img进行腐蚀,迭代一次

python 图片 moviepy 移动 python图像移动_卷积核_109

现在我们展示出来

python 图片 moviepy 移动 python图像移动_像素点_110

python 图片 moviepy 移动 python图像移动_opencv_111

上面这个图是迭代一次后的效果,旁边的须子明显细了很多,现在我们迭代5次看一下

python 图片 moviepy 移动 python图像移动_归一化_112

可以看到触须已经全部消失,并且我们还发现一个事儿,我们2的宽度也明显减小了

python 图片 moviepy 移动 python图像移动_卷积核_113

16.2  第二个例子

我们现在换成一张这个图,黑色背景中有一个白色的圆,我们命名其为circle

python 图片 moviepy 移动 python图像移动_像素点_114

现在我们对这张图进行50次迭代的腐蚀操作

python 图片 moviepy 移动 python图像移动_卷积核_115

这两个例子很好表现了腐蚀的作用,在核内将少数像素值变为多数像素值

  • 核越小腐蚀的力度越小,反之变大
  • 迭代次数越少腐蚀的力度越小,反之变大

我们对之前猫的图片腐蚀五次

python 图片 moviepy 移动 python图像移动_像素点_116

17  膨胀操作 dilate()

膨胀操作可以看作腐蚀操作的逆操作

我们先以刚才的2距离,这个是它没膨胀之前的样子

python 图片 moviepy 移动 python图像移动_归一化_117

现在我对这张图膨胀5次

python 图片 moviepy 移动 python图像移动_opencv_118

这个是它膨胀后的样子

python 图片 moviepy 移动 python图像移动_归一化_119

我们再使用刚刚的圆做例子,这个是它没膨胀前的样子

python 图片 moviepy 移动 python图像移动_卷积核_120

现在我对其做5次膨胀

python 图片 moviepy 移动 python图像移动_像素点_121

左侧已经贴到了边上,如果迭代次数更多会更明显

我们最后再对之前猫的图片做膨胀

python 图片 moviepy 移动 python图像移动_归一化_122

这个是膨胀了五次的效果

18  开运算与闭运算

18.1  开运算 morphologyEx(cv2.MORPH_OPEN)

先腐蚀,再膨胀,如果不设置迭代器默认进行一轮腐蚀膨胀,现在我们设置为5轮

python 图片 moviepy 移动 python图像移动_python_123

python 图片 moviepy 移动 python图像移动_opencv_124

18.2  闭运算 morphologyEx(cv2.MORPH_CLOSE)

先膨胀再腐蚀,闭运算与开运算调用的方法相同,区别为换了一个参数

python 图片 moviepy 移动 python图像移动_像素点_125

python 图片 moviepy 移动 python图像移动_卷积核_126

19  梯度运算 morphologyEx(cv2.MORPH_GRADIENT)

梯度运算实际上是膨胀-腐蚀,目的是找出我们这张图的轮廓

我们分别对圆形的图进行腐蚀与膨胀,然后我们使用膨胀-腐蚀,然后把这三个图放到一起

python 图片 moviepy 移动 python图像移动_像素点_127

python 图片 moviepy 移动 python图像移动_卷积核_128

使用opencv中的morphologyEx方法可以替代上述功能

python 图片 moviepy 移动 python图像移动_卷积核_129

参数改为cv2.MORPH_GRADIENT

python 图片 moviepy 移动 python图像移动_归一化_130

与上面得到的结果相同

我们再对之前猫的图片做梯度运算,看看能不能显示出来轮廓

python 图片 moviepy 移动 python图像移动_归一化_131

发现可以显示大致轮廓

python 图片 moviepy 移动 python图像移动_opencv_132

20  礼帽与黑帽

20.1  礼帽 morphologyEx(cv2.MORPH_TOPHAT)

礼貌=原始输入-开运算结果

python 图片 moviepy 移动 python图像移动_像素点_133

python 图片 moviepy 移动 python图像移动_像素点_134

图片中只有外面的那些触须

20.2  黑帽 morphologyEx(cv2.MORPH_BLACKHAT)

闭运算-原始输入

python 图片 moviepy 移动 python图像移动_卷积核_135

python 图片 moviepy 移动 python图像移动_python_136

这个原理上应该会有断断续续的2的轮廓,是我将图片resize的问题,我们把resize取消

python 图片 moviepy 移动 python图像移动_opencv_137

python 图片 moviepy 移动 python图像移动_卷积核_138

21  图像复制 copy()

python 图片 moviepy 移动 python图像移动_像素点_139

python 图片 moviepy 移动 python图像移动_归一化_140

这个和直接赋值是不一样的,比如如果我们使用img2 = img,此时img2和img的地址就相同了,我们之后施加在img2上的操作也同样会施加在img上而复制就可以避免这个问题,是img2与img独立存在

22  图像翻转 flip()

分三种,一种上下翻,一种左右翻,一种上下翻加左右翻

22.1  上下翻

python 图片 moviepy 移动 python图像移动_像素点_141

python 图片 moviepy 移动 python图像移动_归一化_142

22.2  左右翻

python 图片 moviepy 移动 python图像移动_python_143

python 图片 moviepy 移动 python图像移动_像素点_144

22.3  上下翻加左右翻

python 图片 moviepy 移动 python图像移动_像素点_145

python 图片 moviepy 移动 python图像移动_像素点_146

23  图像逆时针旋转90度 transpose()

也叫图像转置

python 图片 moviepy 移动 python图像移动_归一化_147

python 图片 moviepy 移动 python图像移动_像素点_148

这个迭代多次使用没有用,只有两种状态,一种是上面这种,一种是原图

我们可以使用tranpose()配合上面的flip()这样可以达到我们以90度为单位的旋转

24  图像任意角度旋转 getRotationMatrix2D()与warpAffine()

如果是以90度为单位旋转我建议使用上面的方法,因为使用这个方法一定会有黑色填充到图片其他的区域,因为我们的窗口不是斜的

python 图片 moviepy 移动 python图像移动_卷积核_149

getRotationMatrix2D的参数

  • (height*0.5,width*0.5) 旋转的中心点
  • 20 旋转角度
  • 0.5 缩放比例

warpAffine的参数

  • img 要旋转的图像
  • M 上面getRotationMatrix2D的返回值
  • (500,500) 旋转后的图像大小

python 图片 moviepy 移动 python图像移动_卷积核_150

25  图像画矩形框 rectangle()

python 图片 moviepy 移动 python图像移动_卷积核_151

rectangle的参数

  • img 要画的图像
  • (0,0) 矩形框的左上角点
  • (300,300) 矩形框的右下角点
  • (0,255,0) 矩形框的颜色
  • 2 矩形框的宽度

python 图片 moviepy 移动 python图像移动_opencv_152

26  图像写文字 putText()

26.1 写英文

python 图片 moviepy 移动 python图像移动_像素点_153

python 图片 moviepy 移动 python图像移动_归一化_154

putText参数

  • img 要写的图像
  • 'hello' 要写的文字
  • (100,100) 要写文字的位置
  • cv2.FONT_HERSHEY_SIMPLEX 字体
  • 1 字号
  • (255,0,0) 颜色
  • 2 字体线条宽度

字体还可以选择下面这些值

python 图片 moviepy 移动 python图像移动_卷积核_155

他们都写不了中文,如果要写中文需要用其他的库来写

26.2 写汉字

我下面做个例子,首先我们要有一个这样的字体文件放在代码的同级目录下

python 图片 moviepy 移动 python图像移动_归一化_156

字体文件下载地址

链接:百度网盘 请输入提取码 提取码:jsst

python 图片 moviepy 移动 python图像移动_卷积核_157

python 图片 moviepy 移动 python图像移动_卷积核_158

27  图像与运算 bitwise_and()

是两张图像的每个像素点转换为二进制后对每一位进行与运算,然后再转换为十进制

  • 与运算:全1为1,有0为0

python 图片 moviepy 移动 python图像移动_像素点_159

python 图片 moviepy 移动 python图像移动_归一化_160

我们举几个例子

  • 84与80 = 80

1010100 = 84

1010000 = 80


1010000 = 80

  • 84与79 = 68

1010100 = 84

1001111 = 79


1000100 = 64

python 图片 moviepy 移动 python图像移动_opencv_161

28  图像或运算 bitwise_or()

与上面的方法相似,不同为 或运算:有1为1,全0为0

python 图片 moviepy 移动 python图像移动_像素点_162

python 图片 moviepy 移动 python图像移动_opencv_163

我们同样举两个例子

  • 84 与 80 = 84

1010100 = 84

1010000 = 80


1010100 = 84

  • 84与79 = 95

1010100 = 84

1001111 = 79


1011111 = 95

python 图片 moviepy 移动 python图像移动_opencv_164

29  图像非运算 bitwise_not()

这个只有一个参数,参数为要操作的图像

python 图片 moviepy 移动 python图像移动_归一化_165

python 图片 moviepy 移动 python图像移动_归一化_166

结果为 255-该点的像素值

python 图片 moviepy 移动 python图像移动_opencv_167

30  图像异或运算 bitwise_xor()

异或运算:相同为0,不同为1

python 图片 moviepy 移动 python图像移动_像素点_168

python 图片 moviepy 移动 python图像移动_归一化_169

我们举两个例子

  • 84异或80 = 4

1010100 = 84

1010000 = 80


0000100 = 4

  • 84异或79 = 27

1010100 = 84

1001111 = 79


0011011 = 27

python 图片 moviepy 移动 python图像移动_归一化_170

31  图像画圈 circle()

python 图片 moviepy 移动 python图像移动_像素点_171

参数

  • img 要画圈的图像
  • (50,50) 圈的原点
  • 10 圈的半径
  • (0,0,255) 圈的颜色
  • 4 圈的线条宽度

python 图片 moviepy 移动 python图像移动_opencv_172

32  图像绘制有颜色填充的多边形 fillConvexPoly()与fillPoly()

有两种方法,分别是fillConvexPoly()与fillPoly()

32.1  fillConvexPoly()

python 图片 moviepy 移动 python图像移动_归一化_173

参数

  • img 要画的图像
  • point 点集
  • (0,255,0) 要填充的颜色

python 图片 moviepy 移动 python图像移动_卷积核_174

32.2  fillPoly()

python 图片 moviepy 移动 python图像移动_像素点_175

参数

  • img 要画的图像
  • [point] 点集的变量,在变量外要再加一个中括号
  • (0,255,0) 要填充的颜色

python 图片 moviepy 移动 python图像移动_卷积核_176

33  图像上绘制一条线 line()

python 图片 moviepy 移动 python图像移动_python_177

参数

  • img 要画的图像
  • (50,50) 线的起始点
  • (100,100) 线的终止点
  • (0,255,0) 线的颜色
  • 2 线的宽度

python 图片 moviepy 移动 python图像移动_归一化_178

34  颜色通道转换 cvtColor()

opencv的默认颜色通道为BGR,我们搞一张名为traffic_lights的交通灯测一下

python 图片 moviepy 移动 python图像移动_像素点_179

34.1  BGR转灰度图

python 图片 moviepy 移动 python图像移动_opencv_180

python 图片 moviepy 移动 python图像移动_卷积核_181

34.2  BGR转RGB

python 图片 moviepy 移动 python图像移动_归一化_182

python 图片 moviepy 移动 python图像移动_归一化_183

34.3  RGB转BGR

我们将图像转到RGB,之后再转到BGR就可以看到原图像的样子了

python 图片 moviepy 移动 python图像移动_卷积核_184

python 图片 moviepy 移动 python图像移动_归一化_185

35  拼接多张图像

比如我要拼接这三张图像

python 图片 moviepy 移动 python图像移动_opencv_186

35.1  横向拼接 hconcat()

拼接前需要将三张图像调整为同样的 高度,宽度可以不一样

python 图片 moviepy 移动 python图像移动_python_187

python 图片 moviepy 移动 python图像移动_归一化_188

35.2  纵向拼接 vconcat()

拼接前需要将三张图像调整为同样的 宽度,高度可以不一样

python 图片 moviepy 移动 python图像移动_卷积核_189

python 图片 moviepy 移动 python图像移动_卷积核_190