opencv 绘图及交互(python)

Posted 暴风雨中的白杨

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了opencv 绘图及交互(python)相关的知识,希望对你有一定的参考价值。

绘图及交互

Opencv提供了方便的绘图功能,使用其中的绘图函数可以绘制直线、矩形、圆、椭圆等多种几何图形,还能在图像中的指定位置添加文字说明。

OpenCV提供了鼠标事件,使用户可以通过鼠标与图像交互。鼠标事件能够识别常用的鼠标操作,例如:针对不同按键的单击、双击,鼠标的滑动、拖曳等。

OpenCV还提供了滚动条用于实现交互功能。用户可以拖动滚动条在某一个范围内设置特定的值,并将该值应用于后续的图像处理中。而且,如果设置为二值形式,滚动条还可以作为开关选择器使用。

绘画基础

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连接类型。

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

OpenCV提供了函数cv2.line()用来绘制直线(线段)。

该函数的语法格式为:

img = cv2.line( img, pt1, pt2, color[, thickness[, lineType ]])
  • 参数img、color、thickness、lineType的含义如前面的说明所示。
  • pt1表示线段的第1个点(起点)。
  • pt2表示线段的第2个点(终点)。

使用cv2.line()函数在一个黑色背景图像内绘制三条线段。

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)  
cv2.namedWindow("test") 
cv2.imshow("test", img) 
cv2.waitKey(0) 
cv2.destroyAllWindows() 

绘制矩形

OpenCV提供了函数cv2.rectangle()用来绘制矩形。

该函数的语法格式为:

img = cv2.rectangle( img, pt1, pt2, color[, thickness[, lineType]] )
  • 参数img、color、thickness、lineType的含义如前面的说明所示。
  • pt1为矩形顶点。
  • pt2为矩形中与pt1对角的顶点。

使用函数cv2.rectangle()在一个白色背景图像内绘制一个实心矩形。

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 = test 
cv2.namedWindow(winname) 
cv2.imshow(winname, img) 
cv2.waitKey(0) 
cv2.destroyAllWindows() 

绘制圆形

OpenCV提供了函数cv2.circle()用来绘制圆。

该函数的语法格式为:

img = cv2.circle( img, center, radius, color[, thickness[, lineType]] ) 
  • 参数img、color、thickness、lineType的含义如前面的说明所示。
  • center为圆心。
  • radius为半径。

使用函数cv2.circle()在一个白色背景图像内绘制一组同心圆。

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("test", img) 
cv2.waitKey(0) 
cv2.destroyAllWindows() 

绘制椭圆

OpenCV提供了函数cv2.ellipse()用来绘制椭圆。

该函数的语法格式为:

img=cv2.ellipse(img, center, axes, angle, startAngle, endAngle, color[, thickness[, lineType]]) 
  • 参数img、color、thickness、lineType的含义如前面的说明所示。
  • center为椭圆的圆心坐标。
  • axes为轴的长度。有两个轴,所以是个元组
  • angle为偏转的角度。
  • startAngle为圆弧起始角的角度
  • endAngle为圆弧终结角的角度

使用函数cv2.ellipse()在一个白色背景图像内随机绘制一组空心椭圆。

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("test", img) 
cv2.waitKey(0) 
cv2.destroyAllWindows() 

绘制多边形

cv2.polylines()用来绘制多边形。

该函数的语法格式为:

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

在使用函数cv2.polylines()绘制多边形时,需要给出每个顶点的坐标。

这些点的坐标构建了一个大小等于“顶点个数12”的数组,这个数组的数据类型必须为numpy.int32。

使用函数cv2.polylines()在一个白色背景图像内绘制一个多边形。

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("test", img) 
cv2.waitKey(0) 
cv2.destroyAllWindows() 

可以使用函数cv2.polylines()来绘制多条首尾相连的线段。只要把线段的各个点放在一个数组中,将这个数组传给函数cv2.polylines()的第2个参数pts,并且isClosed为False。

绘制文字

OpenCV提供了函数cv2.putText()用来在图形上绘制文字。

该函数的语法格式为:

