我想在视频中定义一个感兴趣的区域,只处理该区域

问题描述 投票:1回答:3

我在了解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
3个回答
0
投票

主要问题是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

1
投票

只需按您绘制的矩形区域进行裁剪即可。代替

difference = cv2.absdiff(first_frame, frame)

使用

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

0
投票

在每个帧上,您可以使用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)
© www.soinside.com 2019 - 2024. All rights reserved.