【问题标题】:I would like to define a Region of Interest in a video and only process that area我想在视频中定义一个感兴趣的区域并只处理该区域
【发布时间】:2019-04-16 11:10:50
【问题描述】:

我在理解 opencv 中感兴趣的区域时遇到问题。我有一些代码可以从我的first_frame 中进行简单的背景减法。我还可以使用mouse_draw_rect 函数绘制一个矩形。

现在,我希望背景减法只发生在我绘制的矩形内,因为我想加快算法处理速度。我知道我必须设置某种感兴趣的区域,但我昨天和今天都尝试了,但我从教程中尝试过的都没有奏效。有人可以帮助指导我完成这个过程吗?

编辑:试图修复代码

import numpy as np
import cv2
import matplotlib.pyplot as plt

cap = cv2.VideoCapture(0)

_, first_frame = cap.read()

def mouse_draw_rect(event, x, y, flags, params):
    global point1, point2, drawing, first_frame, x1, x2, y1, y2
    if event == cv2.EVENT_LBUTTONDOWN:
        if drawing is False:
            drawing = True
            point1 = (x, y)
            x1 = (x)
            y1 = (y)
        else:
            drawing = False
    elif event == cv2.EVENT_MOUSEMOVE:
        if drawing is True:
            point2 = (x, y)
            x2 = (x)
            y2 = (y)
    elif event == cv2.EVENT_MBUTTONDOWN:
        first_frame = frame

drawing = False
point1 = ()
point2 = ()
x1 = ()
x2 = ()
y1 = ()
y2 = ()

cv2.namedWindow('Original')
cv2.setMouseCallback("Original", mouse_draw_rect)

while True:

    ret, frame = cap.read( )

    if point1 and point2:
        cv2.rectangle(frame, point1, point2, (0, 0, 0),5)


    difference = cv2.absdiff(first_frame[y1:y2, x1:x2], frame[y1:y2, x1:x2])
    difference = cv2.GaussianBlur(difference, (3, 3), 0)

    _, difference = cv2.threshold(difference, 18, 255, cv2.THRESH_BINARY)


    cv2.imshow('first frame (1)', first_frame)
    cv2.imshow('Original', frame)
    cv2.imshow('difference', difference)


    key = cv2.waitKey(30) & 0xff
    if key == 27:
        break

cap.release()
cv2.destroyAllWindows()

