Duration of videoWriter being controlled with fps and frame Count (OpenCV & Python) - python

When use the code below, it gives me a video from stream which has desired number of frames and FPS I choose. However, video length becomes duration =(1/fps)*frameCount. I guess that mp4 does video compression so that the duration of the video does not make the file size bigger, this is a good thing. Nevertheless, is there a way to have a video with smaller duration?
EDIT: An example scenario:
The thing I wanna do is to have 1 Frame for every minutes of streaming and I want to have, lets say 1 FPS video with 1000 Frames. In this scenario, the actual streaming duration becomes 1000 minutes, but I want a 1 FPS video which has 1000 seconds of duration.
Here is the code I am using below:
import os
import cv2 as cv
import math
cap = cv.VideoCapture('rtsp://**.***.**.*:*****/***********')
# Frame sizes
down_width = 640
down_height = 480
down_points = (down_width, down_height)
# stream fps and desired FPS
fpsSystem = cap.get(cv.CAP_PROP_FPS) # 25 in my case
fps = 1.0/60
# Frame Count parameters
frameRead = 0 # successfully readed frame number
DesFrameCount = 60*6 # Desired frame count
takeFrameTime = 1/fps # every TakeFrameTime seconds frames will be stored
frameCycle = 0 # every frameCycle. frame will be stored
frameWritten = 0
success = True
# Define the codec and create VideoWriter object
fourcc = cv.VideoWriter_fourcc(*'mp4v')
# Video Name
randomName = np.random.randint(0,1000)
out = cv.VideoWriter('output'+str(randomName) + ".mp4", fourcc, fps, (down_width, down_height))
while success:
success, frame = cap.read()
if not success:
print("Can't receive frame (stream end?). Exiting ...")
break
else:
frameRead += 1
frameCycle += 1
# Frame Resizing
frame = cv.resize(frame,down_points,interpolation= cv.INTER_LINEAR)
# Save the particular frame desired to be written according to frame parameters
if frameCycle == math.floor(fpsSystem*takeFrameTime):
frameCycle = 0
out.write(frame)
frameWritten += 1
# Stop the loop when desired number of Frame obtained
if cv.waitKey(1) == ord('q') or (frameWritten == DesFrameCount):
break
# Release everything if job is finished
cap.release()
out.release()
cv.destroyAllWindows()

Related

capturing fps drops with lower resolution opencv

I have a USB camera that is able to record 60 fps. I am using openCV with simple python code on Windows to capture some videos however it is not going all smoothly!
My main problem is that, if I set the [width, height] properties to the maximum the camera accepts it is able to record 60 fps just fine otherwise (i.e. any lower resolution) the recording/streaming will drop to 30 fps max (the recording will be so funny that is either sped up or slowed down to match the specified recording fps; i.e. if the resolution specified 320X240 and recording fps set to 60 and for 10 seconds the resultant video will be squashed to 5 seconds so basically sped up 2x!!)
I don't understand why exactly that happens? any ideas?
here is a snippet of the code:
import cv2
import os
import time
def readVideo(Did):
cap = cv2.VideoCapture(Did)
# cap.set(cv2.CAP_PROP_FPS, 60) # no matter if you specify or not it selects what suits!!
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 320) # 640 is maximum
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 240) # 480 is maximum
ret,frame = cap.read()
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('./output.avi', fourcc, 60.0, (320,240)) # (width,height) must match what is stated above in CAP!
while ret:
ret,frame = cap.read()
elapsed = time.time() - start
count = count + 1 # frame numbers
cv2.putText(frame,str(cfpsBacked), (25,15),font,fontScale,fontColor,lineType)
out.write(frame)
cv2.imshow('camera',frame)
if elapsed - tick >= 1:
print("Actual count:{}",count)
tick += 1
cfpsBacked = count
count = 0
if tick - 10 == 0: # just records 10 seconds
break
if cv2.waitKey(10) & 0xFF == ord('q'):
break
out.release()
cap.release()
cv2.destroyAllWindows() # destroy all the opened windows

