I want capture images from webcam using opencv at certain intervals - opencv

I tried using schedule. It works fine but the viewfinder of the webcam is stuck at the initial state so it produces only one image multiple times.
Any help?
import cv2
import time
import schedule
cam = cv2.VideoCapture(0)
cv2.namedWindow("Webcam")
img_counter = 0
def capture():
global img_counter
img_name = "opencv_frame_{}.png".format(img_counter)
cv2.imwrite(img_name, frame)
print("screenshot taken")
img_counter += 1
while True:
ret, frame = cam.read()
if not ret:
print("failed to grab frame")
break
cv2.imshow("test", frame)
k = cv2.waitKey(1)
if k % 256 == 27:
print("closing the app")
break
else:
schedule.every(5).seconds.do(capture)
while 1:
schedule.run_pending()
time.sleep(1)
cam.release()
cam.destroyAllWindows()

You are suffering from buffering. OpenCV VideoCapture() reads a few frames into a buffer - I think it is 5 but have not checked for a while and it may differ between platforms or versions.
There are a few possible work-arounds depending on your situation:
call read() 4-5 times when you want a frame - it will only take a couple of hundred milliseconds
call grab() either repeatedly in another thread or just before you want a frame
reduce the size of the buffer so it can only hold a single frame.
Sorry for the somewhat woolly answer as I am not set up to test more at the moment.

I think your code could be simplified to something like this while still retaining a near-realtime preview of the periodically saved images.
import cv2
import schedule
cam = cv2.VideoCapture(0)
cv2.namedWindow("Webcam")
img_counter = 0
def capture():
global img_counter
img_name = "opencv_frame_{}.png".format(img_counter)
cv2.imwrite(img_name, frame)
print("screenshot taken")
img_counter += 1
# Set up schedule before loop
schedule.every(5).seconds.do(capture)
while True:
ret, frame = cam.read()
if not ret:
print("failed to grab frame")
break
cv2.imshow("test", frame)
schedule.run_pending()
k = cv2.waitKey(100) # 1/10 sec delay; no need for separate sleep
if k % 256 == 27:
print("closing the app")
break
cam.release()
cam.destroyAllWindows()

Related

Read frames from UVC camera

My camera is sporting 'GREY' and 'Y16' formats.
the output of v4l2-ctl --list-formats -d 0 # 0 is video0 is:
ioctl: VIDIOC_ENUM_FMT
Type: Video Capture
[0]: 'GREY' (8-bit Greyscale)
[1]: 'Y16 ' (16-bit Greyscale)
now if i use basic code of video streaming
import numpy as np
import cv2 as cv
cap = cv.VideoCapture('/dev/video0')
if not cap.isOpened():
print("Cannot open camera")
exit()
while True:
# Capture frame-by-frame
ret, frame = cap.read()
# if frame is read correctly ret is True
if not ret:
print("Can't receive frame (stream end?). Exiting ...")
break
cv.imshow('frame', frame)
if cv.waitKey(1) == ord('q'):
break
# When everything done, release the capture
cap.release()
cv.destroyAllWindows()
it is returning black image
cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter.fourcc('G','R','E','Y'))
by setting the property of the camera, now i am able to get the frame.

Saving multiple videos at the same time with opencv

For my project I have multiple cameras and I need to save the video feed to multiple output files at the same time. Here's my code:
import cv2
def one_cam_is_open(list_of_cams):
for cam in list_of_cams:
if cam.isOpened():
return True
return False
cam_list = []
# Capture video from camera
for i in range(0, 2):
cap = cv2.VideoCapture(i)
if cap!=-1:
cam_list.append(cv2.VideoCapture(i))
# the width and height of all cameras will be 1900x1080
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH) + 0.5)
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT) + 0.5)
dim = (1900, 1080)
# Define the codec and create VideoWriter object
fourcc = cv2.VideoWriter_fourcc(*'mp4v') # Be sure to use the lower case
video_writers = {}
for i, cam in enumerate(cam_list):
video_writers[cam] = cv2.VideoWriter("output_" + str(i) + ".mp4", fourcc, 20.0, dim)
while one_cam_is_open(cam_list):
for (cam, out) in video_writers:#TypeError: cannot unpack non-iterable cv2.VideoCapture object
ret, frame = cam.read()
if ret == True:
frame = cv2.flip(frame, 0)
# write the flipped frame
out.write(frame)
cv2.imshow('frame', frame)
if (cv2.waitKey(1) & 0xFF) == ord('q'): # Hit `q` to exit
break
else:
break
# Release everything if job is finished
for (cam, out) in video_writers:
out.release()
cam.release()
cv2.destroyAllWindows()
As noted in the code, I get the error TypeError: cannot unpack non-iterable cv2.VideoCapture object when I try to unpack the references to the VideoWriter obejects for each camera.
Is there a way to write to multiple video files using VideoWriter?

Grabbing images from webcam using opencv at specific FPS