img=cv2.putText(img, text, org, fontFace, fontScale, color[, thickness[, lineType[, bottomLeftOrigin]]]) 
  • 参数img、color、thickness、lineType和shift的含义如前面的说明所示。

  • text为要绘制的文本。

  • org为绘制字体的位置,以文字的左下角为起点。

  • fontFace表示字体类型

  • fontScale表示字体大小。

  • bottomLeftOrigin用于控制文字的方向。默认值为False,当设置为True时,文字是垂直镜像的效果。

使用函数cv2.putText()在一个白色背景图像内绘制文字。

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("test", 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.LINE_8, True)
cv2.imshow("test", img) 
cv2.waitKey(0) 
cv2.destroyAllWindows() 

参数bottomLeftOrigin的值被设置为True,实现绘制镜像文字效果

鼠标交互

用户单击鼠标,就画一个圆。通常的做法是,创建一个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 
# 将响应函数Demo与窗口“test”建立连接(实现绑定) 
img = np.ones((300,300,3), np.uint8)*255 
cv2.namedWindow(test) 
cv2.setMouseCallback(test, Demo) 
cv2.imshow(test, img) 
cv2.waitKey() 
cv2.destroyAllWindows() 

按住鼠标左键拖动鼠标,会依次触发单击左键事件“cv2.EVENT_LBUTTONDOWN”和左键拖动事件“cv2.EVENT_FLAG_LBUTTON”

例子: 实现一个双击鼠标绘制矩形的简单程序。

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(test) 
cv2.setMouseCallback(test, draw)

while(1): 
    cv2.imshow(test, img)   # 刷新界面
    if cv2.waitKey(20)==27: 
        break 
cv2.destroyAllWindows() 

例子: 通过键盘与鼠标的组合控制显示不同的形状或文字。

import cv2 
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() 

滚动条

滚动条(Trackbar)在OpenCV中是非常方便的交互工具,它依附于特定的窗口而存在。

通过调节滚动条能够设置、获取指定范围内的特定值。

在OpenCV中,函数cv2.createTrackbar()用来定义滚动条,其语法格式为:

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为滚动条所依附的窗口的名称。
用滚动条实现调色板

在RGB颜色空间中,任何颜色都是由红(R)、绿(G)、蓝(B)三种颜色构成的,每一种颜色分量的区间是[0, 255]。

用函数cv2.createTrackbar()和函数cv2.getTrackbarPos()设计一个模拟调色板:在窗体中,有三个滚动条分别用来设置R、G、B的值,调色板会根据当前的R、G、B值实时显示其所对应的颜色。

设计一个滚动条交互程序,通过滚动条模拟调色板效果。

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() 

用滚动条控制阈值处理参数

设计一个滚动条交互程序,通过滚动条控制函数cv2.threshold()中的阈值和模式。

回顾一下函数cv2.threshold()的语法格式:

retval, dst=cv2.threshold(src, thresh, maxval, type)
  • src:源图像。
  • thresh:阈值。
  • maxval:当type参数的值为THRESH_BINARY或者THRESH_BINARY_INV时,需要设定的最大值。
  • type:阈值处理的方式(类型)
  • dst:处理结果
  • retval:返回的阈值
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("./img/hand1.png",0) 
windowName = "test"  #窗体名 
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() 

用滚动条作为开关

滚动条只有两种值“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) 

    g=cv2.getTrackbarPos(R, image) 
    if g==0: 
        thickness=-1 
    else: 
        thickness=2
    k=cv2.waitKey(1)&0xff
    if k==27: 
        break 
cv2.destroyAllWindows() 

以上是关于opencv 绘图及交互(python)的主要内容,如果未能解决你的问题,请参考以下文章

使用Python,Opencv绘制调色板及圆形来模拟霓虹的渐变效果

在 OpenCV python 中将白色像素转换为黑色

[opencv][原创]python opencv创建白色图像并画个框

使用Python,OpenCV对图像进行亚像素点检测,并拟合椭圆进行绘制

怎么用OpenCV编程实现输出白色像素点的坐标值

Python-OpenCV 中的绘图函数