苦学Opencv的第五天:绘制图形与文字

Python OpenCV入门到精通学习日记:绘制图形与文字

前言

Opencv提供了许多绘制图形的方法,包括了绘制线段line()方法,绘制矩形的rectangle()方法,绘制圆形的circle()方法,绘制多边形的polylines方法和绘制文字的putText()方法。今天就学习这些方法的使用。

绘制图形和文字
绘制线段
绘制矩形
绘制圆形
绘制多边形
绘制文字
动态绘制图形

1 线段的绘制

Opencv提供了用于绘制线段的line()方法,使用这个方法可以创建各式各样的线段。语法如下:

img = cv2.line(img,pt1,pt2,color,thickness

参数说明:
 img:画布。
 pt1:线段的起点坐标。
 pt2:线段的终点坐标。
 color:绘制线段时的线条颜色。
 thickness:绘制线段时的线条宽度。

示例:使用line()方法分别绘制颜色为蓝色、绿色、红色和黄色,线条宽度为5、10、15和20的4条线段,并且这4条线段能够拼成一个“王”字。

import numpy as np
import cv2
# np.zeros()创建一个画布
# (300,300,3):一个300*300,具有3个颜色空间的画布
# np.uint8:OPencv中的灰度图像和RGB图像都是以uint8存储的,因此这里的类型也是uint8
canvas = np.zeros((300,300,3),np.uint8)
# 在画布上绘制一条起点坐标为(50,50),终点坐标为(250,50),蓝色的,线条宽度为5的线段
canvas = cv2.line(canvas,(50,50),(250,50),(255,0,0),5)
# 在画布上,绘制一条起点坐标为(50, 150)、终点坐标为(250, 150)、绿色的、线条宽度为10的线段
canvas = cv2.line(canvas,(50,150),(250,150),(0,255,0),10)
# 在画布上,绘制一条起点坐标为(50, 250)、终点坐标为(250, 250)、红色的、线条宽度为15的线段
canvas = cv2.line(canvas,(50,250),(250,250),(0,0,255),15)
# 在画布上,绘制一条起点坐标为(150, 50)、终点坐标为(150, 250)、黄色的、线条宽度为20的线段
canvas = cv2.line(canvas,(150,50),(150,250),(0,255,255),20)
cv2.imshow("lines",canvas)
cv2.waitKey()
cv2.destroyAllWindows()

运行结果如下:
在这里插入图片描述

注意在这里(x,y)坐标是正常表示的

如果想要把黑色背景改为白色背景,只需要替换
canvas = np.zeros((300,300,3),np.uint8)

canvas = np.ones((300,300,3),np.uint8)*255
至于为什么,看我前面的文章就可以啦!

2 矩形的绘制

OpenCV提供了用于绘制矩形的rectangle()方法,使用这个方法既可以绘制矩形边框,也可以绘制实心矩形。语法如下:

img = cv2.rectangle(img, pt1, pt2, color, thickness)

参数和之前一样,在这不再赘述。

示例:编写一个程序,使用rectangle()方法绘制一个青色的、线条宽度为20的矩形边框。绘制矩形时,矩形的左上角坐标为(50, 50),矩形的右下角坐标为(200, 150)。

canvas = np.zeros((300,300,3),np.uint8)
canvas = cv2.rectangle(canvas,(50,50),(200,150),(255,255,0),20)
cv2.imshow("rectangle",canvas)
cv2.waitKey()
cv2.destroyAllWindows()

运行结果如下:
在这里插入图片描述

现在我们已经绘制了一个矩形,那么如何绘制实心矩形呢?在rectangle方法的语法格式中,我们只需要将thickness的值修改为-1,就可以绘制实心矩形了。

关键代码:canvas = cv2.rectangle(canvas,(50,50),(200,150),(255,255,0),-1)

学到这里,我们可以来个进阶版本:
示例:编写一个程序,使用rectangle()方法分别绘制3个正方形边框和1个实心正方形。

canvas = np.zeros((300,300,3),np.uint8)
canvas = cv2.rectangle(canvas,(50,50),(250,250),(0,0,255),40)
canvas = cv2.rectangle(canvas,(90,90),(210,210),(0,255,0),30)
canvas = cv2.rectangle(canvas,(120,120),(180,180),(255,0,0),20)
canvas = cv2.rectangle(canvas,(140,140),(160,160),(0,255,255),-1)
cv2.imshow("square",canvas)
cv2.waitKey()
cv2.destroyAllWindows()

运行结果如下:
在这里插入图片描述

3 圆形的绘制

OpenCV提供了用于绘制圆形的circle()方法,这个方法与rectangle()方法的功能相同,既可以绘制圆形边框,也可以绘制实心圆形。circle()方法的语法格式如下:

img = cv2.circle(img, center, radius, color, thickness)

参数说明:
 img:画布。
 center:圆形的圆心坐标。
 radius:圆形的半径。
 color:绘制圆形时的线条颜色。
 thickness:绘制圆形时的线条宽度。

圆形的绘制和矩形的绘制很相似,只是矩形的起始坐标和终点坐标参数改为了圆心坐标和半径,大家可以尝试绘制个圆形试试。这里展示如何绘制同心圆和随机圆的示例,原理都很简单。

示例:编写一个程序,使用circle()方法和for循环绘制5个同心圆,这些圆形的圆心坐标均为画布的中心,半径的值分别为0,30,60,90和120,线条颜色均为绿色,线条宽度均为5。

canvas = np.zeros((300,300,3),np.uint8)
center_x = int(canvas.shape[1]/2)
center_y = int(canvas.shape[0]/2)
for r in range(0,150,30):
    cv2.circle(canvas,(center_x,center_y),r,(0,255,0),5)
cv2.imshow("circle",canvas)
cv2.waitKey()
cv2.destroyAllWindows()

运行结果如下:
在这里插入图片描述

示例:编写一个程序,使用circle()方法和for循环随机绘制27个实心圆。其中,圆心的横、纵坐标在[0, 299]内取值,半径在[11, 70]内取值,线条颜色由3个在[0, 255]内的随机数组成的列表表示。

canvas = np.zeros((300,300,3),np.uint8)
for numbers in range(0,28):
    center_x = np.random.randint(0,high = 300)
    center_y = np.random.randint(0,high = 300)
    r = np.random.randint(11,high = 71)
    # 使用NumPy库的random模块中的randint函数来生成随机整数
    # 这个函数可以生成指定范围内的随机整数数组
    color = np.random.randint(  # 调用randint函数

        # 第一个参数是随机整数的最小值,这里设置为0
        0,

        # high参数指定随机整数的最大值,这里设置为256
        # 由于randint是闭区间,所以实际生成的整数范围是[0, 255]
        high=256,

        # size参数定义了生成的随机整数数组的形状
        # 这里设置为(3,),意味着生成一个包含3个元素的一维数组
        # 这三个元素分别代表RGB颜色模型中的红色、绿色和蓝色通道
        size=(3,)

    ).tolist()  # randint函数调用结束

    # tolist()方法将NumPy数组转换为Python列表
    # 因为后续的cv2.circle函数需要一个列表作为颜色参数
    # 所以这里将生成的NumPy数组转换为列表.tolist()
    cv2.circle(canvas,(center_x,center_y),r,color,-1)
cv2.imshow("circles",canvas)
cv2.waitKey()
cv2.destroyAllWindows()

因为color的定义的内容可能新手有些难懂,我在这里打上了详细的注释,random.randint的用法在像素的操作那一章已经讲过了

运行结果如下:
在这里插入图片描述

4 多边形的绘制

OpenCV提供了绘制多边形的polylines()方法,使用这个方法绘制的多边形既可以是闭合的,也可以是不闭合的。polylines()方法的语法格式如下:

img = cv2.polylines(img, pts, isClosed, color,thickness)
参数说明:
	img:画布。
	pts:由多边形各个顶点的坐标组成的一个列表,这个列表是一个numpy的数组类型。
	isClosed:如果值为True,表示一个闭合的多边形;如果值为False,表示一个不闭合的多边形。
	color:绘制多边形时的线条颜色。
	thickness:绘制多边形时的线条宽度。

示例:编写一个程序,按顺时针给出等腰梯形4个顶点的坐标,即(100,50),(200, 50),(250, 250)和(50, 250)。在画布上根据4个顶点的坐标,绘制一个闭合的、红色的、线条宽度为5的等腰梯形边框。

canvas = np.zeros((300,300,3),np.uint8)
 # 按顺时针给出等腰梯形4个顶点的坐标
 # 这4个顶点的坐标构成了一个大小等于“顶点个数 * 1 * 2”的数组
 # 这个数组的数据类型为np.int32
pts = np.array([[100,50],[200,50],[250,250],[50,250]],np.int32)
canvas = cv2.polylines(canvas,[pts],True,(0,0,255),5)
cv2.imshow("polylines",canvas)
cv2.waitKey()
cv2.destroyAllWindows()

注意绘制边框时,给出的顶点坐标是顺时针或逆时针给出的,否则无法绘制。

运行结果如下:
在这里插入图片描述

5 文字的绘制

OpenCV提供了用于绘制文字的putText()方法,使用这个方法不仅能够设置字体的样式、大小和颜色,而且能够使字体呈现斜体的效果,还能够控制文字的方向,进而使文字呈现垂直镜像的效果。putText()方法的语法格式如下:

img = cv2.putText(img, text, org, fontFace, fontScale,color, thickness, lineType, bottomLeftOrigin)
参数说明:
	img:画布。
	text:要绘制的文字内容。
	org:文字在画布中的左下角坐标。
	fontFace:字体样式,可选参数如表所示。
	fontScale:字体大小。
	color:绘制文字时的线条颜色。
	thickness:绘制文字时的线条宽度。
	lineType:线型。(线型指的是线的产生算法,有4和8两个值,默认值为8)
	bottomLeftOrigin:绘制文字时的方向。(有True和False两个值,默认值为False)
常量名称描述
cv2.FONT_HERSHEY_SIMPLEX简单字体样式
cv2.FONT_HERSHEY_PLAIN无衬线字体,较细
cv2.FONT_HERSHEY_DUPLEX双倍宽度的字体
cv2.FONT_HERSHEY_COMPLEX复杂字体
cv2.FONT_HERSHEY_TRIPLEX三倍宽度的字体
cv2.FONT_HERSHEY_COMPLEX_SMALL小号复杂字体
cv2.FONT_HERSHEY_SCRIPT_SIMPLEX手写风格字体
cv2.FONT_HERSHEY_SCRIPT_COMPLEX复杂手写风格字体

示例:编写一个程序,在画布上绘制文字“hello”。其中,文字左下角的坐标为(20, 70),字体样式为FONT_HERSHEY_TRIPLEX,字体大小为2,线条颜色是绿色,线条宽度为5。

canvas = np.zeros((300,300,3),np.uint8)
cv2.putText(canvas,"hello",(20,70),cv2.FONT_HERSHEY_TRIPLEX,2,(0,255,0),5)
cv2.imshow("text",canvas)
cv2.waitKey()
cv2.destroyAllWindows()

运行结果如下:
在这里插入图片描述

不借助其他库或者模块,绘制中文时,会出现乱码

FONT_ITALIC可以和其他文字类型一起使用,在呈现字体样式的同时,可以呈现斜体效果。
将参数fontface可以进行如下赋值,关键代码:

fontStyle = cv2.FONT_HERSHEY_TRIPLEX + cv2.FONT_ITALIC

5.1 文字的垂直镜像效果

putText()方法的语法格式中,有一个控制绘制文字时的方向的参数,即 bottomLeftOrigin , 其默认值为False。当bottomLeftOriginTrue时,文字将呈现垂直镜像效果。

关键代码:

cv2.putText(canvas, "hello", (20, 100),cv2.FONT_HERSHEY_TRIPLEX , 2,(0, 255, 0), 5, 8, True)

记住,如果使文字“mrsoft”呈现垂直镜像效果,这时lineType和bottomLeftOrigin变成了必须参数

5.2 在图像上绘制文字

OpenCV除了可以在np.zeros()创建的画布上绘制文字外,还能够在图像上绘制文字。区别是当在图像上绘制文字时,不再需要导入Python中的numpy模块。

示例:编写一个程序,在img.png上绘制文字“women”。其中,文字左下角的坐标为(20, 90),字体样式为FONT_HERSHEY_TRIPLEX,字体大小为1,线条颜色是黄色。

img = cv2.imread("img.png")
cv2.putText(img,"women",(20,90),cv2.FONT_HERSHEY_TRIPLEX,1,(0,255,255))
cv2.imshow("text",img)
cv2.waitKey()
cv2.destroyAllWindows()

运行结果如下:
在这里插入图片描述

6 动态绘制图形

我们在前面已经学会了如何绘制静态的图形和文字了,那么如何让静态变动态呢?想要实现这个功能需要解决两个问题:如何计算运动轨迹和如何实现动画。

示例:在一个宽、高都为200像素的纯白色图像中,绘制一个半径为20像素的纯蓝色小球。让小球做匀速直线运动,一旦圆形碰触到图像边界则开始反弹(反弹不损失动能)。

  1. 计算运动轨迹

首先,我们需要定义小球的初始位置和速度。 假设水平速度为 v x ,垂直速度为 v y 。 假设水平速度为 v_x ,垂直速度为 v_y 。 假设水平速度为vx,垂直速度为vy

小球的运动可以通过以下方式计算:

  • 每帧更新小球的位置:

x new = x + v x x_{\text{new}} = x + v_x xnew=x+vx

  • 每帧更新小球的位置:

y new = y + v y y_{\text{new}} = y + v_y ynew=y+vy

当小球碰到边界时,需要改变其速度的正负号。具体规则如下:

如果小球的横坐标超出图像宽度,改变 v x 的正负号。 如果小球的横坐标超出图像宽度,改变 v_x 的正负号。 如果小球的横坐标超出图像宽度,改变vx的正负号。
如果小球的纵坐标超出图像高度,改变 v y 的正负号。 如果小球的纵坐标超出图像高度,改变 v_y 的正负号。 如果小球的纵坐标超出图像高度,改变vy的正负号。

  1. 通过time模块实现动画效果
    Python自带一个time时间模块,该模块提供了一个sleep()方法可以让当前线程休眠一段时间。
    语法如下:
time.sleep(seconds)
参数说明:
	seconds:休眠时间,单位为s,可以是小数,如1/10表示(1/10)s。

动画实际上是由多幅画面在短时间内交替放映实现的视觉效果。每一幅画面被称为一帧,所谓的60帧就是指1s放映了60幅画面。使用time模块每(1/60)s计算一次小球的移动轨迹,并将移动后的结果绘制到图像上,这样1s有60幅图像交替放映,就可以看到弹球的动画效果了。

import cv2, time, numpy as np  # 导入所需的库

width, height = 200, 200  # 设置窗口的宽度和高度
r = 20  # 圆的半径
x = r + 20  # 初始水平位置
y = r + 20  # 初始垂直位置
x_offer = y_offer = 4  # 圆的水平和垂直移动速度

while cv2.waitKey(1) == -1:  # 持续循环直到用户关闭窗口
    if x > width - r or x < r:  # 检查圆是否到达窗口的右侧或左侧边界
        x_offer *= -1  # 改变圆的水平移动方向
    if y > height - r or y < r:  # 检查圆是否到达窗口的底部或顶部边界
        y_offer *= -1  # 改变圆的垂直移动方向

    x += x_offer  # 更新圆的水平位置
    y += y_offer  # 更新圆的垂直位置

    img = np.ones((width, height, 3), np.uint8) * 255  # 创建一个全白的图像
    cv2.circle(img, (x, y), r, (255, 0, 0), -1)  # 在图像上绘制一个红色的圆

    cv2.imshow("img", img)  # 显示图像
    time.sleep(1 / 60)  # 等待约1/60秒,控制动画的帧率

cv2.destroyAllWindows()  # 关闭所有OpenCV窗口

想要修改小球初始速度就修改xy的初始速度,矢量和就是小球初始速度。

运行代码如下:
请添加图片描述

7 小结

绘制图形和文字这一块主要还是记住那几个函数和参数,很多都大同小异。难度还是在numpy对数组计算上。得多看看。从静态到动态的过渡就是对time模块和帧的认识和使用,需要一定的逻辑性,可以试试编写一个贪吃蛇了。

  • 36
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值