绘制图形函数
先做准备工作:
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 显示函数
def cv_show(name, img):
cv2.imshow('name', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
再创建一个黑色的图片:
# 创建一个黑色的照片
'''
numpy.zeros(shape, dtype=float, order=’C’)
创建0矩阵 返回给定形状和类型的新数组,用零填充
shape: int或ints序列 ,例如(2 ,3)或 2
dtype: 数组类型,可选,numpy.int8或numpy.float64
order:可选,是否在存储器中以c或fortran连续(按行或列方式)存储多为数组
'''
img = np.zeros((512, 512, 3), np.uint8)
'''
(512, 512, 3):512*512*3的数组的形式
np.uint8: 8位的数据类型,最大255
全部填充0,所以是黑色
'''
1.画线
# 只需要知道起点和终点
# 画一条宽度为5的蓝线 起点和终点 BGR格式
cv2.line(img, (0, 0), (511, 511), (255, 0, 0), 3)
'''
img:要画线的图片
(0, 0): 线段的起点
(511, 511): 线段的终点
(255, 0, 0): BGR格式的 要画的线是蓝色的
3: 线段的宽度
'''
cv_show('line', img)
输出结果:
2.画矩形
# 画矩形
# 知道左上角顶点和右下角顶点
cv2.rectangle(img, (300, 30), (500, 100), (0, 255, 0), 3)
'''
img: 要画的图片
(300, 0): 左上角的顶点
(500, 100): 右下角的顶点
(0, 255, 0): BGR 绿色
3: 线宽
'''
cv_show('rectangle', img)
输出结果:
3.画圆
# 画圆
# 知道中心点坐标和半径大小
cv2.circle(img, (400, 60), 30, (0, 0, 255), -1)
'''
img:要画的图片
(400, 60):中心点的坐标
30:圆的半径
(0, 0, 255):BGR 红色
-1: 是实心的, 如果是其他数字就是线宽
'''
cv_show('circle', img)
输出结果:
4.画椭圆
椭圆
# 中心点坐标,长轴和短轴的长度,逆时针旋转的角度
# 顺时针方向起始的角度和结束角度
cv2.ellipse(img, (200, 200), (100, 50), 45, 90, 360, (0, 255, 0), -1)
'''
img: 要画的图片
(200, 200): 中心点坐标
(100, 50): 长轴和短轴的长度,如果相等,就是一个圆
45:逆时针旋转的角度 45度就是斜左上角,0度就是正的
90:起始的角度,配合结束的角度 ,可以画一些扇形
360 结束的角度,配合起始的角度 ,可以画一些扇形
(0, 255, 0):BGR 绿色
-1: 实心填充
'''
cv_show('ellipse', img)
输出结果:
5.画多边形
画空心的:
# 画多边形 需要指定每个顶点的坐标 数组的类型必须是int32
# 画一个黄色的具有四个顶点的多边形
'''
创建一个数组
numpy.array(object, dtype=None, copy=True, order='K', subok=False, ndmin=0)
object:公开数组接口的任何对象,__array__方法返回数组的对象,或任何(嵌套)序列
dtype:可选 数组的数据类型,默认是序列中对象所需的最小类型
copy: 可选 默认True 则赋值对象,
order: {'K,'A','C','F'}可选 指定阵列的内存布局 C是行 F是列
subok:可选 如果是True,则子类将被传递,否则返回的数组被强制为基类数组(默认)
ndmin:可选 指定结果数组具有的最小维数,
'''
pts = np.array([[100, 50], [20, 130], [70, 120], [80, 110]], np.int32)
'''
[[100, 50], [20, 130], [70, 120], [80, 110]]: 这是一个二维数组
np.int32: 数据类型是32位
'''
'''
不改变元素的值,改变数组的形状
reshape()
'''
pts = pts.reshape((-1, 1, 2))
# 这里reshape 的第一个参数为-1 表明这一维的长度是根据后面的维度计算出来的
'''
polylines(img, pts,isClosed, color,thickness = 1, lineType = LINE_8, shift = 0)
img:要画的图片
pts:多边形的曲线的点的集合
isClosed:True 封闭的
color:画的颜色
thickness:线宽
lineType:线的类型
shift:坐标点的小数位数
'''
cv2.polylines(img, [pts], True, (0, 255, 0), 3)
'''
img:要画的图片
[pts]:要画的多边形的顶点的集合
True: 表示多边形是否是封闭的
(0, 255, 0):BGR 绿色
3:线宽
'''
cv_show('reshape', img)
输出结果:
实心多边形
# 画填充实心多边形
'''
fillConvexPoly(img, pts, npts, color, lineType=8, shift=0)
img: 要绘制的图片
pts: 指向单个多边形的指针数组 多边形的顶点集合
npts: 多边形的顶点个数
color: 颜色
lineType: 线条的类型
shift: 顶点坐标的小数点位数
'''
cv2.fillConvexPoly(img, pts, (0, 255, 0))
'''
fillPoly(img,ppt,npt,1,Scalar(255,255,255),lineType);
img: 要绘制的图片
ppt: 多边形的顶点集合
npt: 多边形的顶点数目
1: 要绘制的多边形的数量为1
Scalar(255,255,255): 颜色
lineType: 线的类型
没有线宽的参数 默认是实心
'''
# cv2.fillPoly(img, [pts], (200, 0, 200))
cv_show('fillPoly', img)
输出结果:
6.在图片上添加文字
在图片上添加文字
'''
cvInitFont(font, font_face, hscale, vscale, shear=0, thickness=1, line_type=8 );
font: 字体初始化
font_face: 字体名称标识符 来自于Hershey字体集
(http://sources.isc.org/utils/misc/hershey-font.txt)
FONT_HERSHEY_SIMPLEX 正常大小无衬线字体
FONT_HERSHEY_DUPLEX 正常大小无衬线字体 更复杂
FONT_HERSHEY_PLAIN 小号无衬线字体
FONT_HERSHEY_COMPLEX 正常大小有衬线字体
FONT_HERSHEY_TRIPLEX 正常大小有衬线字体 更复杂
FONT_HERSHEY_SCRIPT_SIMPLEX 手写风格字体
FONT_HERSHEY_SCRIPT_COMPLEX 手写风格字体 更复杂
hscale: 字体宽度, 1.0f 字体的宽度就是最初的字体宽度 0.5f 字体宽度为原来一半
vscale: 字体高度 1.0f 字体的高度就是最初的字体高度 0.5f 字体高度为原来一半
shear: 字体斜度 0 字体不倾斜 1.0f 倾斜45度
thickness: 字体笔划的粗细程度
line_type: 字体笔划的类型
'''
font1 = cv2.FONT_HERSHEY_SIMPLEX
font2 = cv2.FONT_HERSHEY_DUPLEX
font3 = cv2.FONT_HERSHEY_PLAIN
font4 = cv2.FONT_HERSHEY_COMPLEX
font5 = cv2.FONT_HERSHEY_SCRIPT_SIMPLEX
font6 = cv2.FONT_HERSHEY_DUPLEX
font7 = cv2.FONT_HERSHEY_SCRIPT_COMPLEX
'''
PutText(img, text, org, font, color );
img:绘制的图片
text:显示的字符串
org:第一个字符左下角的坐标
font:字体结构初始化
color:文本的字体颜色
'''
cv2.putText(img, 'luatao', (50, 100), font1, 4, (255, 0, 255), 2)
# 图像 绘制的文字 绘制的位置 字体 字体大小 颜色 线宽
cv2.putText(img, 'luatao', (50, 200), font2, 4, (255, 0, 255), 2)
cv2.putText(img, 'luatao', (50, 300), font3, 4, (255, 0, 255), 2)
cv2.putText(img, 'luatao', (50, 400), font4, 4, (255, 0, 255), 2)
cv2.putText(img, 'luatao', (50, 500), font6, 4, (255, 0, 255), 2)
cv_show('text', img)
输出结果:
7.把鼠标当画笔
查看所有支持的鼠标事件
events = [i for i in dir(cv2) if 'EVENT' in i]
for e in events:
print(e)
'''
鼠标回调函数固定格式
def draw_circle(event, x, y, flags, param):
event: 鼠标的各种操作
EVENT_MOUSEMOVE 滑动
EVENT_LBUTTONDOWN 左键点击
EVENT_RBUTTONDOWN 右键点击
EVENT_MBUTTONDOWN 中键点击
EVENT_LBUTTONUP 左键放开
EVENT_RBUTTONUP 右键放开
EVENT_MBUTTONUP 中键放开
EVENT_LBUTTONDBLCLK 左键双击
EVENT_RBUTTONDBLCLK 右键双击
EVENT_MBUTTONDBLCLK 中键双击
x: 窗口的x,y坐标位置
y: 窗口的x,y坐标位置
flags: 鼠标的拖拽时间,以及键盘鼠标联合事件, 共32种事件
EVENT_FLAG_LBUTTON 左鍵拖曳
EVENT_FLAG_RBUTTON 右鍵拖曳
EVENT_FLAG_MBUTTON 中鍵拖曳
EVENT_FLAG_CTRLKEY (8~15)按Ctrl不放事件
EVENT_FLAG_SHIFTKEY (16~31)按Shift不放事件
EVENT_FLAG_ALTKEY (32~39)按Alt不放事件
param:标记了响应事件的函数,自定义了ID
'''
# 鼠标回调函数
# 在图片上双击过的位置绘制一个圆圈。
def draw_circle(event, x, y, flags, param):
if event == cv2.EVENT_LBUTTONDBLCLK:
cv2.circle(img, (x, y), 50, (255, 0, 0), -1)
# 创建图像与窗口并将窗口与回调函数绑定
img = np.zeros((512, 512, 3), np.uint8)
# 新建一个显示窗口
cv2.namedWindow('image')
cv2.setMouseCallback('image', draw_circle)
while True:
cv2.imshow('image', img) # 显示图片串口
if cv2.waitKey(20) & 0xff == 27: # 等待按下esc键
break
cv2.destroyAllWindows()
输出结果:
根据选择的模式判断是绘制矩形还是圆形
# 根据选择的模式,在拖动鼠标时绘制矩形或者是圆圈
# 当鼠标按下时变为 True
drawing = False
# 如果mode 为 True 绘制矩形,按下‘m’绘制曲线
mode = True
ix, iy = -1, -1
# 创建回调函数
def draw_circle_Rect(event, x, y, flags, param):
global ix, iy, drawing, mode # 调用的是全局变量
# 当按下左键是返回起始位置坐标
if event == cv2.EVENT_LBUTTONDOWN:
drawing = True
ix, iy = x, y
# 当鼠标左键按下并移动是绘制图形 event可以查看移动,flag查看是否按下
elif event == cv2.EVENT_MOUSEMOVE and flags == cv2.EVENT_FLAG_LBUTTON:
if drawing == True:
if mode == True:
cv2.rectangle(img, (ix, iy), (x, y), (0, 255, 0), -1)
else:
# 绘制圆圈 小圆点连在一起就成了线
cv2.circle(img, (x, y), 3, (0, 0, 255), -1)
# 当鼠标松开停止绘画
elif event == cv2.EVENT_LBUTTONUP:
drawing == False
# 创建窗口并绑定回调函数
img = np.zeros((512, 512, 3), np.uint8)
cv2.namedWindow('image')
cv2.setMouseCallback('image', draw_circle_Rect)
while True:
cv2.imshow('image', img)
k = cv2.waitKey(1) & 0xff # 等待按键返回ASCII码
if k == ord('m'): # 判断ASCII是否等于m
mode = not mode # 模式改变
elif k == 27:
break
8.滑动条
# 通过调节滑动条来设定画板颜色
# 回调函数 每次滑动条的滑动都会调用回调函数
def nothing(x):
pass # 什么也不做
# 创建一副黑色图像
img = np.zeros((300, 500, 3), np.uint8)
cv2.namedWindow('image')
'''
创建一个滑动控件
createTrackbar(trackbarname, winname, value,count,TrackbarCallback onChange = 0,userdata = 0);
trackbarname: 滑动控件的名字
winname: 滑动控件依附的图像窗口的名字
value: 初始化阈值 滑动条的初始值
count: 滑动控件的刻度范围
TrackbarCallback: 回调函数
# 滑动条的另一个重要应用就是用作转换按钮。
'''
cv2.createTrackbar('R', 'image', 100, 255, nothing)
cv2.createTrackbar('G', 'image', 0, 255, nothing)
cv2.createTrackbar('B', 'image', 0, 255, nothing)
switch = '0:OFF\n1:ON' # 开关
cv2.createTrackbar(switch, 'image', 0, 1, nothing)
'''
获取滑动条的位置的值
getTrackbarPos(trackbarname,winname)
trackbarname: 控件的名字
winname:窗口的名字
'''
while True:
cv2.imshow('image', img) # 显示
k = cv2.waitKey(1) & 0xff # 获取ASCII值
if k == 27: # 退出键ESC
break
r = cv2.getTrackbarPos('R', 'image')
g = cv2.getTrackbarPos('G', 'image')
b = cv2.getTrackbarPos('B', 'image')
s = cv2.getTrackbarPos(switch, 'image')
if s == 0: # 如果开关是关的,图片的所有值都是0
img[:] = 0
else:
img[:] = [b, g, r] # 给图片重新赋值 改变颜色
cv2.destroyAllWindows()
输出结果:
这些图片的操作都是基础,接下来就是重点了。要好好学啊。