【问题标题】:OpenCV: How to draw on just the first frame of a video file and then continue showing the entire videoOpenCV:如何仅在视频文件的第一帧上绘制,然后继续显示整个视频
【发布时间】:2019-05-17 18:57:32
【问题描述】:

我在 python 中使用 opencv 库。我打开了一个现有的视频文件并编写了一个小脚本,允许我在视频的任何位置绘制一个矩形。问题是:我想在视频的第一帧上绘制这个矩形,然后把它留在那里为我标记一个感兴趣的区域。

我正在使用cv2.imshow(winname, frame) 来展示我的视频。由于它以每秒非常高的帧速率运行/显示视频(我不想改变它,因为我的视频很长),当我开始绘制矩形时,已经显示了许多帧。

因为我认为这可能会有所帮助,所以这是我目前的代码: 导入cv2

#mouse callback function#
def draw_rectangle(event, x, y, flags, param):

    global pt1, pt2, topLeft_clicked, bottomRight_clicked

    #mouse click
    if event == cv2.EVENT_LBUTTONDOWN:
        #reset
        if topLeft_clicked and bottomRight_clicked:
            topLeft_clicked = False
            bottomRight_clicked = False
            pt1 = (0,0)
            pt2 = (0,0)
        #get coordinates of top left corner
        if not topLeft_clicked:
            pt1 = (x,y)
            topLeft_clicked = True
        #get coordinates of bottom right corner
        elif not bottomRight_clicked:
            pt2 = (x,y)
            bottomRight_clicked = True

#start actual program 

#initially we haven't drawn anything
pt1 = (0,0)
pt2 = (0,0)
topLeft_clicked = False
bottomRight_clicked = False

#capture video
cap = cv2.VideoCapture('Path to video')
cv2.namedWindow(winname='myName')
cv2.setMouseCallback('myName', draw_rectangle)

firstFrame = True
while True: 
    ret, frame = cap.read()
    gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    while ret and firstFrame: 
        cv2.imshow('myName', gray_frame)

        if topLeft_clicked: 
            cv2.circle(gray_frame, center=pt1, radius=5, color=(255,0,0), thickness=-1)

        if topLeft_clicked and bottomRight_clicked: 
            cv2.rectangle(gray_frame, pt1, pt2, (255,0,0), 2)
            firstFrame = False

    cv2.imshow('Estimate_Velocity', gray_frame)

    if cv2.waitKey(1) &0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

【问题讨论】:

  • 如果您想对视频文件进行视频流式传输,但又想绘制 ROI 矩形,则必须在每一帧上都这样做。这是因为当您使用cv2.imshow 时,它会覆盖前一帧。另一种方法是打开另一个窗口,该窗口仅显示带有矩形的第一帧
  • @nathancy:真的吗?到目前为止,我在一个命名窗口中打开了视频。然后我使用回调函数(鼠标点击回调)在这个窗口中绘制我的矩形。它工作正常,我想我只是画了一次矩形。这里的问题是,当我的视频已经显示了这么多帧时,我已经完成了矩形的绘制。我想先画矩形
  • 另外:我想在第一帧上绘制这个矩形,这样我就可以使用坐标 pt1 和 pt2 来声明我可以执行某些操作的 ROI,例如阈值。不知道有没有效果
  • 我刚刚编辑了我认为应该如何工作的代码。但事实并非如此。我的窗口打开了,python 崩溃了

标签: python opencv video-capture


【解决方案1】:

我做了一点实验,找到了以下解决我的问题的方法:

import cv2

#mouse callback function#
def draw_rectangle(event, x, y, flags, param):

    global pt1, pt2, topLeft_clicked, bottomRight_clicked

    #mouse click
    if event == cv2.EVENT_LBUTTONDOWN:
        #reset
        if topLeft_clicked and bottomRight_clicked:
            topLeft_clicked = False
            bottomRight_clicked = False
            pt1 = (0,0)
            pt2 = (0,0)
        #get coordinates of top left corner
        if not topLeft_clicked:
            pt1 = (x,y)
            topLeft_clicked = True
        #get coordinates of bottom right corner
        elif not bottomRight_clicked:
            pt2 = (x,y)
            bottomRight_clicked = True

#start actual program 

#initially we haven't drawn anything
pt1 = (0,0)
pt2 = (0,0)
topLeft_clicked = False
bottomRight_clicked = False

#capture video
cap = cv2.VideoCapture('Video path')
cv2.namedWindow(winname='myName')
cv2.setMouseCallback('myName', draw_rectangle)

firstFrame = True
while True: 
    ret, frame = cap.read()
    gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    while firstFrame: 
        cv2.imshow('myName', gray_frame)

        if topLeft_clicked: 
            cv2.circle(gray_frame, center=pt1, radius=5, color=(255,0,0), thickness=-1)

        if topLeft_clicked and bottomRight_clicked: 
            cv2.rectangle(gray_frame, pt1, pt2, (255,0,0), 2)

        if cv2.waitKey(1) &0xFF == ord('c'):
            firstFrame = False
            break

    if topLeft_clicked and bottomRight_clicked: 
        cv2.rectangle(gray_frame, pt1, pt2, (255,0,0), 2)

    cv2.imshow('myName', gray_frame)

    if cv2.waitKey(1) &0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

【讨论】:

    【解决方案2】:

    我还没有测试过这个,但是你可以修改你的while循环中断条件:

    if cv2.waitKey(1) &0xFF == ord('q'):
              break
    

    if (topLeft_clicked and bottomRight_clicked):
        if cv2.waitKey(1)  &0xFF == ord('q'):
            break
    else:
         # change 1 to 0
         cv2.waitKey(0)
    

    你需要在画完方框后按一个键。

    【讨论】:

    • 这根本不起作用。我收到一条错误消息,说我的 src 为空(对于 cv2.cvtColor)。另外,我认为这不能解决我的问题
    • 其实我最初的想法和你的差不多,我也做了好几次。我只是忘了把while 放在那里。无论如何,已针对不同的解决方案进行了更新。
    猜你喜欢
    • 1970-01-01
    • 2016-05-05
    • 2021-12-03
    • 1970-01-01
    • 1970-01-01
    • 2019-04-02
    • 2016-04-13
    • 1970-01-01
    • 2016-05-26
    相关资源
    最近更新 更多