我正在尝试使用鼠标作为输入在Python中使用Opencv绘制矩形。我从opencv文档中创建了这段代码。绘制矩形时有问题,当您尝试从起点矩形拖动时一直绘制到终点。就像我在图像中展示的那样。
如何绘制干净的未填充矩形?在那里我可以看到绘制一个实际的矩形。就像我们在Paint中做的那样
import cv2
import numpy as np
drawing = False
ix,iy = -1,-1
def draw_rect(event,x,y,flags,param):
global ix,iy,drawing,mode
if event == cv2.EVENT_LBUTTONDOWN:
drawing = True
ix,iy = x,y
elif event == cv2.EVENT_MOUSEMOVE:
if drawing == True:
cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),1)
elif event == cv2.EVENT_LBUTTONUP:
drawing = False
cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),1)
img = np.zeros((512,512,3), np.uint8)
cv2.namedWindow('image')
cv2.setMouseCallback('image',draw_rect)
while(1):
cv2.imshow('image',img)
k = cv2.waitKey(1) & 0xFF
if k == 27:
break
cv2.destroyAllWindows()
谁能告诉我为什么会这样?有什么解决方案??
答案 0 :(得分:3)
在event == cv2.EVENT_MOUSEMOVE
期间移动鼠标时,您还会同时绘制recatngle cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),1)
。
尝试以下代码。
import cv2
import numpy as np
drawing = False # true if mouse is pressed
mode = True # if True, draw rectangle.
ix,iy = -1,-1
# mouse callback function
def draw_circle(event,x,y,flags,param):
global ix,iy,drawing,mode
if event == cv2.EVENT_LBUTTONDOWN:
drawing = True
ix,iy = x,y
elif event == cv2.EVENT_MOUSEMOVE:
if drawing == True:
if mode == True:
cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),3)
a=x
b=y
if a != x | b != y:
cv2.rectangle(img,(ix,iy),(x,y),(0,0,0),-1)
else:
cv2.circle(img,(x,y),5,(0,0,255),-1)
elif event == cv2.EVENT_LBUTTONUP:
drawing = False
if mode == True:
cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),2)
else:
cv2.circle(img,(x,y),5,(0,0,255),-1)
img = np.zeros((512,512,3), np.uint8)
cv2.namedWindow('image')
cv2.setMouseCallback('image',draw_circle)
while(1):
cv2.imshow('image',img)
k = cv2.waitKey(1) & 0xFF
if k == ord('m'):
mode = not mode
elif k == 27:
break
cv2.destroyAllWindows()
希望它能解决你的问题。欢呼声。
预期产出:
上面的代码只能用于黑色背景图像。但我们可以在任何图像上绘制矩形 -
尝试以下代码。
# import the necessary packages
import cv2
import argparse
# now let's initialize the list of reference point
ref_point = []
def shape_selection(event, x, y, flags, param):
# grab references to the global variables
global ref_point, crop
# if the left mouse button was clicked, record the starting
# (x, y) coordinates and indicate that cropping is being performed
if event == cv2.EVENT_LBUTTONDOWN:
ref_point = [(x, y)]
# check to see if the left mouse button was released
elif event == cv2.EVENT_LBUTTONUP:
# record the ending (x, y) coordinates and indicate that
# the cropping operation is finished
ref_point.append((x, y))
# draw a rectangle around the region of interest
cv2.rectangle(image, ref_point[0], ref_point[1], (0, 255, 0), 2)
cv2.imshow("image", image)
# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True, help="Path to the image")
args = vars(ap.parse_args())
# load the image, clone it, and setup the mouse callback function
image = cv2.imread(args["image"])
clone = image.copy()
cv2.namedWindow("image")
cv2.setMouseCallback("image", shape_selection)
# keep looping until the 'q' key is pressed
while True:
# display the image and wait for a keypress
cv2.imshow("image", image)
key = cv2.waitKey(1) & 0xFF
# press 'r' to reset the window
if key == ord("r"):
image = clone.copy()
# if the 'c' key is pressed, break from the loop
elif key == ord("c"):
break
# close all open windows
cv2.destroyAllWindows()
将文件另存为capture_events.py
并进行测试,我们选择了位于同一目录的演示图片。现在按照 -
python capture_events.py --image demo.jpg
预期产出:
如果出于某种原因我们想要重新选择图片的任何部分,我们只需按下' r'摆脱糟糕的选择尝试一个新的。
希望,它会提供更多帮助。检查此gist,您可以在此实现更多功能。欢呼声。
答案 1 :(得分:0)
您可以将鼠标事件更改为类似的内容
elif event == cv2.EVENT_MOUSEMOVE:
if drawing==True:
copy = image.copy()
cv2.rectangle(copy,(ix,iy),(x,y),(0,255,0),1)
cv2.imshow("image", copy)
脚本将基于当前的x和y创建带有矩形的图像副本,并显示实时效果
答案 2 :(得分:0)
我设法使用副本解决了这个问题。现在,仅需一个imshow()更新即可使用。使用全局变量可能不是最好的方法。
import cv2 as cv
drawing = False
ix, iy = -1, -1
def draw_markers(event, x, y, flags, param):
global ix, iy, drawing, frame, frame_copy
if flags == cv.EVENT_FLAG_ALTKEY + cv.EVENT_FLAG_LBUTTON:
if event == cv.EVENT_LBUTTONDOWN:
print("Alt + lmouse down")
drawing = True
ix, iy = x, y
frame_copy = frame.copy()
elif event == cv.EVENT_MOUSEMOVE:
if drawing:
frame = cv.rectangle(
frame_copy.copy(), (ix, iy), (x, y), (0, 255, 0), 2)
elif event == cv.EVENT_LBUTTONUP:
print("Alt + lmouse up")
drawing = False
cv.rectangle(frame, (ix, iy), (x, y), (0, 255, 0), 2)
elif event == cv.EVENT_LBUTTONUP:
print("Draw crosshair")
cv.drawMarker(frame, (x, y), (255, 0, 0), 0, 16, 2, 8)
cap = cv.VideoCapture('video.avi')
cap.set(cv.CAP_PROP_POS_FRAMES, 1)
ret, frame = cap.read()
frame_copy = frame.copy()
cv.namedWindow('frame')
cv.setMouseCallback('frame', draw_markers)
while(True):
cv.imshow('frame', frame)
if cv.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv.destroyAllWindows()
答案 3 :(得分:0)
基于先前的答案,我设法创建了一个脚本,可以在图像上绘制矩形和任意大小的圆。在按住鼠标左键的同时四处移动鼠标会更新矩形。通过分别按r或t,圆会变大或变小。按“ m”在模式之间切换。按“ x”重置图像(删除您绘制的所有内容)。 这是代码,显然可以进行更多优化,我将继续努力。
import cv2
import numpy as np
drawing = False # true if mouse is pressed
mode = True # if True, draw rectangle. Press 'm' to toggle to curve
ix,iy = -1,-1
x_, y_ = 0,0
r = 15 #circle radius
# mouse callback function
def draw_shape(event,x,y,flags,param):
print(event)
global ix,iy,drawing,mode,x_,y_, r
if event == cv2.EVENT_LBUTTONDOWN:
print('inside mouse lbutton event....')
drawing = True
ix,iy = x,y
x_,y_ = x,y
elif event == cv2.EVENT_MOUSEMOVE and drawing:
copy = img.copy()
x_,y_ = x,y
if mode:
cv2.rectangle(copy,(ix,iy),(x_,y_),(0,255,0),1)
cv2.imshow("image", copy)
else:
cv2.circle(copy,(x,y),r,(0,0,255),1)
cv2.imshow('image', copy)
#
elif event == cv2.EVENT_LBUTTONUP:
print('inside mouse button up event')
drawing = False
if mode:
cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),1)
else:
cv2.circle(img,(x,y),r,(0,0,255),1)
img = np.zeros((512,512,3), np.uint8)
temp_img = np.copy(img)
cv2.namedWindow('image')
cv2.setMouseCallback('image',draw_shape)
while(1):
# print('inside while loop...')
cv2.imshow('image',img)
if not cv2.EVENT_MOUSEMOVE:
copy = img.copy()
# print('x_: , y_ : '.format(x_,y_))
print(x_)
if mode == True:
cv2.rectangle(copy,(ix,iy),(x_,y_),(0,255,0),1)
cv2.imshow('image',copy)
else:
cv2.circle(copy,(x_,y_),r,(0,0,255),1)
cv2.imshow('image',copy)
k = cv2.waitKey(1) & 0xFF
if k == ord('m'): #toggle between circle and rectangle
mode = not mode
x_,y_ = -10,-10
ix,iy = -10,-10
elif k == ord('r') and not mode: #make circle bigger
r += 1
elif k == ord('t') and not mode: #make circle smaller
if r <=2:
r = 1
else:
r -= 1
elif k == ord('x'): #resets the image (removes circles and rectangles)
img = np.copy(temp_img)
x_,y_ = -10,-10
ix,iy = -10,-10
elif k == 27:
break
cv2.destroyAllWindows()