OpenCV学习笔记(十四)——绘图及交互

本节介绍了如何在图像上绘制图形,并且如何用鼠标和滚动条实现用户交互。

1. 绘画基础

OpenCV 提供了绘制直线的函数cv2.line()、绘制矩形的函数cv2.rectangle()、绘制圆的函数cv2.circle()、绘制椭圆的函数cv2.ellipse()、绘制多边形的函数cv2.polylines()、在图像内添加文字的函数cv2.putText()等多种绘图函数。

这些绘图函数有一些共有的参数,主要用于设置源图像、颜色、线条属性等。下面对这些共有参数做简单的介绍。

  • img:在其上面绘制图形的载体图像(绘图的容器载体,也称为画布、画板)。
  • color:绘制形状的颜色。通常使用BGR 模型表示颜色,例如,(0, 255, 0)表示绿色。对
    于灰度图像,只能传入灰度值。需要注意,颜色通道的顺序是BGR,而不是RGB。
  • thickness:线条的粗细。默认值是1,如果设置为-1,表示填充图形(即绘制的图形是实心的)。
  • lineType:线条的类型,默认是8 连接类型。lineType 参数的值及说明如表 所示。

在这里插入图片描述

  • shift:数据精度。该参数用来控制数值(例如圆心坐标等)的精度,一般情况下不需要设置。
1.1 绘制直线

img = cv2.line( img, pt1, pt2, color[, thickness[, lineType ]])

  • 参数 img、color、thickness、lineType 的含义如前面的说明所示。
  • pt1 表示线段的第1 个点(起点)。
  • pt2 表示线段的第2 个点(终点)。
import numpy as np
import cv2
n = 300
img = np.zeros((n+1,n+1,3), np.uint8)
img = cv2.line(img,(0,0),(n,n),(255,0,0),3)
img = cv2.line(img,(0,100),(n,100),(0,255,0),1)
img = cv2.line(img,(100,0),(100,n),(0,0,255),6)
winname = 'Demo19.1'
cv2.namedWindow(winname)
cv2.imshow(winname, img)
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述

1.2 绘制矩形

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

  • 参数 img、color、thickness、lineType 的含义如前面的说明所示。
  • pt1 为矩形顶点。
  • pt2 为矩形中与pt1 对角的顶点。
import numpy as np
import cv2
n = 300
img = np.ones((n,n,3), np.uint8)*255
img = cv2.rectangle(img,(50,50),(n-100,n-50),(0,0,255),-1)
winname = 'Demo19.1'
cv2.namedWindow(winname)
cv2.imshow(winname, img)
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述

1.3 绘制圆形

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

  • 参数 img、color、thickness、lineType 的含义如前面的说明所示。
  • center 为圆心。
  • radius 为半径。
import numpy as np
import cv2
d = 400
img = np.ones((d,d,3),dtype="uint8")*255
(centerX,centerY) = (round(img.shape[1] / 2),round(img.shape[0] / 2))
# 将图像的中心作为圆心,实际值为d/2
red = (0,0,255) # 设置白色变量
for r in range(5,round(d/2),12):
	cv2.circle(img,(centerX,centerY),r,red,3)
# circle(载体图像,圆心,半径,颜色)
cv2.imshow("Demo19.3",img)
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述

import numpy as np
import cv2
d = 400
img = np.ones((d,d,3),dtype="uint8")*255
# 生成白色背景
for i in range(0,100):
	centerX = np.random.randint(0,high = d)
	centerY = np.random.randint(0,high = d)
	# 生成随机圆心centerY,确保在画布img 内
	radius = np.random.randint(5,high = d/5)
	# 生成随机半径,值范围为[5,d/5),最大半径是d/5
	color = np.random.randint(0,high = 256,size = (3,)).tolist()
	# 生成随机颜色,3[0,256)的随机数
	cv2.circle(img,(centerX,centerY),radius,color,-1)
	# 使用上述随机数在画布img 内画圆
	# 生成随机圆心centerX,确保在画布img 内
