以下代码功能:创建窗口、在给定窗口显示图像、并在窗口上动态绘制直线、矩形、圆,类似labelme等标注工具画标注框。
缺陷:内存占用过高,有待优化,欢迎讨论并改进。
import numpy as np
import cv2
#1、创建窗口
cv2.namedWindow("demo1", cv2.WINDOW_NORMAL)
cv2.resizeWindow("demo1", 640, 480)
#2、创建图像、亦可cv2.imread读入
img = np.zeros((480, 640, 3), np.uint8)
img_backup = img.copy() #img的备份,防止画出叠叠框(类似千手观音)
start_point=(0,0)#起始点
state=-1 #标记量,0则画直线,1则画矩形,2则画圆
drawing=False #标记量、True表示开始画,False表示结束画
def onMouse(event, x, y, flags, param): #鼠标监听函数
global start_point,state,drawing,img,img_backup #局部变量全局化
if event==cv2.EVENT_LBUTTONDOWN: # 鼠标左键按下
drawing=True
start_point = (x, y)
elif event==cv2.EVENT_MOUSEMOVE: #鼠标移动
if drawing:#进入该层判断,改变了img,显示后要改回来,具体改回来的位置要位于图像显示之后
if state==0:
cv2.line(img, start_point, (x,y), (255,0,0), 2)
elif state==1:
cv2.rectangle(img, start_point, (x,y), (0,255,0), 2)
elif state==2:
radius=int(((start_point[0]-x)**2+(start_point[1]-y)**2)**0.5)
cv2.circle(img, start_point, radius, (0,0,255), 2)
else:
print(f"state error: {state}")
elif event==cv2.EVENT_LBUTTONUP: #鼠标左键抬起,只有进入此判断img才允许被改变
drawing=False
if state==0:
cv2.line(img, start_point, (x,y), (255,0,0), 2)
elif state==1:
cv2.rectangle(img, start_point, (x,y), (0,255,0), 2)
elif state==2:
radius=int(((start_point[0]-x)**2+(start_point[1]-y)**2)**0.5)
cv2.circle(img, start_point, radius, (0,0,255), 2)
else:
print(f"state error: {state}")
img_backup=img.copy() # 备份图像更新
cv2.setMouseCallback("demo1",onMouse) #窗口和鼠标监听函数绑定
while True:
cv2.imshow("demo1", img)
if drawing:# 开始画后,鼠标移动,画完后吧img还原
img=img_backup.copy()
key = cv2.waitKey(1)
if key==ord('q'):#按q退出
break
elif key==ord('l'):#按'l'画line
state=0
elif key==ord('r'):#按'r'画rectangle
state=1
elif key==ord('c'):#按'c'画circle
state=2
cv2.destroyAllWindows()#窗口销毁