Is there an OpenCV function that allows me to grab still images at a specific frame rate. Like I can tell this function to grab 5 images at 10fps, it will take 5 images 0.1 seconds apart exactly.
If not what is a good way to achieve this? My current attempt is to constantly grab images and only save when time is 0.1 seconds after previous frame but not accurate 10fps
afterNextFrame = False
while x < 20:
now = time.monotonic()
if now >= nextFrame:
afterNextFrame = True
if afterNextFrame == True:
cameraCap.grab()
print("\nNow: ", now, "\n")
_, frame = cameraCap.retrieve()
# save frame here
nextFrame += 0.1 # wait 0.1 second for 10 fps
afterNextFrame = False

OpenCV3 does not properly release camera

System Architecture:
Fedora 27
OpenCV 3.4
Python 3.6
The issue produced from the following code:
def capture_input():
cap = cv2.VideoCapture(0)
while 1:
# Take each frame
ret = cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 45)
ret = cap.set(cv2.CAP_PROP_FRAME_WIDTH, 45)
ret, frame = cap.read()
frame = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY)
cv2.imshow("Detecting Digits Frame", frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
frame = cv2.resize(frame, (45, 45))
break
cap.release()
cv2.destroyAllWindows()
return frame
The code works as expected sometimes, the other times it refuses to run producing:
select timeout
cv2.error:/io/opencv/modules/core/include/opencv2/core/mat.inl.hpp:500: error: (-215) total() == 0 || data != __null in function Mat
Not only that. Moreover, the webcam does not even work after that, I tried opening it with Cheese, it show a black screen and buttons are grayed out.
I tried to follow these SO links:
Issue 1
Issue 2
but with no success, and same for the other GitHub links.
Thanks in advance.

Overlay Live video with paintbrush style drawings?

I need some direction on whats the best programming approach to overlay a live video from a webcam (or a pre loaded video), with paintbrush. i.e, drawing lines , circles and such, to mark areas in the video while its playing.
right now using OpenCV + Tkinter, is there a better way to approach this?
Thanks
EDIT: trying to paint directly on the video window, but cant get it to work.. here is my code:
import cv2
import numpy as np
def interactive_drawing(event,x,y,flags,param):
global ix,iy,drawing, mode
if event==cv2.EVENT_LBUTTONDOWN:
drawing=True
ix,iy=x,y
elif event==cv2.EVENT_MOUSEMOVE:
if drawing==True:
if mode==True:
cv2.line(frame,(ix,iy),(x,y),(0,0,255),10)
ix=x
iy=y
print x,y
elif event==cv2.EVENT_LBUTTONUP:
drawing=False
if mode==True:
cv2.line(frame,(ix,iy),(x,y),(0,0,255),10)
ix=x
iy=y
return x,y
drawing=False # true if mouse is pressed
mode=True # if True, draw rectangle. Press 'm' to toggle to curve
cap = cv2.VideoCapture('track.avi')
while(cap.isOpened()):
ret, frame = cap.read()
if frame is None:
break
# cv2.namedWindow("frame", cv2.WND_PROP_FULLSCREEN)
# cv2.setWindowProperty("frame",cv2.WND_PROP_FULLSCREEN,cv2.WINDOW_FULLSCREEN)
cv2.setMouseCallback('frame',interactive_drawing)
cv2.imshow('frame',frame)
if cv2.waitKey(15) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
# mouse callback function
##img = np.zeros((512,512,3), np.uint8)
##
##cv2.namedWindow('begueradj')
##cv2.setMouseCallback('begueradj',interactive_drawing)
##while(1):
## cv2.imshow('begueradje',img)
## k=cv2.waitKey(1)&0xFF
## if k==27:
## break
##cv2.destroyAllWindows()
I would only use OpenCV for that purpose, as it already provides drawing functions such as :
Lines
Rectangles
Circles
Ellipses
Polygons
etc.
EDIT: This code snippet should help you get started. The important point here is that you have to save the drawing elements in a variable (curve_points in my case) and draw them on each new frames:
import cv2
import numpy as np
def interactive_drawing(event,x,y,flags,param):
global drawing, mode
if event==cv2.EVENT_LBUTTONDOWN:
drawing=True
elif event==cv2.EVENT_MOUSEMOVE:
if drawing==True:
if mode==True:
curves[len(curves)-1].append((x,y)) #append new points to the last list of curves
elif event==cv2.EVENT_LBUTTONUP:
drawing=False
if mode==True:
curves.append([]) #adding a new list to curves
return x,y
def draw_curves(myArray):
for j in range(0, len(myArray)):
for i in range(1, len(myArray[j])):
cv2.line(frame,myArray[j][i-1],myArray[j][i],(0,0,255),10)
drawing=False # true if mouse is pressed
mode=True # if True, draw rectangle. Press 'm' to toggle to curve
cap = cv2.VideoCapture(0) #cap = cv2.VideoCapture('track.avi')
curves = [[]] # initializing curves list with an empty list
cv2.namedWindow('frame')
cv2.setMouseCallback('frame',interactive_drawing)
while(cap.isOpened()):
ret, frame = cap.read()
if frame is None:
break
draw_curves(curves)
cv2.imshow('frame',frame)
if cv2.waitKey(15) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()

Resources