Python OpenCV select ROI on video/stream while its playing - python

appreciate if anyone can help tyring to select an ROI on a video stream while it's playing (don't want it to pause or capture the first frame)
am I missing something, I've tried setting to the frames to the same name
cv2.selectROI('Frame', frame, False)
cv2.imshow('Frame',frame)
Thanks

You can't use cv2.selectROI() in that case because the function is blocking, i.e. it stops the execution of your program until you have selected your region of interest (or cancelled it).
To achieve what you want you will need to handle the selection of the ROI yourself. Here is a short example of how you can do that, using two left-clicks to define the ROI and a right-click to erase it.
import cv2, sys
cap = cv2.VideoCapture(sys.argv[1])
cv2.namedWindow('Frame', cv2.WINDOW_NORMAL)
# Our ROI, defined by two points
p1, p2 = None, None
state = 0
# Called every time a mouse event happen
def on_mouse(event, x, y, flags, userdata):
global state, p1, p2
# Left click
if event == cv2.EVENT_LBUTTONUP:
# Select first point
if state == 0:
p1 = (x,y)
state += 1
# Select second point
elif state == 1:
p2 = (x,y)
state += 1
# Right click (erase current ROI)
if event == cv2.EVENT_RBUTTONUP:
p1, p2 = None, None
state = 0
# Register the mouse callback
cv2.setMouseCallback('Frame', on_mouse)
while cap.isOpened():
val, frame = cap.read()
# If a ROI is selected, draw it
if state > 1:
cv2.rectangle(frame, p1, p2, (255, 0, 0), 10)
# Show image
cv2.imshow('Frame', frame)
# Let OpenCV manage window events
key = cv2.waitKey(50)
# If ESCAPE key pressed, stop
if key == 27:
cap.release()

Related

Why does the cropped video not get saved?