cv2.imshow("demo19.4",img)
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述

1.4 绘制椭圆

img=cv2.ellipse(img, center, axes, angle, startAngle, endAngle, color[, thickness[, lineType]])

  • 参数 img、color、thickness、lineType 的含义如前面的说明所示。
  • center 为椭圆的圆心坐标。
  • axes 为轴的长度。
  • angle 为偏转的角度。
  • startAngle 为圆弧起始角的角度。
  • endAngle 为圆弧终结角的角度。
import numpy as np
import cv2
d = 400
img = np.ones((d,d,3),dtype="uint8")*255
# 生成白色背景
center=(round(d/2),round(d/2))
# 注意数值类型,不可以使用语句center=(d/2,d/2)
size=(100,200)
# 轴的长度
for i in range(0,10):
	angle = np.random.randint(0,361)
	# 偏移角度
	color = np.random.randint(0,high = 256,size = (3,)).tolist()
	# 生成随机颜色,3[0,256)的随机数
	thickness = np.random.randint(1,9)
	cv2.ellipse(img, center, size, angle, 0, 360, color,thickness)
cv2.imshow("demo19.5",img)
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述

1.5 绘制多边形

img = cv2.polylines( img, pts, isClosed, color[, thickness[, lineType[, shift]]])

  • 参数 img、color、thickness、lineType 和shift 的含义如前面的说明所示。
  • pts 为多边形的各个顶点。
  • isClosed 为闭合标记,用来指示多边形是否是封闭的。若该值为True,则将最后一个点与第一个点连接,让多边形闭合;否则,仅仅将各个点依次连接起来,构成一条曲线。

在使用函数cv2.polylines()绘制多边形时,需要给出每个顶点的坐标。这些点的坐标构建了一个大小等于“顶点个数×1×2”的数组,这个数组的数据类型必须为numpy.int32。下面的例子绘制了一个黄色的具有四个顶点的多边形。

import numpy as np
import cv2
d = 400
img = np.ones((d,d,3),dtype="uint8")*255
# 生成白色背景
pts=np.array([[200,50],[300,200],[200,350],[100,200]], np.int32)
# 生成各个顶点,注意数据类型为int32
pts=pts.reshape((-1,1,2))
# 第1 个参数为-1, 表明它未设置具体值,它所表示的维度值是通过其他参数值计算得到的
cv2.polylines(img,[pts],True,(0,255,0),8)
# 调用函数cv2.polylines()完成多边形绘图。注意,第3 个参数控制多边形是否封闭
cv2.imshow("demo19.6",img)
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述

1.6 在图像上绘制文字

img=cv2.putText(img, text, org, fontFace, fontScale, color[, thickness[, lineType[, bottomLeftOrigin]]])

  • 参数 img、color、thickness、lineType 和shift 的含义如前面的说明所示。
  • text 为要绘制的字体。
  • org 为绘制字体的位置,以文字的左下角为起点。
  • fontFace 表示字体类型,其参数类型及含义如表所示。

在这里插入图片描述

  • fontScale 表示字体大小。
  • bottomLeftOrigin 用于控制文字的方向。默认值为False,当设置为True 时,文字是垂直镜像的效果。
import numpy as np
import cv2
d = 400
img = np.ones((d,d,3),dtype="uint8")*255
# 生成白色背景
font=cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img,'OpenCV',(0,200), font, 3,(0,255,0),15)
cv2.putText(img,'OpenCV',(0,200), font, 3,(0,0,255),5)
cv2.imshow("demo19.7",img)
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述

import numpy as np
import cv2
d = 400
img = np.ones((d,d,3),dtype="uint8")*255
# 生成白色背景
font=cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img,'OpenCV',(0,150),font, 3,(0,0,255),15)
cv2.putText(img,'OpenCV',(0,250),font, 3,(0,255,0),15,cv2.FONT_HERSHEY_SCRIPT_SIMPLEX,True)
cv2.imshow("demo19.7",img)
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述

