我想在视频中定义一个感兴趣区域并只处理该区域
I would like to define a Region of Interest in a video and only process that area
我在理解 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()
只需按您绘制的矩形中的区域裁剪即可。
而不是
difference = cv2.absdiff(first_frame, frame)
使用
difference = cv2.absdiff(first_frame[y1:y2, x1:x2], frame[y1:y2, x1:x2])
在每一帧你可以使用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)
主要问题在于 ROI selection 事件及其当前的调用方式。当前的实施不是动态的,这意味着我们无法想象我们试图达到的 ROI select。此外,我们甚至在 select 投资回报率之前就开始处理了。
select ROI 的正确方法是,一旦我们捕获了第一帧,注册鼠标单击事件并使用 imshow
和 waitKey(n)
无限期地可视化帧,直到一些特定键被按下。或者,我们可以通过使用 waitKey(0)
(未测试)在没有无限循环的情况下实现相同的效果。
在这个阶段,我们应该能够绘制出想要的ROI矩形。这里的关键因素是执行 必须 通过使用无限循环或 waitKey(0)
停止。仅仅注册事件是不够的。 ROI selection完成后,再继续剩下的代码。
部分推荐如下:
- 尽可能避免使用全局变量
- 为 ROI select离子创建单独的 window 并在之后丢弃它
- 为每个单独的任务创建单独的函数
以下是演示如何正确使用鼠标单击事件的完整代码 select 视频处理的 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
我在理解 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()
只需按您绘制的矩形中的区域裁剪即可。 而不是
difference = cv2.absdiff(first_frame, frame)
使用
difference = cv2.absdiff(first_frame[y1:y2, x1:x2], frame[y1:y2, x1:x2])
在每一帧你可以使用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)
主要问题在于 ROI selection 事件及其当前的调用方式。当前的实施不是动态的,这意味着我们无法想象我们试图达到的 ROI select。此外,我们甚至在 select 投资回报率之前就开始处理了。
select ROI 的正确方法是,一旦我们捕获了第一帧,注册鼠标单击事件并使用 imshow
和 waitKey(n)
无限期地可视化帧,直到一些特定键被按下。或者,我们可以通过使用 waitKey(0)
(未测试)在没有无限循环的情况下实现相同的效果。
在这个阶段,我们应该能够绘制出想要的ROI矩形。这里的关键因素是执行 必须 通过使用无限循环或 waitKey(0)
停止。仅仅注册事件是不够的。 ROI selection完成后,再继续剩下的代码。
部分推荐如下:
- 尽可能避免使用全局变量
- 为 ROI select离子创建单独的 window 并在之后丢弃它
- 为每个单独的任务创建单独的函数
以下是演示如何正确使用鼠标单击事件的完整代码 select 视频处理的 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