(Using OpenCV 4.1)
I am trying to capture screenshots from videos. My intention is to have the script capture a frame every five minutes up to 20 captures.
My test video is 20 minutes long. Once the script loops 4 times, I want it to quit. However, it loops a 5th time and captures 2 seconds from the end of the video. Then it loops a 6th time and captures the same frame as the 4th loop. It keeps repeating these last two loops until there are 20 frames captured.
How do I get the script to recognize that it has reached the end of the video and stop?
Note: the last frame captured may not be the last frame in the video. For example, if the video is 23 minutes long, the last frame captured should be near the 20-minute mark.
import datetime
import sys
import time
from cv2 import cv2
def milsec_to_hr_min_sec(milliseconds): # Returned from CAP_PROP_POS_MSEC
ms = int(milliseconds)
seconds = str(int((ms / 1000) % 60))
minutes = str(int((ms / (1000 * 60)) % 60))
hours = str(int((ms / (1000 * 60 * 60)) % 24))
return hours, minutes, seconds
def FrameCapture(path): # Extract frame
cap = cv2.VideoCapture(path)
framerate = cap.get(cv2.CAP_PROP_FPS)
count = 1
framecount = 0
# checks whether frames were extracted
while True:
while count < 21 and framecount < cap.get(cv2.CAP_PROP_FRAME_COUNT):
# Capture frame every 5 minutes
framecount = count * framerate * 60 * 5
cap.set(1, framecount)
# capture frame at timestamp
success, image = cap.read()
if success:
cv2.imwrite(
path + " (screencap #%d).jpg" % count, image,
)
# Convert timestamp to hr:min:sec
hours, minutes, seconds = milsec_to_hr_min_sec(
cap.get(cv2.CAP_PROP_POS_MSEC)
)
print(
str(success)
+ " "
+ "Captured: screencap #{} at timestamp ".format(count)
+ hours
+ "h "
+ minutes
+ "m "
+ seconds
+ "s"
)
count += 1
if cv2.waitKey(1) & 0xFF == ord("q"):
break
else:
break
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()
print("Finished capture")
# Driver Code
if __name__ == "__main__":
# Calling the function
fn = "\\full\path\to\file"
FrameCapture(fn)
Please forgive the hack-y nature of my scripts. I pieced them together with parts found from searches.
At the beginning of the "while" loop you may use the following code:
ret, frames = cap.read()
if frames is None:
break
There are two ways of doing it:
Loop through a while(true) loop and break when frame.empty().
Obtain the frame count using: int nFrames = vid_cap.get(CAP_PROP_FRAME_COUNT); //Get the number of frames avaiable in the video and use a for_loop to loop through the frames.
This code will get all frames from your video
def get_list_frame_by_video(file_path_video):
vs = cv2.VideoCapture(file_path_video)
list_frame = []
print("____start load video____")
len_frames = int(vs.get(cv2.CAP_PROP_FRAME_COUNT))
while True:
is_cap, frame = vs.read()
if frame is None:
continue
list_frame.append(frame)
if len_frames == len(list_frame):
break
print("____complete load video____")
return list_frame
A simple way is:
sucess, img = cap.read()
if img is None:
print(' Successful process ')
break
You just have to add this line and process will be ended if 'cap' is empty
Related
I have a webcam that captures video stream. After 30 seconds I want to remove 1 sec of the video from the start and keep capturing the video stream and so on. In short, I only want to save the latest 30 seconds of the live video.
OpenCV does not provide video processing
ffmpeg trims the video but creates a new output file, I don't want to keep copies.
#Create a video write before entering the loop
#Create a video write before entering the loop
video_writer = cv2.VideoWriter(
video_file, video_codec, fps, (int(cap.get(3)), int(cap.get(4)))
)
#video_file is the file being saved
start = time.time()
i=0
seconds='1'
while cap.isOpened():
ret, frame = cap.read()
if ret == True:
cv2.imshow("frame", frame)
if time.time() - start > 10:
print('video > 10 sec')
subprocess.call(['ffmpeg', '-i', video_file, '-ss', seconds, 'output.avi'])
break
# Write the frame to the current video writer
video_writer.write(frame)
if i%24 == 0:
cv2.imwrite('image'+str(i)+'.jpg',frame)
i+=1
if cv2.waitKey(1) & 0xFF == ord("q"):
break
else:
break
cap.release()
cv2.destroyAllWindows()
What I am looking for is how we can trip a live video and keep saving future frames so that the video don't exceed 30 seconds and keeps the latest frames.
You can use the segment muxer:
ffmpeg -i input -f segment -segment_time 30 -segment_wrap 2 -reset_timestamps 1 output_%d.avi
This will create two files: output_0.avi and output_1.avi. Every 30 seconds the output will alternate between these files and overwrite earlier versions.
You could use -segment_wrap 1 and only output 1 file, but you risk losing video. For example stopping recording at 32 seconds will leave you with a 2 second video instead of a 30 second video + a 2 second video.
I'm working with a code that analyzes frames from a live stream with OpenCV and if a condition is met saves the current frame to file.
The infinite loop to analyze the video frame by frame is something like this:
while True:
ret,frame = stream.read()
if conditionisMet :
pil_image = Image.fromarray(frame)
pil_image.save("/path/to/folder/image.jpg")
cv2.imshow("LiveStream", frame)
What I want to add is that if the condition is met again too soon (20-30 sec) the image does not have to be saved and the while loop has to grab another frame and continue its work. I've tried with time.sleep(30.0) inside the if statement but it blocks the while loop waiting for the 30 sec to pass. Is there a way to use time.sleep in this case, or another method suitable for my needs?
Thanks in advance
you could do something like this:
last_grab=time.time()-30 # this to get things started
while True:
if condition and time.time()-last_grab > 30:
last_grab=time.time()
# Do things here
else:
continue
Just add a variable to keep track of your last saving time:
last_save_time = time.time()
while True:
ret,frame = stream.read()
if conditionisMet and time.time() - last_save_time() > 20:
pil_image = Image.fromarray(frame)
pil_image.save("/path/to/folder/image.jpg")
# update last save time
last_save_time = time.time()
cv2.imshow("LiveStream", frame)
Why not just capture the amount of time running then save image if greater than the given amount of time....
a = dt.now()
b = dt.now()
c = b - a
if c < x:
do something
I am running the following code:
import numpy as np
import cv2
import os
count = 0
cap = cv2.VideoCapture("/home/simon/PROJECT/real_data/00000020.mp4")
while not cap.isOpened():
cap = cv2.VideoCapture("./00000020.mp4")
cv2.waitKey(1000)
print "Wait for the header"
pos_frame = cap.get(cv2.cv.CV_CAP_PROP_POS_FRAMES)
while True:
flag, frame = cap.read()
if flag:
# The frame is ready and already captured
cv2.imshow('video', frame)
pos_frame = cap.get(cv2.cv.CV_CAP_PROP_POS_FRAMES)
print str(pos_frame)+" frames"
else:
# The next frame is not ready, so we try to read it again
cap.set(cv2.cv.CV_CAP_PROP_POS_FRAMES, pos_frame-1)
print "frame is not ready"
# It is better to wait for a while for the next frame to be ready
cv2.waitKey(1000)
if cv2.waitKey(10) & 0xFF == 27:
break
if cap.get(cv2.cv.CV_CAP_PROP_POS_FRAMES) == cap.get(cv2.cv.CV_CAP_PROP_FRAME_COUNT):
# If the number of captured frames is equal to the total number of frames,
# we stop
break
if ret == True:
frame = cv2.VideoCapture.grab()
frame = 'frame%d' % count
cv2.imwrite('frame%d.png', frame)
count += 1
else:
print 'stopped at' + count
break
And whenever I run it, it loops on the while not loop, printing "wait for header".
There is never an error code or anything like that either.
I have tried to run it as a more simple piece of code, where it doesnt have all these checks, and again that doesn't throw any errors.
I am attempting to run this code to open a video, and then save the frames as png files throughout the video.
Does anyone spot any particular problems with the code?
Or alternatively does anyone know a piece of code that would do what i want more efficiently, as I have trawled through google searches and stack overflow a lot recently and haven't found anything
Thanks in advance
Panda
You need to include a couple of DLLs in your python directory in order to play videos. Please see this for details:
https://li8bot.wordpress.com/2014/07/09/opencvpython-part-1-working-with-videos/
I have obtained the frame_count of a saved video.
self.frame_count = self.capture.get(cv.CV_CAP_PROP_FRAME_COUNT) - 1
Now, I want to start a frame read from a particular frame_count. How do I do this?
Reason: I need to track an object and I have found the location of the object I want to track using HSV image segmentation. Now to track it, I intend to start the video from that particular frame and set the track window to the objects' coordinates.
Want: It should not be redundant and computationally intensive.
Use the below code to accomplish your task.
The Opencv version you are using is old. Use Opencv2.
Link : http://docs.opencv.org/trunk/doc/py_tutorials/py_tutorials.html
import numpy as np
import cv2
import os
cam = cv2.VideoCapture('full_path/bird.avi')
i = 1
initialize_first_frame = cam.read()[1]
start_from_frame = 5
dir = './testImages/'
os.makedirs(dir)
while True:
if(i>=start_from_frame):
cv2.imshow('Frame Conversion',cam.read()[1])
cv2.imwrite(dir + "/image-"+str(i).zfill(5)+".png",cam.read()[1])
i = i + 1
key = cv2.waitKey(10)
if key == 27:
cv2.destroyWindow('Frame Conversion')
break
print "End"
I hope this is the code you want.
Try the following:
f = # put here the frame from which you want to start
self.capture.set(CV_CAP_PROP_POS_FRAMES, f)
while f < self.frame_count:
retval, image = self.capture.read()
f += 1
For any version 3 and 4 of OpenCV Python, follow this -
import cv2
# suppose you want to start reading from frame no 500
frame_set_no = 500
cap = cv2.VideoCapture("full_path/cow.mp4")
# capture is set to the desired frame
cap.set(cv2.CAP_PROP_POS_FRAMES, frame_set_no)
while True:
ret, frame = cap.read()
cv2.imshow("Video", frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
I'm trying to have my webcam do the following:
capture 10 captures for 1 minute duration (one capture every 6
seconds).
Then save them into an array or on the computer.
Then get other captures for 5 minutes duration (one capture every 6
seconds) and compare each capture with the first array.
so far I have this code:
import cv
cv.NamedWindow("Camera", 1)
# in case im using another camera:
cv.NamedWindow("Camera", 2)
capture = cv.CaptureFromCAM(0)
img = cv.QueryFrame(capture)
while True:
img = cv.QueryFrame(capture)
cv.ShowImage("Camera", img)
if cv.WaitKey(10) == 27:
break
cv.DestroyWindow("Camera")
How do I proceed with this? any ideas?
thanks in advance.