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

23c0lvtd  于 2022-11-24  发布在  Python
关注(0)|答案(3)|浏览(169)

我想保存视频流中的一幅图像,然后在显示的图像上画一个矩形以产生感兴趣的区域,稍后,我用opencv python grabcut例子来使用setMouseCallback函数,但是我不知道我做错了什么,因为它没有给出我期望的结果。我希望看到在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

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

kupeojn61#

每次调用{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))
6ojccjat

6ojccjat2#

这是我目前的工作,我再次渲染EVENT_LBUTTONUP窗口在EVENT_LBUTTONUP上。为了避免边界框出现在保存到文件的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的矩形,但我仍然不知道如何在按下鼠标左键并移动鼠标光标时可视化包围框。该可视化在grabcut示例中有效,但在我的示例中无法理解。在EVENT_MOUSEMOVE期间取消注解绘制矩形的行时,我得到了多个绘制到图像上的矩形。如果有人回答一个方法,可视化一个单一的矩形,因为它正在创建我可以接受它。

v440hwme

v440hwme3#

在@Marco167提供的答案的基础上,我将只更改一行,否则会出现对象引用问题。
因此,我建议使用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))

相关问题