-1

I have an application that needs to capture only a few frames per second from a webcam. Setting videowriter in the below code to 3 frames per second results in the webcam's normal framerate of approximately 30 fps being saved. What are the options to save only the recorded 3 frames per second, and let the other 27 or so go? Thanks in advance.

import cv2
import numpy as np
import time
import datetime
import pathlib
import imutils

cap = cv2.VideoCapture(0)

if (cap.isOpened() == False): 
  print("Unable to read camera feed")

capture_duration = 15
frame_per_sec = 3
frame_width = 80
frame_height = 60

out = cv2.VideoWriter('C:\\Users\\student\\Desktop\\videoFile.avi',cv2.VideoWriter_fourcc('m','j','p','g'),frame_per_sec, (frame_width,frame_height))

start_time = time.time()
while( int(time.time() - start_time) < capture_duration ):
    ret, frame = cap.read()
    if ret==True:
        frame = imutils.resize(frame, width=frame_width)
        out.write(frame)
        cv2.imshow('frame',frame) 
        if cv2.waitKey(1) & 0xFF == ord('q'):
          break
    else:
        break

cap.release()
out.release()
 
cv2.destroyAllWindows()
portsample
  • 1,986
  • 4
  • 19
  • 35
  • 4
    `frame_width = int('80')` Why on earth do you do this? If you want to make the frame width 80, just do `frame_width = 80` rather than needlessly making it a string you don't want and then converting it to an integer. – Mark Setchell Jan 21 '23 at 07:44
  • 1
    If time.time() - time_of_last_written_frame < 333 ms : skip current_frame – Micka Jan 21 '23 at 10:01
  • Did you try to set the fps for `caps` after creating it as explained in my answer ? – wohlstad Jan 21 '23 at 14:45
  • @wohlstad Actively working on this right now. Greatly appreciate your input. Thanks! – portsample Jan 21 '23 at 14:53
  • as I recommended in your last question, don't program this. use existing programs for the recording. look at ffmpeg or OBS Studio. if you must program it, look at PyAV and imageio (also does video) – Christoph Rackwitz Jan 21 '23 at 18:06

2 Answers2

1

You set the FPS for the output via the VideoWriter,
but you didn't attempt to set the FPS for the input via the VideoCapture.

In order to do that you can try to call cv2.VideoCapture, with the cv2.CAP_PROP_FPS property after you create cap.
For example:

cap.set(cv2.CAP_PROP_FPS, 3)

However - note that the actual behavior is dependant on the specific capture device you are using. Some support only certain FPSs. See also this post regarding it: change frame rate in opencv 3.4.2.

If it does work you will be able to simplify your code a lot - just capture frames, process them and save (without any manual fps management).

wohlstad
  • 12,661
  • 10
  • 26
  • 39
  • When applied, this does reduce the size of the produced file somewhat. Going from 30fps to 3fps using this method produces a 7mb and a 3.9mb file. In other systems that we have used, such a reduction in fps produces a much smaller file relatively. – portsample Jan 21 '23 at 15:25
  • I'm not sure about the file size. It depends on the video codec and be different on different systems. But you can check the actual FPS quite easily: measure the time before the capture loop, and increment a counter in it. Every e.g. 20 frames print the number of frames devided by the number of seconds that passed. – wohlstad Jan 21 '23 at 15:42
  • I think that what you have just described is what I am looking for. This would get us away from the defined fps levels in camera hardware. – portsample Jan 21 '23 at 15:46
1

This method programmatically sets frames per second. A 6.1mb file was created when frame rate was set for 30fps, and a 0.9mb file when set for 3fps.

#!/usr/bin/env python3

import cv2
import numpy as np
import time
import datetime
import pathlib
import imutils

cap = cv2.VideoCapture(0)

if (cap.isOpened() == False): 
  print("Unable to read camera feed")

capture_duration = 15
frame_per_sec = 30
prev = 0
frame_width = int(cap.get(3))
frame_height = int(cap.get(4))
out = cv2.VideoWriter('C:\\videoPy\\LZ\\'outpout.avi',cv2.VideoWriter_fourcc('m','j','p','g'),frame_per_sec, (frame_width,frame_height))
start_time = time.time()
while( int(time.time() - start_time) < capture_duration ): 
#start fps
  time_elapsed = time.time() - prev
  while(time_elapsed > 1./frame_per_sec):                   
        ret, frame = cap.read()
        if not ret:
            break
        if time_elapsed > 1./frame_per_sec:
          prev = time.time()
#end fps
        if ret==True:
          frame = imutils.resize(frame, width=frame_width)
          out.write(frame)
          cv2.imshow('frame',frame) 
        if cv2.waitKey(1) & 0xFF == ord('q'):
          break
        else:
           break

cap.release()
out.release()
 
cv2.destroyAllWindows()
portsample
  • 1,986
  • 4
  • 19
  • 35