2. 鼠标交互

当用户触发鼠标事件时,我们希望对该事件做出响应。例如,用户单击鼠标,我们就画一个圆。通常的做法是,创建一个OnMouseAction()响应函数,将要实现的操作写在该响应函数内。响应函数是按照固定的格式创建的,其格式为:·

def OnMouseAction(event,x,y,flags,param):

  • event 表示触发了何种事件,具体事件如表所示。

在这里插入图片描述
在这里插入图片描述

  • x, y 代表触发鼠标事件时,鼠标在窗口中的坐标(x, y)。
  • flags 代表鼠标的拖曳事件,以及键盘鼠标联合事件,如表所示。

在这里插入图片描述

  • param 为函数ID,标识所响应的事件函数,相当于自定义一个OnMouseAction()函数的ID。
  • OnMouseAction 为响应函数的名称,该名称可以自定义。

定义响应函数以后,要将该函数与一个特定的窗口建立联系(绑定),让该窗口内的鼠标触发事件时, 能够找到该响应函数并执行。要将函数与窗口绑定, 可以通过函数
cv2.setMouseCallback()实现,其基本语法格式是:

cv2.setMouseCallback(winname,onMouse)

  • winname 为绑定的窗口名。
  • onMouse 为绑定的响应函数名。
import cv2
import numpy as np
def Demo(event,x,y,flags,param):
	if event == cv2.EVENT_LBUTTONDOWN:
		print("单击了鼠标左键")
	elif event==cv2.EVENT_RBUTTONDOWN :
		print("单击了鼠标右键")
	elif flags==cv2.EVENT_FLAG_LBUTTON:
		print("按住左键拖动了鼠标")
	elif event==cv2.EVENT_MBUTTONDOWN :
		print("单击了中间键")
# 创建名称为Demo 的响应(回调)函数OnMouseAction
img = np.ones((300,300,3),np.uint8)*255
cv2.namedWindow('Demo19.9')
cv2.setMouseCallback('Demo19.9',Demo)
cv2.imshow('Demo19.9',img)
cv2.waitKey()
cv2.destroyAllWindows()

运行上述程序,先后单击左键、右键、滚轮、拖动鼠标,则程序运行结果如图所示。
在这里插入图片描述
说明:可以通过下面的方法查看OpenCV 所支持的鼠标事件:

import cv2
events=[i for i in dir(cv2) if 'EVENT'in i]
print(events)
2.1 简单示例

实现一个双击鼠标绘制矩形的简单程序。在该程序中,首先创建响应函数draw(),在该函数内编写代码,实现:当双击鼠标时,以当前位置为顶点绘制大小随机、颜色随机的矩形。通过函数cv2.setMouseCallback()将函数draw()和新建窗口“Demo19.10”绑定。

import cv2
import numpy as np
d = 400
def draw(event,x,y,flags,param):
	if event==cv2.EVENT_LBUTTONDBLCLK:
		p1x=x
		p1y=y
		p2x=np.random.randint(1,d-50)
		p2y=np.random.randint(1,d-50)
		color = np.random.randint(0,high = 256,size = (3,)).tolist()
		cv2.rectangle(img,(p1x,p1y),(p2x,p2y),color,2)
img = np.ones((d,d,3),dtype="uint8")*255
cv2.namedWindow('Demo19.10')
cv2.setMouseCallback('Demo19.10',draw)
while(1):
	cv2.imshow('Demo19.10',img)
	if cv2.waitKey(20)==27:
		break
cv2.destroyAllWindows()

在这里插入图片描述

2.2 进阶实例

鼠标事件为用户与计算机之间的交互提供了接口,让用户能够非常灵活地与计算机之间实现交互。本节通过一个鼠标与键盘配合的例子,展示如何实现用户与计算机的交互。