How to maintain constant FPS when grabbing frames with opencv and python?

I am using OpenCV4 along with python 3 to open a webcam, grab the frames and display them in a window, just like the first code tutorial provided here. However, it takes a different amount of time grabbing different frames: sometimes it takes 0.01 s to grab, and sometimes it takes 0.33 s, which creates lags when showing the frames in the window.
Is there a way to force a constant time when grabbing frames so that i can see the video without lag? I think it is happening with OpenCV because when i use a default windows camera viewer to see the video it displays it normally.
What i already tried is wait for some time using time.sleep() before grabbing a frame again. But this does not help.
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
while(True):
# Capture frame-by-frame
ret, frame = cap.read()
# Display the resulting frame
cv2.imshow('frame',gray)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()
One potential way is to set a timestamp within the loop and keep track of the time the last frame was shown. For instance, only once a certain amount of time has elapsed then you show the frame. At the same time, you constantly read frames to keep the buffer empty to ensure that you have the most recent frame. You don't want to use time.sleep() because it will freeze the program and not keep the buffer empty. Once the timestamp hits, you show the frame and reset the timestamp.
import cv2
import time
cap = cv2.VideoCapture(0)
# Timeout to display frames in seconds
# FPS = 1/TIMEOUT
# So 1/.025 = 40 FPS
TIMEOUT = .025
old_timestamp = time.time()
while(True):
# Capture frame-by-frame
ret, frame = cap.read()
if (time.time() - old_timestamp) > TIMEOUT:
# Display the resulting frame
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
old_timestamp = time.time()
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()
When working correctly, this app will be suspended at the read() call until the next frame from the streaming webcam is available. Smooth display depends on being able to execute whatever you may have added to the loop in less than the 1/FPS seconds. It also depends on the camera being UVC compliant and it may depend on the encoding algorithm being MJPEG, which is the case for most webcams. However the fact that you see delay up to 1/3 second is curious because that is a typical GOP period for mpeg or other inter-frame encoders.
If none of the above applies to your case then I suspect the problem is platform related rather than an OCV issue. Have you tried to duplicate the problem on another system?
I was facing a similar problem, and this is the solution I came up with. This would be the exact way to set a constant fps. This works on both live video and recorded video.
import cv2
import time
cap = cv2.VideoCapture('your video location')
initial_time = time.time()
to_time = time.time()
set_fps = 25 # Set your desired frame rate
# Variables Used to Calculate FPS
prev_frame_time = 0 # Variables Used to Calculate FPS
new_frame_time = 0
while True:
while_running = time.time() # Keep updating time with each frame
new_time = while_running - initial_time # If time taken is 1/fps, then read a frame
if new_time >= 1 / set_fps:
ret, frame = cap.read()
if ret:
# Calculating True FPS
new_frame_time = time.time()
fps = 1 / (new_frame_time - prev_frame_time)
prev_frame_time = new_frame_time
fps = int(fps)
fps = str(fps)
print(fps)
cv2.imshow('joined', frame)
initial_time = while_running # Update the initial time with current time
else:
total_time_of_video = while_running - to_time # To get the total time of the video
print(total_time_of_video)
break
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()

Extract images from live video feed of ipcamera