Here, I have a code that takes a video as input and let the user draw a ROI. Later the cropped video will be displayed. This code was originally taken from I would like to define a Region of Interest in a video and only process that area.
I have provided the code below.
Question: I would like to save the cropped video in .mp4 format. The video output shows only a 1kb file. Can you go through the code and suggest a solution?
NB: I went through answer provided at OpenCV video not getting saved. Still I have failed to figure out the error.
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
#here, it is the copy of the first frame.
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))
print(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(r'E:\cardiovascular\brad1low.mp4')
#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]]
print(f'first frame roi is {first_frame_roi}')
#An empty image of full size just for visualization of difference
difference_image_canvas = np.zeros_like(first_frame)
out = cv2.VideoWriter(r'E:\cardiovascular\filename2.mp4', cv2.VideoWriter_fourcc(*'MP4V'), int(cap.get(cv2.CAP_PROP_FRAME_COUNT)), (int(first_frame_roi.shape[0]), (int(first_frame_roi.shape[1]))))
while cap.isOpened():
ret, frame = cap.read()
if ret:
#ROI of current frame
roi = frame[point1[1]:point2[1], point1[0]:point2[0]]
print(f'roi is {roi}')
cv2.imshow(DIFFERENCE_WINDOW_TITLE, roi)
out.write(roi)
key = cv2.waitKey(30) & 0xff
if key == 27:
break
else:
break
cap.release()
out.release()
cv2.destroyAllWindows()

Python, drawing a polygon over webcam video using mouse clicks to detect points

I'm using Python3 and OpenCV (4.1.0) to realize a script that:
displays the contents of the webcam;
records the coordinates of mouse clicks over video;
after pressing a certain button ('p' in my example), draws a polyline between the points identified by previous mouse clicks;
So far, I'm trying:
import numpy as np
import cv2
def main():
cap = cv2.VideoCapture("files/long_video.mp4") # Open video file
points = []
while (cap.isOpened()):
ret, frame = cap.read() # read a frame
try:
cv2.imshow('Frame', frame)
except:
print('EOF')
break
cv2.setMouseCallback('Frame', left_click_detect, points)
# Abort and exit with 'Q'
key = cv2.waitKey(25)
if (key == ord('q')):
break
elif (key== ord('p')): # HERE, IT SHOULD DRAW POLYLINE OVER VIDEO!!!
pts_array = np.array([[x, y] for (x, y) in points], np.int0)
frame = cv2.polylines(frame, np.int32(np.array(points)), False, (255, 0, 0), thickness=5)
points = []
cv2.imshow('Frame', frame)
cap.release() # release video file
cv2.destroyAllWindows() # close all openCV windows
def left_click(event, x, y, flags, points):
if (event == cv2.EVENT_LBUTTONDOWN):
print(f"\tClick on {x}, {y}")
points.append([x,y])
It kinda works, but after pressing 'p' it doesn't draw the polyline over the video.
Any suggestions?
There are 2 problems with your code:
cv2.polylines() accepts a list of arrays. so here:
frame = cv2.polylines(frame, np.int32(np.array(points)), False, (255, 0, 0), thickness=5)
Replace np.int32(np.array(points)) with [np.int32(points)] to fix the exception. (you also don't need to use np.array() here)
After you draw the polygon on the frame, you call cv2.show(), but almost immediately after, you show the next frame without the polygon on it, so you don't have time to see the polygon. to fix it you need to draw the polygon again for each frame. and to do that, you need to save it until you press p again (to show another polygon).
This will work:
import numpy as np
import cv2
def main():
cap = cv2.VideoCapture("files/long_video.mp4") # Open video file
polygon = []
points = []
while (cap.isOpened()):
ret, frame = cap.read() # read a frame
if not ret:
print('EOF')
break
frame = cv2.polylines(frame, polygon, False, (255, 0, 0), thickness=5)
cv2.imshow('Frame', frame)
# Abort and exit with 'Q'
key = cv2.waitKey(25)
if (key == ord('q')):
break
elif (key== ord('p')):
polygon = [np.int32(points)]
points = []
cv2.setMouseCallback('Frame', left_click_detect, points)
cap.release() # release video file
cv2.destroyAllWindows() # close all openCV windows
def left_click_detect(event, x, y, flags, points):
if (event == cv2.EVENT_LBUTTONDOWN):
print(f"\tClick on {x}, {y}")
points.append([x,y])
print(points)

Opencv python crashes after certain time

In my code after certain time (depend of the PC or OS) crashes. The error displayed is
libpng warning: Image width is zero in IHDR
libpng warning: Image height is zero in IHDR
libpng error: Invalid IHDR data
My code draw ROI on a video from webcam and take a snapshot. The ROI is deleted after 5-10 minutes (I'm not sure why, this is the error) and the picture saved not have dimensions then the error above is displayed but I'm not find the error. The instructions are, press "c" to stop the video and draw a ROI, press again "c" to take the picture, press "r" to resume the video, and repeat if you need another pictures.
I tested the code in Windows 10 and raspbian on a raspberry and the time is not the same but on both the program crashes. This is my code:
import cv2
# python PSI_Camera_test.py
class staticROI(object):
def __init__(self):
self.capture = cv2.VideoCapture(0)
self.capture.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
self.capture.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)
# Bounding box reference points and boolean if we are extracting coordinates
self.image_coordinates = []
self.extract = False
self.selected_ROI = False
self.img_counter = 0
self.update()
def update(self):
while True:
if self.capture.isOpened():
# Read frame
(self.status, self.frame) = self.capture.read()
cv2.imshow('image', self.frame)
key = cv2.waitKey(2)
# Crop image
if key == ord('c'):
self.clone = self.frame.copy()
cv2.namedWindow('image')
cv2.setMouseCallback('image', self.extract_coordinates)
while True:
key = cv2.waitKey(2)
cv2.imshow('image', self.clone)
# Crop and display cropped image
if key == ord('c'):
self.crop_ROI()
img_name = "Images\opencv_frame_{}.png".format(
self.img_counter)
cv2.imwrite(img_name, self.cropped_image)
print("{} written!".format(img_name))
self.img_counter += 1
# Resume video
if key == ord('r'):
break
# Close program with keyboard 'esp'
if key % 256 == 27:
cv2.destroyAllWindows()
exit(1)
else:
pass
def extract_coordinates(self, event, x, y, flags, parameters):
# Record starting (x,y) coordinates on left mouse button click
if event == cv2.EVENT_LBUTTONDOWN:
self.image_coordinates = [(x, y)]
self.extract = True
# Record ending (x,y) coordintes on left mouse bottom release
elif event == cv2.EVENT_LBUTTONUP:
self.image_coordinates.append((x, y))
self.extract = False
self.selected_ROI = True
# Draw rectangle around ROI
cv2.rectangle(
self.clone, self.image_coordinates[0], self.image_coordinates[1], (0, 255, 0), 2)
# Clear drawing boxes on right mouse button click
elif event == cv2.EVENT_RBUTTONDOWN:
self.clone = self.frame.copy()
self.selected_ROI = False
def crop_ROI(self):
if self.selected_ROI:
self.cropped_image = self.frame.copy()
x1 = self.image_coordinates[0][0]
y1 = self.image_coordinates[0][1]
x2 = self.image_coordinates[1][0]
y2 = self.image_coordinates[1][1]
self.cropped_image = self.cropped_image[y1:y2, x1:x2]
print('Cropped image: {} {}'.format(
self.image_coordinates[0], self.image_coordinates[1]))
else:
print('Select ROI to crop before cropping')
# python PSI_Camera_test.py
if __name__ == '__main__':
static_ROI = staticROI()
Thanks in advance!

Previewing line when drawing with opencv

I want to make a simple draw function to draw a line, but I want it to be previewed while it's being drawn; on EVENT_MOUSEMOVE it should draw the line continuously, while not saving it (e.g. how MS paint behaves when you draw a line and can see the output, which is saved when you release the mouse button).
I've used the "more advanced demo" here, where I use the input image as a global, make a copy of it, and then overwrite the image with the copy after drawing, but it doesn't actually make any difference (I neither see the "preview" of the line, and all the lines I draw stay on the canvas) and I can't see why:
img = None
def draw_circle(event,x,y,flags,param):
global ix,iy,drawing,mode,img
img_c = img.copy()
if event == cv2.EVENT_LBUTTONDOWN:
drawing = True
ix,iy = x,y
elif event == cv2.EVENT_MOUSEMOVE:
if drawing == True:
if mode == True:
cv2.line(img,(ix,iy),(x,y),(0,255,0),1)
img = img_c.copy()
else:
cv2.circle(img,(x,y),5,(0,0,255),-1)
elif event == cv2.EVENT_LBUTTONUP:
drawing = False
if mode == True:
cv2.line(img,(ix,iy),(x,y),(0,255,0),1)
else:
cv2.circle(img,(x,y),5,(0,0,255),-1)
while(1):
cv2.imshow('image',img)
k = cv2.waitKey(1) & 0xFF
To preview a line while drawing it, you need to update the image every time you move the mouse, but you need to keep the original to only draw one line. If the line changes orientation the idea is not to draw multiple lines, but to show only one line.
Here is a sample code of what I am talking about. I start with a black canvas, then I preview the line in blue, and once it is finish it becomes green. Read the comments inside the code to understand the details. If you have any questions just comment :)
import numpy as np
import cv2
# create black canvas of size 600x600
img = np.zeros((600, 600, 3), dtype=np.uint8)
# intialize values in unusable states
preview = None
initialPoint = (-1, -1)
# mouse callback
def drawLine(event,x,y,flags,param):
global initialPoint,img, preview
if event == cv2.EVENT_LBUTTONDOWN:
# new initial point and preview is now a copy of the original image
initialPoint = (x,y)
preview = img.copy()
# this will be a point at this point in time
cv2.line(preview, initialPoint, (x,y), (0,255,0), 1)
elif event == cv2.EVENT_MOUSEMOVE:
if preview is not None:
# copy the original image again a redraw the new line
preview = img.copy()
cv2.line(preview, initialPoint, (x,y), (0,255,0), 1)
elif event == cv2.EVENT_LBUTTONUP:
# if we are drawing, preview is not None and since we finish, draw the final line in the image
if preview is not None:
preview = None
cv2.line(img, initialPoint, (x,y), (255,0,0), 1)
# set the named window and callback
cv2.namedWindow("image")
cv2.setMouseCallback("image", drawLine)
while (True):
# if we are drawing show preview, otherwise the image
if preview is None:
cv2.imshow('image',img)
else :
cv2.imshow('image',preview)
k = cv2.waitKey(1) & 0xFF
if k == ord('q'):
break;
cv2.destroyAllWindows()

opencv window not closing after calling destroyAllWindows() function

I am implementing camshift algorithm in python using opencv and using the position given by it to move my mouse and draw on the kolour application.
When i press the button on in tkinter ui a frame launches and then
Upon pressing the key 'q' the 'frame' does not close, The frame just freezes and the option to force quit comes. I am using tkinter for UI.
global paint_open
paint_open = 0
def func():
global frame, roiPts, inputMode ,token
camera = cv2.VideoCapture(0)
cv2.namedWindow("frame")
cv2.setMouseCallback("frame", selectROI)
termination = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1)
roiBox = None
li=[]
while True:
(grabbed, frame) = camera.read()
if roiBox is not None:
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
backProj = cv2.calcBackProject([hsv], [0], roiHist, [0, 180], 1)
(r, roiBox) = cv2.CamShift(backProj, roiBox, termination)
pts = np.int0(cv2.cv.BoxPoints(r))
li.append(pts)
#coordinates contain the coordinates of the tracked object
coordinates = r[0]
# x, y contains the coordinates
x = int(coordinates[0])
y = int(coordinates[1])
drawing(x,y)
#draws a circle around the center from x,y
cv2.circle(frame, (int(x), int(y)), 4, (0, 0, 255), 2)
#draws a colored frame around the object
cv2.polylines(frame, [pts], True, (255, 0, 0), 2)
#here imshow function start
cv2.imshow("frame", frame)
key = cv2.waitKey(1) & 0xFF
# handle if the 'i' key is pressed, then go into ROI
if key == ord("i") and len(roiPts) < 4:
inputMode = True
orig = frame.copy()
while len(roiPts) < 4:
cv2.imshow("frame", frame)
cv2.waitKey(0)
roiPts = np.array(roiPts)
s = roiPts.sum(axis = 1)
tl = roiPts[np.argmin(s)]
br = roiPts[np.argmax(s)]
roi = orig[tl[1]:br[1], tl[0]:br[0]]
roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
roiHist = cv2.calcHist([roi], [0], None, [16], [0, 180])
roiHist = cv2.normalize(roiHist, roiHist, 0, 255, cv2.NORM_MINMAX)
roiBox = (tl[0], tl[1], br[0], br[1])
# if the 'q' key is pressed, stop the loop
elif key == ord("q"):
break
camera.release()
cv2.destroyAllWindows()
def drawing(x,y):
global paint_open
if paint_open == 0:
launchapp('kolourpaint')
paint_open = 1
py.dragTo(x,y)
def main():
root=tk.Tk()
bkgcolor='#D84315'
root.configure(background=bkgcolor)
label=tk.Label(root,text="Gesture Recognition Project",font=('arial black',12),fg="white",width=90,height=3,bg="purple")
label.pack()
frame1 = tk.Frame(root,bg=bkgcolor)
frame1.pack(padx=205,pady=25)
bframe1 = tk.Frame(root,bg=bkgcolor)
bframe1.pack(side=tk.BOTTOM,padx=205)
photo3 = tk.PhotoImage(file="3.png")
button2 = tk.Button(frame1, width=255, height=255, image=photo3,text="Slide Presenter",fg="purple",bg="white",command=func)
button2.pack(side=tk.LEFT,padx=25)
button2.image = photo1
# start the event loop
root.mainloop()
This question is a bit old but worth answering, since it comes up in searches. I experienced the same problem and eventually found an answer that worked. It seems hack-ish, but allows opencv to go through its processes to close a window. Opencv performs its processing during the waitKey(), so adding a few of those before and after the destroyallwindows() function did the trick.
In your code, where it says
cv2.destroyAllWindows()
... try this instead. It worked for me.
# All these waitkeys are a hack to get the OpenCV window to close
cv2.waitKey(1)
cv2.destroyAllWindows()
for i in range (1,5):
cv2.waitKey(1)
return
I'm not sure but cv may use tkinter to display windows so root.mainloop() may keep windows open. You can try to end root.mainloop() to close program and all windows.
import Tkinter as tk
import cv2
# create global value (with some value)
root = None
def func():
# inform function to use global variable instead of local one
global root
# ...
cv2.destroyAllWindows()
camera.release()
# close root window and leave mainloop()
root.destroy()
def main():
# inform function to use global variable instead of local one
global root
root = tk.Tk()
# ...
root.mainloop()
main()
Since a new window is opened upon calling destroyAllWindows() function, you need to press space-key to close the execution of the command.
This work for me
while True:
_, frame = cap.read()
cv2.imshow(windowName, frame)
keyCode = cv2.waitKey(1)
if cv2.getWindowProperty(windowName, cv2.WND_PROP_VISIBLE) <1:
break
cv2.destroyAllWindows()
from https://newbedev.com/closing-video-window-using-close-x-button-in-opencv-python

Categories