绘制图形其二
画多边形
画多边形就是画很多直线(线段),所以画多边形会接收一个点集的集合,是个三维数组,如果你使用二维数组来绘画的画,就会出现如下的效果:
from cv2 import cv2
import numpy as np
# 创建纯黑的背景图用来画图形
img = np.zeros((480, 640, 3), np.uint8)
# polylines(img, pts, isClosed, color, thickness=None, lineType=None, shift=None)
# polylines(图片, int32以上类型点集的集合(三维), 图形是否闭合, bgr颜色, 线宽, 线型(1/4/[8]/16), 坐标缩放比例)
pts = np.array([(320, 40), (20, 320), (620, 320)], np.int32)
cv2.polylines(img, pts, True, (0, 0, 255), 5)
cv2.imshow('draw', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
然后你会收获一个报错:
OpenCV(3.4.1) Error: Assertion failed (p.checkVector(2, 4) >= 0) in cv::polylines, file C:\projects\opencv-python\opencv\modules\imgproc\src\drawing.cpp, line 2441
Traceback (most recent call last):
File "G:/opencvStudy/note/demo.py", line 18, in <module>
cv2.polylines(img, pts, True, (0, 0, 255), 5)
cv2.error: OpenCV(3.4.1) C:\projects\opencv-python\opencv\modules\imgproc\src\drawing.cpp:2441: error: (-215) p.checkVector(2, 4) >= 0 in function cv::polylines
在当中捕获到了一个非常重要的判断:p.checkVector(2, 4) >= 0
,这说明了什么?说明他检查维度必须是三维的,因为一个多边形,可以是由多组图形合体形成的,比如我下面这个小栗子:
from cv2 import cv2
import numpy as np
# 创建纯黑的背景图用来画图形
img = np.zeros((480, 640, 3), np.uint8)
# polylines(img, pts, isClosed, color, thickness=None, lineType=None, shift=None)
# polylines(图片, int32以上类型点集的集合(三维), 图形是否闭合, bgr颜色, 线宽, 线型(1/4/[8]/16), 坐标缩放比例)
pts1 = np.array([(320, 40), (20, 320), (620, 320)], np.int32)
pts2 = np.array([(20, 140), (620, 140), (320, 420)], np.int32)
cv2.polylines(img, [pts1, pts2], True, (0, 0, 255), 5)
cv2.imshow('draw', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
就画出来了由两个三角形组成的六边形:
当中 isClosed
代表图形是否闭合,如果闭合的话,会首尾相连,否则会止步于最后一点。
填充多边形
因为是填充,所以必定会闭合图形,然后在封闭的图形中填充颜色。但他有个小小的要注意的地方,就拿填充上面六边形来说,如果你用画六边形的方法填充他,那你铁定获得了6个相连的填充三角形:
from cv2 import cv2
import numpy as np
# 创建纯黑的背景图用来画图形
img = np.zeros((480, 640, 3), np.uint8)
# fillPoly(img, pts, color, lineType=None, shift=None, offset=None)
# fillPoly(图片, int32以上类型点集的集合(三维), bgr颜色, 线型(1/4/[8]/16), 坐标缩放比例, 坐标偏移量(x, y))
pts1 = np.array([(320, 40), (20, 320), (620, 320)], np.int32)
pts2 = np.array([(20, 140), (620, 140), (320, 420)], np.int32)
cv2.fillPoly(img, [pts1, pts2], (0, 255, 0))
cv2.imshow('draw', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果图:
那如何让他填充实体的六边形呢?答案也很简单,分开来填充~
from cv2 import cv2
import numpy as np
# 创建纯黑的背景图用来画图形
img = np.zeros((480, 640, 3), np.uint8)
# fillPoly(img, pts, color, lineType=None, shift=None, offset=None)
# fillPoly(图片, int32以上类型点集的集合(三维), bgr颜色, 线型(1/4/[8]/16), 坐标缩放比例, 坐标偏移(x, y))
pts1 = np.array([(320, 40), (20, 320), (620, 320)], np.int32)
pts2 = np.array([(20, 140), (620, 140), (320, 420)], np.int32)
cv2.fillPoly(img, [pts1], (0, 255, 0))
cv2.fillPoly(img, [pts2], (0, 255, 0))
cv2.imshow('draw', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
这下就得到了整个正六边形的填充体了:
添加文字
字体格式:
方法说明看注释:
from cv2 import cv2
import numpy as np
# 创建纯黑的背景图用来画图形
img = np.zeros((480, 640, 3), np.uint8)
# putText(img, text, org, fontFace, fontScale, color, thickness=None, lineType=None, bottomLeftOrigin=None)
# putText(图片, 文字(英文), 左下角坐标, 字体格式, 字体大小, color, thickness=None, lineType=None, bottomLeftOrigin=None)
cv2.putText(img, 'OpenCV', (50, 150), cv2.FONT_HERSHEY_COMPLEX, 4, (0, 0, 255))
cv2.putText(img, '你好cv2!!', (50, 350), cv2.FONT_HERSHEY_COMPLEX, 4, (0, 0, 255))
cv2.imshow('draw', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
打印结果,发现中文以及中文符号都变成问号了,只有英文和英文标点和数字能正常显示。可以看出OpenCV实际上是一点也不支持中文的,字体都是英文字体:
如何让图片上有中文?
这里有一种 “曲线救国” 的方式——使用 Pillow
库绘制中文。
实际上这里的绘制中文,跟OpenCV完全没有关系(毕竟我们不会大佬那种修改C++的方式)。
from cv2 import cv2
import numpy as np
from PIL import ImageFont, ImageDraw, Image
# 纯白
# img = np.full((617, 821, 3), 255, np.uint8)
# 读取背景图片
img = cv2.imread('./cat.jpeg')
# 导入字体文件
font = ImageFont.truetype('./113.ttf', 64)
# 创建一个pillow的图片
img_pil = Image.fromarray(img)
draw = ImageDraw.Draw(img_pil)
# 利用draw去绘制中文
draw.text((250, 300), '你好cv2!!', font=font, fill=(0, 0, 255))
# 重新变回ndarray
img = np.array(img_pil)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行效果图:
这下中文可以正常显示出来了,Nice!