import numpy as np
thickness=-1
mode=1
d=400
def draw_circle(event,x,y,flags,param):
	if event==cv2.EVENT_LBUTTONDOWN:
		a=np.random.randint(1,d-50)
		r=np.random.randint(1,d/5)
		angle = np.random.randint(0,361)
		color = np.random.randint(0,high = 256,size = (3,)).tolist()
		if mode==1:
			cv2.rectangle(img,(x,y),(a,a),color,thickness)
		elif mode==2:
			cv2.circle(img,(x,y),r,color,thickness)
		elif mode==3:
			cv2.line(img,(a,a),(x,y),color,3)
		elif mode==4:
			cv2.ellipse(img, (x,y), (100,150), angle, 0, 360,color,thickness)
		elif mode==5:
			cv2.putText(img,'OpenCV',(0,round(d/2)),cv2.FONT_HERSHEY_SIMPLEX, 2,color,5)
img=np.ones((d,d,3),np.uint8)*255
cv2.namedWindow('image')
cv2.setMouseCallback('image',draw_circle)
while(1):
	cv2.imshow('image',img)
	k=cv2.waitKey(1)&0xFF
	if k==ord('r'):
		mode=1
	elif k==ord('c'):
		mode=2
	elif k==ord('l'):
		mode=3
	elif k==ord('e'):
		mode=4
	elif k==ord('t'):
		mode=5
	elif k==ord('f'):
		thickness=-1
	elif k==ord('u'):
		thickness=3
	elif k==27:
		break
cv2.destroyAllWindows()
  • 按下“r”键后,在窗体1内单击鼠标左键,会显示以当前鼠标位置为顶点,以任意位置为对角顶点的一个矩形。
  • 按下“c”键后,在窗体内单击鼠标左键,会显示以当前鼠标位置为圆心,以随机数为半径的一个圆。
  • 按下“l”键后,在窗体内单击鼠标左键,会显示以当前鼠标位置为端点,以任意位置为另一个端点的线段。
  • 按下“e”键后,在窗体内单击鼠标左键,会显示以当前鼠标位置为中心点,角度随机的一个椭圆。
  • 按下“t”键后,在窗体内单击鼠标左键,会在当前窗体内显示颜色随机的文字“OpenCV”。
    此外,还通过“f”键和“u”键控制各种图形是否为实心:
  • 按下“f”键后,图形为实心。
  • 按下“u”键后,图形为空心。

在这里插入图片描述

import cv2
import numpy as np

d=400
centerx=round(d/2)
centery=round(d/2)
r=50

def Demo(event,x,y,flags,param):
    global centerx,centery
    if flags==cv2.EVENT_FLAG_LBUTTON:
        if x>centerx-r and x<centerx+r and y>centery-r and y<centery+r:
            centerx=x
            centery=y
            global img
            img = np.ones((400,400,3),np.uint8)*255
            cv2.circle(img,(centerx,centery),r,(0,0,255),-1)
        print("yes")
            
# 创建名称为Demo 的响应(回调)函数OnMouseAction
img = np.ones((400,400,3),np.uint8)*255
cv2.circle(img,(centerx,centery),r,(0,0,255),-1)
cv2.namedWindow('test')
cv2.setMouseCallback('test',Demo)

while(1):
	cv2.imshow('test',img)
	if cv2.waitKey(20)==27:
		break
cv2.destroyAllWindows()

当鼠标按下左键拖动,且鼠标的坐标在圆范围内时,即可拖动圆的位置。

在这里插入图片描述

3. 滚动条

滚动条(Trackbar)在OpenCV 中是非常方便的交互工具,它依附于特定的窗口而存在。通过调节滚动条能够设置、获取指定范围内的特定值。

cv2.createTrackbar(trackbarname, winname, value, count, onChange)

  • trackbarname 为滚动条的名称。
  • winname 为滚动条所依附窗口的名称。
  • value 为初始值,该值决定滚动条中滑块的位置。
  • count 为滚动条的最大值。通常情况下,其最小值是0。
  • onChange 为回调函数。一般情况下,将滚动条改变后要实现的操作写在回调函数内。其中,回调函数的参数为滚动条拖动后的值。