I want to extract images every 5 minutes from a webcam live video feed using opencv. I have the below code to extract from a video. But don't know how to do it for a live video stream from an ipcamera
Below code is used to get an image every 5 seconds from a valid video
import cv2
videoFile = "folder-path"
cap = cv2.VideoCapture(videoFile)
success, image = cap.read()
success = True
count = 0
while success:
# Capture frame-by-frame
cap.set(cv2.CAP_PROP_POS_MSEC,(count*1000)
success, image = cap.read()
cv2.imwrite("file path/frame%d.jpg" % count, image)
count = count + 5
Use cv2.VideoCapture() with the index of the camera you care about. If you have only one camera, cv2.VideoCapture(0) will do the trick. If you have multiple, you will want to increment the index until you are accessing the correct camera.
This code will capture a frame from camera 0 every 5 minutes:
camera = cv2.VideoCapture(0) # start a connection to the camera
ret, frame = camera.read() # read a frame
cv2.waitKey(300000) # wait 5 minutes

Removing frames with no motion in openCV

I am trying to write a openCV program where i am breaking down the video into frames and comparing two frames one after the other if both are the same i reject the frame else append the frame to a output file.
How can i achieve it?
OpenCV 2.4.13 Python 2.7
The following example captures frames from the first camera connected to your system, compares each frame to the previous frame, and when different, the frame is added to a file. If you sit still in front of the camera, you might see the diagnostic 'no change' message printed if you run the program from a console terminal window.
There are a number of ways to measure how different one frame is from another. For simplicity we have used the average difference, pixel by pixel, between the new frame and the previous frame, compared to a threshold.
Note that frames are returned as numpy arrays by the openCV read function.
import numpy as np
import cv2
interval = 100
fps = 1000./interval
camnum = 0
outfilename = 'temp.avi'
threshold=100.
cap = cv2.VideoCapture(camnum)
ret, frame = cap.read()
height, width, nchannels = frame.shape
fourcc = cv2.VideoWriter_fourcc(*'MJPG')
out = cv2.VideoWriter( outfilename,fourcc, fps, (width,height))
while(True):
# previous frame
frame0 = frame
# new frame
ret, frame = cap.read()
if not ret:
break
# how different is it?
if np.sum( np.absolute(frame-frame0) )/np.size(frame) > threshold:
out.write( frame )
else:
print( 'no change' )
# show it
cv2.imshow('Type "q" to close',frame)
# check for keystroke
key = cv2.waitKey(interval) & 0xFF
# exit if so-commanded
if key == ord('q'):
print('received key q' )
break
# When everything done, release the capture
cap.release()
out.release()
print('VideoDemo - exit' )

Python and OpenCV - Determine Correct Frame Rate of Captured Streaming Video

I’m using OpenCV in a Python environment to capture a video stream from an external source, display the video, and write the video to a file. The video stream can come from different video sources. I need to write the video using the exact same frame rate as the incoming video (e.g., 60 fps, 29.97 fps, 30 fps, etc.).
Because the streaming video does not have the frame rate embedded in the stream, I need to determine the correct frame rate. I have tried suggestions by others of sampling some frames then divide the number of captured frames by the elapsed time. For me, this results in a frame rate that is close, but not close enough.
When I capture the video with VLC Media Player, VLC determines the frame rate correctly.
Here is the Python script that I’m currently using. It buffers 500 frames to compute the frame rate and then starts writing the video while continuing to capture (with a 500 frame delay). (VLS capture/write doesn’t have a noticeable delay.)
Foremost importance to me – correctly determine the frame rate of the incoming video stream. Second importance – I want to write the video with minimum delay after capture.
Any suggestions?
import numpy as np
import cv2
from time import time
cap = cv2.VideoCapture(0)
frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fourcc = cv2.VideoWriter_fourcc(*'DIVX')
kount = 0
delay = 500
buffer = []
start = time()
while(cap.isOpened()):
ret, frame = cap.read()
if ret==True:
kount += 1
buffer.append(frame)
cv2.imshow('frame',frame)
if kount >= delay:
if kount == delay:
end = time()
fps = kount / (end - start)
out = cv2.VideoWriter('output.avi',fourcc, fps, (frame_width,frame_height))
out.write(buffer[kount-delay])
if cv2.waitKey(1) & 0xFF == ord('q'):
for i in range(kount - delay, kount):
out.write(buffer[i])
break
else:
break
print("Frames Per Second = ", fps)
cap.release()
out.release()
cv2.destroyAllWindows()

Categories