繁体   English   中英

Python OpenCV:绘制矩形的鼠标回调

[英]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
  • param windowName将显示选择过程的窗口的名称。
  • 参数img图像以选择ROI。
  • 如果显示选择矩形的真实十字线,则参数showCrosshair
  • fromCenter参数,如果选择的真实中心将与鼠标的初始位置匹配。 在相反的情况下,选择矩形的角将对应于鼠标的初始位置。

返回选定的ROI或空白矩形(如果取消选择)。

控制:使用spaceenter键完成选择,使用键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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM