五、图像绘制
这一节,将学习如何使用OpenCV来绘制三种不同的形状:直线、矩形与圆形。
照例,先自己看一下整体的源代码揣测一下大致各行代码是什么意思。
1、源代码展现
drawing.py
(From Practical Python and OpenCV, 3rd Edition)
import numpy as np
import cv2
# Initialize our canvas as a 300x300 with 3 channels,
# Red, Green, and Blue, with a black background
canvas = np.zeros((300, 300, 3), dtype = "uint8")
# Draw a green line from the top-left corner of our canvas
# to the bottom-right
green = (0, 255, 0)
cv2.line(canvas, (0, 0), (300, 300), green)
cv2.imshow("Canvas", canvas)
cv2.waitKey(0)
# Now, draw a 3 pixel thick red line from the top-right
# corner to the bottom-left
red = (0, 0, 255)
cv2.line(canvas, (300, 0), (0, 300), red, 3)
cv2.imshow("Canvas", canvas)
cv2.waitKey(0)
# Draw a green 50x50 pixel square, starting at 10x10 and
# ending at 60x60
cv2.rectangle(canvas, (10, 10), (60, 60), green)
cv2.imshow("Canvas", canvas)
cv2.waitKey(0)
# Draw another rectangle, this time we'll make it red and
# 5 pixels thick
cv2.rectangle(canvas, (50, 200), (200, 225), red, 5)
cv2.imshow("Canvas", canvas)
cv2.waitKey(0)
# Let's draw one last rectangle: blue and filled in
blue = (255, 0, 0)
cv2.rectangle(canvas, (200, 50), (225, 125), blue, -1)
cv2.imshow("Canvas", canvas)
cv2.waitKey(0)
# Reset our canvas and draw a white circle at the center
# of the canvas with increasing radii - from 25 pixels to
# 150 pixels
canvas = np.zeros((300, 300, 3), dtype = "uint8")
(centerX, centerY) = (canvas.shape[1] // 2, canvas.shape[0] // 2)
white = (255, 255, 255)
for r in range(0, 175, 25):
cv2.circle(canvas, (centerX, centerY), r, white)
cv2.imshow("Canvas", canvas)
cv2.waitKey(0)
# Let's go crazy and draw 25 random circles
for i in range(0, 25):
# randomly generate a radius size between 5 and 200,
# generate a random color, and then pick a random
# point on our canvas where the circle will be drawn
radius = np.random.randint(5, high = 200)
color = np.random.randint(0, high = 256, size = (3,)).tolist()
pt = np.random.randint(0, high = 300, size = (2,))
# draw our random circle
cv2.circle(canvas, tuple(pt), radius, color, -1)
# Show our masterpiece
cv2.imshow("Canvas", canvas)
cv2.waitKey(0)
2、结果展现
![]() |
![]() |
![]() |
---|---|---|
直线 | 矩形 | 同心圆 | 随机圆 |
3、代码解释
a. 导包与初始化
import numpy as np
import cv2
canvas = np.zeros((300, 300, 3), dtype = "uint8")
Line 1-2
导入Numpy和OpenCV库,相信不需要再解释了。
Line 6
对画布进行初始化。通过np.zeros设定了一个300行、300列,三通道的画布。该矩阵中所有元素均为0【0代表最暗,所以这是一张黑色背景的画布】,三个通道分别留给红、绿、蓝三种颜色。此外,定义数据类型data type为uint8(8-bit unsigned integer),即8位无符号整型,因为我们的像素值的取值范围是[0, 255]。
b. 绘制直线
green = (0, 255, 0)
cv2.line(canvas, (0, 0), (300, 300), green)
cv2.imshow("Canvas", canvas)
cv2.waitKey(0)
red = (0, 0, 255)
cv2.line(canvas, (300, 0), (0, 300), red, 3)
cv2.imshow("Canvas", canvas)
cv2.waitKey(0)
Line 8-20
分别定义两个元组,并将代表绿色和红色的RGB值赋给green和red。
通过cv2.line可以画出一条直线。其中的第一个参数是我们想要在上面绘制形状的图像,在这里即为canvas,第二和第三个参数则分别标示着直线的起点和终点。第四个参数则是直线的颜色。
注意到,在绘制红色直线的时候,cv2.line中最后还出现了一个参数,3。这个参数代表着你想画的直线粗细,数字越大显然直线越粗。根据结果来看,猜测直线粗细默认值应当为1。
最后,同样都使用cv2.imshow,因为输入的参数完全一致,可知,在敲下任意键的时候,并不会出现第二个图形界面,而是将第二次所画的红色直线直接添加到了绿色直线所在的画布当中。
c. 绘制矩形
cv2.rectangle(canvas, (10, 10), (60, 60), green)
cv2.imshow("Canvas", canvas)
cv2.waitKey(0)
cv2.rectangle(canvas, (50, 200), (200, 225), red, 5)
cv2.imshow("Canvas", canvas)
cv2.waitKey(0)
blue = (255, 0, 0)
cv2.rectangle(canvas, (200, 50), (225, 125), blue, -1)
cv2.imshow("Canvas", canvas)
cv2.waitKey(0)
Line 22-38
绘制绿色与红色矩形时,除了将cv2.line替换成cv2.rectangle以外,其他操作基本与绘制直线一致,第二和第三个参数分别标示矩形的起始位置和终止位置。此时我们绘制出的是一个空心的矩形,那如何绘制实心矩形呢?
答案很简单,只需要在代表线条粗细的数值前添加负号即可~
绘制蓝色矩形时,我们就通过更改线条粗细值为-1填充出一个蓝色的实心矩形。
d. 绘制圆形
①同心圆
canvas = np.zeros((300, 300, 3), dtype = "uint8")
(centerX, centerY) = (canvas.shape[1] // 2, canvas.shape[0] // 2)
white = (255, 255, 255)
for r in range(0, 175, 25):
cv2.circle(canvas, (centerX, centerY), r, white)
cv2.imshow("Canvas", canvas)
cv2.waitKey(0)
Line 43
在开始绘制圆形之前,首先我们将画布重置,清空先前在上面画的线条和矩形。
接下来让我们先来看一下cv2.circle这个函数。
Line 48
可以看到,中间两个参数发生了变化,不再是起点和终点了。这时,第二个参数(centerX, centerY)是一个元组,表示圆心的位置,而第三个参数r则是圆的半径。在本例中想要绘制一串同心圆,因此我们需要预先找到同心圆的公共圆心,亦即画布的中心,并将其位置放到所需的元组里以便在函数中取用。
Line 44-45
使用//(地板除:floor(x) = [x]{不大于x的整数},与取整除不同)分别取到centerX和centerY作为同心圆的圆心坐标。【切记:Numpy数组中shape[0]代表高度,而shape[1]代表宽度】
之后,创建一个代表白色的元组。
Line 47-51
通过循环,分别绘制直径不同的圆形组成同心圆。由于最后175的半径是取不到的,所以最外面的圆刚好是150的半径,成为矩形画布的内切圆。
②进阶:25个随机圆
for i in range(0, 25):
radius = np.random.randint(5, high = 200)
color = np.random.randint(0, high = 256, size = (3,)).tolist()
pt = np.random.randint(0, high = 300, size = (2,))
cv2.circle(canvas, tuple(pt), radius, color, -1)
cv2.imshow("Canvas", canvas)
cv2.waitKey(0)
Line 53-67
显然可以看出,这段代码通过循环分别产生25个任意半径、任意颜色、任意位置的随机圆并绘制。
np.random.randint:返回随机数整型,第一个参数为区间下限(闭),第二个参数通过high = X指定了区间上限X(开),size作为可选参数表示输出随机数的尺寸(如:颜色作为三通道尺寸为3,而点位需要x和y坐标,故尺寸为2)
在产生随机颜色时,我们通过python的tolist方法将产生的Numpy数组转换成了列表,之后在绘制圆形时通过tuple( )将列表转换为元组输出。由设定线条粗细为负值,我们设置绘制的圆形是实心的,从结果显示也可以得出这一结论。
4、写在最后
由于全程我们一直使用同一个窗口输出绘制结果,因此我们只需要运行源代码后敲击键盘按键就可以看到我们绘制的直线、矩形、同心圆以及最后的25个随机圆了。
【天知道为了最后那25个圆能呈现出一张好看的图片博主Run了多少次程序o(╥﹏╥)o】