[英]Python OpenCV: mouse callback for drawing rectangle
我想保存视频 stream 中的图像,然后在显示的图像上绘制一个矩形以生成感兴趣区域。 稍后,将该 ROI 保存在一个文件中。 我使用 opencv python grabcut 示例来使用 setMouseCallback function。但我不知道我做错了什么,因为它没有给出我期望的结果。 我想看到在mouse input
window 中显示的 static 图像上绘制的绿色矩形,并将 roi 保存到文件中。 请帮助调试此代码或展示更好的方法:
import cv2
rect = (0,0,1,1)
rectangle = False
rect_over = False
def onmouse(event,x,y,flags,params):
global sceneImg,rectangle,rect,ix,iy,rect_over
# Draw Rectangle
if event == cv2.EVENT_LBUTTONDOWN:
rectangle = True
ix,iy = x,y
elif event == cv2.EVENT_MOUSEMOVE:
if rectangle == True:
cv2.rectangle(sceneImg,(ix,iy),(x,y),(0,255,0),2)
rect = (min(ix,x),min(iy,y),abs(ix-x),abs(iy-y))
elif event == cv2.EVENT_LBUTTONUP:
rectangle = False
rect_over = True
cv2.rectangle(sceneImg,(ix,iy),(x,y),(0,255,0),2)
rect = (min(ix,x),min(iy,y),abs(ix-x),abs(iy-y))
x1,y1,w,h = rect
roi = sceneImg[y1:y1+h, x1:x1+w]
cv2.imwrite('roi.jpg', roi)
# Named window and mouse callback
cv2.namedWindow('video')
cv2.namedWindow('mouse input')
cv2.setMouseCallback('mouse input',onmouse)
camObj = cv2.VideoCapture(-1)
keyPressed = None
running = True
scene = False
# Start video stream
while running:
readOK, frame = camObj.read()
keyPressed = cv2.waitKey(5)
if keyPressed == ord('s'):
scene = True
cv2.imwrite('sceneImg.jpg',frame)
sceneImg = cv2.imread('sceneImg.jpg')
cv2.destroyWindow('video')
cv2.imshow('mouse input', sceneImg)
elif keyPressed == ord('r'):
scene = False
cv2.destroyWindow('mouse input')
elif keyPressed == ord('q'):
running = False
if not scene:
cv2.imshow('video', frame)
cv2.destroyAllWindows()
camObj.release()
每次调用 {event == cv2.EVENT_MOUSEMOVE:} 时都需要重置图像。
您的代码应如下所示:
if event == cv2.EVENT_LBUTTONDOWN:
rectangle = True
ix,iy = x,y
elif event == cv2.EVENT_MOUSEMOVE:
if rectangle == True:
sceneImg = sceneImg2.copy()
cv2.rectangle(sceneImg,(ix,iy),(x,y),(0,255,0),2)
rect = (min(ix,x),min(iy,y),abs(ix-x),abs(iy-y))
elif event == cv2.EVENT_LBUTTONUP:
rectangle = False
rect_over = True
cv2.rectangle(sceneImg,(ix,iy),(x,y),(0,255,0),2)
rect = (min(ix,x),min(iy,y),abs(ix-x),abs(iy-y))
这是我当前的工作,我再次在EVENT_LBUTTONUP
渲染mouse input
窗口。 为了避免在保存到文件的 ROI 中出现边界框,我使用了输入场景的副本:
import cv2
rect = (0,0,1,1)
rectangle = False
rect_over = False
def onmouse(event,x,y,flags,params):
global sceneImg,rectangle,rect,ix,iy,rect_over, roi
# Draw Rectangle
if event == cv2.EVENT_LBUTTONDOWN:
rectangle = True
ix,iy = x,y
elif event == cv2.EVENT_MOUSEMOVE:
if rectangle == True:
# cv2.rectangle(sceneCopy,(ix,iy),(x,y),(0,255,0),1)
rect = (min(ix,x),min(iy,y),abs(ix-x),abs(iy-y))
elif event == cv2.EVENT_LBUTTONUP:
rectangle = False
rect_over = True
sceneCopy = sceneImg.copy()
cv2.rectangle(sceneCopy,(ix,iy),(x,y),(0,255,0),1)
rect = (min(ix,x),min(iy,y),abs(ix-x),abs(iy-y))
roi = sceneImg[rect[1]:rect[1]+rect[3], rect[0]:rect[0]+rect[2]]
cv2.imshow('mouse input', sceneCopy)
cv2.imwrite('roi.jpg', roi)
# Named window and mouse callback
cv2.namedWindow('mouse input')
cv2.setMouseCallback('mouse input',onmouse)
cv2.namedWindow('video')
camObj = cv2.VideoCapture(-1)
keyPressed = None
running = True
scene = False
# Start video stream
while running:
readOK, frame = camObj.read()
keyPressed = cv2.waitKey(5)
if keyPressed == ord('s'):
scene = True
cv2.destroyWindow('video')
cv2.imwrite('sceneImg.jpg',frame)
sceneImg = cv2.imread('sceneImg.jpg')
cv2.imshow('mouse input', sceneImg)
elif keyPressed == ord('r'):
scene = False
cv2.destroyWindow('mouse input')
elif keyPressed == ord('q'):
running = False
if not scene:
cv2.imshow('video', frame)
cv2.destroyAllWindows()
camObj.release()
因此,我可以可视化应该绑定 ROI 的矩形,但我仍然不知道如何在鼠标左键按下且鼠标光标移动时可视化边界框。 该可视化在抓取示例中有效,但在我的案例中我无法弄清楚。 在EVENT_MOUSEMOVE
期间取消注释绘制矩形的线后,我会在图像上绘制多个矩形。 如果有人回答了一种在创建时可视化单个矩形的方法,我可以接受。
您可以使用opencv提供的内置功能:
roi = cv2.selectROI(image)
它创建/显示“ ROI选择”窗口,显示框架。 使用鼠标选择边界框,将鼠标指针从左上角拖动到右下角。
该函数有几个不需要的参数:
selectROI(windowName, img[, showCrosshair[, fromCenter]]) -> retval
windowName
将显示选择过程的窗口的名称。 img
图像以选择ROI。 showCrosshair
。 fromCenter
参数,如果选择的真实中心将与鼠标的初始位置匹配。 在相反的情况下,选择矩形的角将对应于鼠标的初始位置。 返回选定的ROI或空白矩形(如果取消选择)。
控制:使用space
或enter
键完成选择,使用键c
取消选择。
重载的函数不需要windowName
。
selectROI(img[, showCrosshair[, fromCenter]]) -> retval
基于@Marco167 提供的答案,我将只更改一行,否则会出现 object 参考问题。
因此,我建议sceneImg[:] = sceneImg2[:]
而不是sceneImg = sceneImg2.copy()
,其中sceneImg2
应该是相同的,单独加载的图像,例如:
sceneImg = cv2.imread('sceneImg.jpg')
sceneImg2 = cv2.imread('sceneImg.jpg')
此外,我已将rectangle
检查移至该条件。
这种方式在鼠标移动时,首先重绘原始图像(从而删除现有矩形)并绘制矩形。 将鼠标移动一个像素,您将再次重绘原始图片,删除任何矩形并再次绘制一个矩形。 在任何给定点,都只有一个矩形。
是的,7 年多后回复,以防万一有人发现它有用:)
把它们放在一起:
if event == cv2.EVENT_LBUTTONDOWN:
rectangle = True
ix,iy = x,y
elif event == cv2.EVENT_MOUSEMOVE and rectangle :
sceneImg[:] = sceneImg2[:]
cv2.rectangle(sceneImg,(ix,iy),(x,y),(0,255,0),2)
rect = (min(ix,x),min(iy,y),abs(ix-x),abs(iy-y))
elif event == cv2.EVENT_LBUTTONUP:
rectangle = False
rect_over = True
cv2.rectangle(sceneImg,(ix,iy),(x,y),(0,255,0),2)
rect = (min(ix,x),min(iy,y),abs(ix-x),abs(iy-y))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.