As @vvanpelt mentioned, cv2.selectROI()
causes the video capture being blocked and there is a need to handle the selection of the ROI in other way.
Here I provide a different solution which is more like how cv2.selectROI()
works with images, emulating in some way its experience, mainly thanks to cv2.EVENT_LBUTTONDOWN
and cv2.EVENT_MOUSEMOVE
events on mouse callback. Drag the mouse to draw the ROI.
import cv2
cap = cv2.VideoCapture(0)
cv2.namedWindow('Frame')
if not cap.isOpened():
exit()
# Our ROI, defined by two points
p1, p2 = (0, 0), (0, 0)
drawing = False # True while ROI is actively being drawn by mouse
show_drawing = False # True while ROI is drawn but is pending use or cancel
blue = (255, 0, 0)
def on_mouse(event, x, y, flags, userdata):
global p1, p2, drawing, show_drawing
if event == cv2.EVENT_LBUTTONDOWN:
# Left click down (select first point)
drawing = True
show_drawing = True
p1 = x, y
p2 = x, y
elif event == cv2.EVENT_MOUSEMOVE:
# Drag to second point
if drawing:
p2 = x, y
elif event == cv2.EVENT_LBUTTONUP:
# Left click up (select second point)
drawing = False
p2 = x, y
cv2.setMouseCallback('Frame', on_mouse)
while True:
val, fr = cap.read()
if not val:
break
if show_drawing:
# Fix p2 to be always within the frame
p2 = (
0 if p2[0] < 0 else (p2[0] if p2[0] < fr.shape[1] else fr.shape[1]),
0 if p2[1] < 0 else (p2[1] if p2[1] < fr.shape[0] else fr.shape[0])
)
cv2.rectangle(fr, p1, p2, blue, 2)
avg_y = (p1[1] + p2[1]) // 2
cv2.line(fr, (p1[0], avg_y), (p2[0], avg_y), blue, 2) # Middle horizontal line
avg_x = (p1[0] + p2[0]) // 2
cv2.line(fr, (avg_x, p1[1]), (avg_x, p2[1]), blue, 2) # Middle vertical line
cv2.imshow('Frame', fr)
pressed = cv2.waitKey(1)
if pressed in [13, 32]:
# Pressed Enter or Space to use ROI
drawing = False
show_drawing = False
# here do something with ROI points values (p1 and p2)
elif pressed in [ord('c'), ord('C'), 27]:
# Pressed C or Esc to cancel ROI
drawing = False
show_drawing = False
elif pressed in [ord('q'), ord('Q')]:
# Pressed Q to exit
break
cap.release()
cv2.destroyAllWindows()