【问题讨论】:

    标签: python opencv matplotlib roi


    【解决方案1】:

    只需按您绘制的矩形中的区域进行裁剪。 而不是

    difference = cv2.absdiff(first_frame, frame)
    

    使用

    difference = cv2.absdiff(first_frame[y1:y2, x1:x2], frame[y1:y2, x1:x2])
    

    【讨论】:

    • 我可能犯了一个重大错误,但我试图应用您的建议,但它返回了一个未定义 y1 的错误。我更改了正文中的代码,以便您可以看到我添加的内容。
    • (x1, y1) 和 (x2, y2) 是您的 point1 和 point2。不要使用 x 和 y,使用您的命名
    • 所以我像这样提取值?差异 = cv2.absdiff(first_frame[point1[1]:point2[1],point1[0]:point2[0]], frame[point1[1]:point2[1],point1[0]:point2[0] ])
    • 不幸的是,当我将它添加到我的函数中时,它仍然不能将自身应用于矩形。我可能会休息一下,明天尝试解决它,感谢您的时间。
    【解决方案2】:

    主要问题在于 ROI 选择事件以及当前如何调用它。当前的实现不是动态的,这意味着我们无法可视化我们正在尝试选择的 ROI。此外,我们甚至在选择 ROI 之前就已经开始处理。

    选择 ROI 的正确方法是,一旦我们捕获了第一帧,注册鼠标单击事件并使用 imshowwaitKey(n) 无限期地可视化该帧,直到按下某个特定键。或者,我们可以通过使用waitKey(0)(未测试)在没有无限循环的情况下实现相同的效果。

    在这个阶段,我们应该能够绘制所需的 ROI 矩形。这里的关键因素是必须通过使用无限循环或waitKey(0) 来停止执行。仅仅注册活动是不够的。完成 ROI 选择后,继续执行其余代码。

    一些建议如下:

    • 尽可能避免使用全局变量
    • 为 ROI 选择创建单独的窗口,然后将其丢弃
    • 为每个单独的任务创建单独的函数

    以下是完整代码,演示了正确使用鼠标点击事件来选择视频处理的 ROI:

    import numpy as np
    import cv2
    import matplotlib.pyplot as plt
    
    
    ORIGINAL_WINDOW_TITLE = 'Original'
    FIRST_FRAME_WINDOW_TITLE = 'First Frame'
    DIFFERENCE_WINDOW_TITLE = 'Difference'
    
    
    canvas = None
    drawing = False # true if mouse is pressed
    
    #Retrieve first frame
    def initialize_camera(cap):
        _, frame = cap.read()
        return frame
    
    
    # mouse callback function
    def mouse_draw_rect(event,x,y,flags, params):
        global drawing, canvas
    
        if drawing:
            canvas = params[0].copy()
    
        if event == cv2.EVENT_LBUTTONDOWN:
            drawing = True
            params.append((x,y)) #Save first point
    
        elif event == cv2.EVENT_MOUSEMOVE:
            if drawing:
                cv2.rectangle(canvas, params[1],(x,y),(0,255,0),2)
    
        elif event == cv2.EVENT_LBUTTONUP:
            drawing = False
            params.append((x,y)) #Save second point
            cv2.rectangle(canvas,params[1],params[2],(0,255,0),2)
    
    
    def select_roi(frame):
        global canvas
        canvas = frame.copy()
        params = [frame]
        ROI_SELECTION_WINDOW = 'Select ROI'
        cv2.namedWindow(ROI_SELECTION_WINDOW)
        cv2.setMouseCallback(ROI_SELECTION_WINDOW, mouse_draw_rect, params)
        roi_selected = False
        while True:
            cv2.imshow(ROI_SELECTION_WINDOW, canvas)
            key = cv2.waitKey(10)
    
            #Press Enter to break the loop
            if key == 13:
                break;
    
    
        cv2.destroyWindow(ROI_SELECTION_WINDOW)
        roi_selected = (3 == len(params))
    
        if roi_selected:
            p1 = params[1]
            p2 = params[2]
            if (p1[0] == p2[0]) and (p1[1] == p2[1]):
                roi_selected = False
    
        #Use whole frame if ROI has not been selected
        if not roi_selected:
            print('ROI Not Selected. Using Full Frame')
            p1 = (0,0)
            p2 = (frame.shape[1] - 1, frame.shape[0] -1)
    
    
        return roi_selected, p1, p2
    
    
    
    
    if __name__ == '__main__':
    
        cap = cv2.VideoCapture(0)
    
        #Grab first frame
        first_frame = initialize_camera(cap)
    
        #Select ROI for processing. Hit Enter after drawing the rectangle to finalize selection
        roi_selected, point1, point2 = select_roi(first_frame)    
    
        #Grab ROI of first frame
        first_frame_roi = first_frame[point1[1]:point2[1], point1[0]:point2[0], :]
    
        #An empty image of full size just for visualization of difference
        difference_image_canvas = np.zeros_like(first_frame)
    
        while cap.isOpened():
    
            ret, frame = cap.read()
    
            if ret:
    
                #ROI of current frame
                roi = frame[point1[1]:point2[1], point1[0]:point2[0], :]
    
                difference = cv2.absdiff(first_frame_roi, roi)
                difference = cv2.GaussianBlur(difference, (3, 3), 0)
    
                _, difference = cv2.threshold(difference, 18, 255, cv2.THRESH_BINARY)
    
    
                #Overlay computed difference image onto the whole image for visualization
                difference_image_canvas[point1[1]:point2[1], point1[0]:point2[0], :] = difference.copy()
    
    
                cv2.imshow(FIRST_FRAME_WINDOW_TITLE, first_frame)
                cv2.imshow(ORIGINAL_WINDOW_TITLE, frame)
                cv2.imshow(DIFFERENCE_WINDOW_TITLE, difference_image_canvas)
    
    
                key = cv2.waitKey(30) & 0xff
                if key == 27:
                    break
            else:
                break
    
        cap.release()
        cv2.destroyAllWindows()
    

    专业提示: 有时,在初始化相机时,根据房间内的环境光,需要一些时间来预热。您可以考虑跳过一些初始帧,让相机从初始化阶段稳定下来。可以通过在上述代码中定义initialize_camera函数来完成,如下:

    def initialize_camera(cap):
        for i in range(0,60): #Skip first 60 frames
            _, frame = cap.read()
        return frame
    

    【讨论】:

    • 这是一个了不起的解释,谢谢。我会梳理你的代码,并尽可能多地从中学习。
    • @sentientnativeplant... 太好了。如果它解决了您的问题,您可以考虑接受答案,以便这篇文章可以从未回答的问题列表中删除,并帮助遇到相同问题的读者。 :)
    【解决方案3】:

    您可以在每一帧上使用subimage = image[y1:y2,x1:x2] 创建子图像,然后使用子图像进行处理。

    在你的代码中快速而肮脏的实现:

    替换
    elif event == cv2.EVENT_MOUSEMOVE:

    elif event == cv2.EVENT_LBUTTONUP:

    并添加子图像:

        if point1 and point2:
                cv2.rectangle(frame, point1, point2, (0, 0, 0),5)
                subimg = frame[point1[1]:point2[1],point1[0]:point2[0]]
                cv2.imshow("Subimage",subimg)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-08-10
      • 2012-02-22
      • 2013-03-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多