函数 cv2.createTrackbar()用于生成一个滚动条。拖动滚动条,就可以设置滚动条的值,并让滚动条返回对应的值。滚动条的值可以通过函数cv2.getTrackbarPos()获取,其语法格式为:

retval=getTrackbarPos( trackbarname,winname )

  • retval 为返回值,获取函数cv2.createTrackbar()生成的滚动条的值。
  • trackbarname 为滚动条的名称。
  • winname 为滚动条所依附的窗口的名称。
3.1 用滚动条实现调色板
import cv2
import numpy as np
def changeColor(x):
	r=cv2.getTrackbarPos('R','image')
	g=cv2.getTrackbarPos('G','image')
	b=cv2.getTrackbarPos('B','image')
	img[:]=[b,g,r]
img=np.zeros((100,700,3),np.uint8)
cv2.namedWindow('image')
cv2.createTrackbar('R','image',0,255,changeColor)
cv2.createTrackbar('G','image',0,255,changeColor)
cv2.createTrackbar('B','image',0,255,changeColor)
while(1):
	cv2.imshow('image',img)
	k=cv2.waitKey(1)&0xFF
	if k==27:
		break
cv2.destroyAllWindows()

在这里插入图片描述

3.2 用滚动条控制阈值处理参数
import cv2
Type=0 # 阈值处理方式
Value=0 # 使用的阈值
def onType(a):
	Type= cv2.getTrackbarPos(tType, windowName)
	Value= cv2.getTrackbarPos(tValue, windowName)
	ret, dst = cv2.threshold(o, Value,255, Type)
	cv2.imshow(windowName,dst)
def onValue(a):
	Type= cv2.getTrackbarPos(tType, windowName)
	Value= cv2.getTrackbarPos(tValue, windowName)
	ret, dst = cv2.threshold(o, Value, 255, Type)
	cv2.imshow(windowName,dst)
o = cv2.imread("lena512.bmp",0)
windowName = "Demo19.13" #窗体名
cv2.namedWindow(windowName)
cv2.imshow(windowName,o)
# 创建两个滚动条
tType = "Type" # 用来选取阈值处理方式的滚动条
tValue = "Value" # 用来选取阈值的滚动条
cv2.createTrackbar(tType, windowName, 0, 4, onType)
cv2.createTrackbar(tValue, windowName,0, 255, onValue)
if cv2.waitKey(0) == 27:
	cv2.destroyAllWindows()

运行程序,在窗体对象内,同时显示控制阈值和阈值处理方式的两个滚动条。调整滚动条可以分别控制阈值处理时所使用的阈值和阈值处理方式。
在这里插入图片描述

3.3 用滚动条作为开关

有时也可将滚动条作为“开关”使用。此时,滚动条只有两种值“0”和“1”,当滚动条的值为0 时,代表False;当滚动条的值为1 时,代表True。

import cv2
import numpy as np
d=400
global thickness
thickness=-1
def fill(x):
	pass
def draw(event,x,y,flags,param):
	if event==cv2.EVENT_LBUTTONDBLCLK:
		p1x=x
		p1y=y
		p2x=np.random.randint(1,d-50)
		p2y=np.random.randint(1,d-50)
		color = np.random.randint(0,high = 256,size = (3,)).tolist()
		cv2.rectangle(img,(p1x,p1y),(p2x,p2y),color,thickness)
img=np.ones((d,d,3),np.uint8)*255
cv2.namedWindow('image')
cv2.setMouseCallback('image',draw)
cv2.createTrackbar('R','image',0,1,fill)
while(1):
	cv2.imshow('image',img)
	k=cv2.waitKey(1)&0xFF
	g=cv2.getTrackbarPos('R','image')
	if g==0:
		thickness=-1
	else:
		thickness=2
	if k==27:
		break
cv2.destroyAllWindows()

在这里插入图片描述

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值