import cv2, time
import numpy as np
I want to make this code not overwrite the previously saved video
video = cv2.VideoCapture(0)
fourcc = cv2.VideoWriter_fourcc(*"XVID")
This line of code makes the video save as output.avi all the time while I want to make it so that it saves the date of that day
out = cv2.VideoWriter('output.avi', fourcc, 20.0, (640,480))
a = 0
while True:
a = a + 1
check, frame = video.read()
print(check)
print(frame)
out.write(frame)
cv2.imshow("Capturing", frame)
I feel as if I used an if statement somewhere around here then it could make the video no overwrite the previous video however I have tried but it did not work
key = cv2.waitKey(1)
if key == ord('q') :
break
print(a)
video.release()
out.release()
cv2.destroyAllWindows()
I also want to make this code save the video as the current date of day if that is possible
You simply format the filename and put the date in it:
import datetime
filename = 'output_{0}.avi'.format(datetime.datetime.now().strftime("%Y-%m-%d"))
print (filename)
Output:
output_2018-02-25.avi
Then you supply it to your video-create method:
out = cv2.VideoWriter(filename, fourcc, 20.0, (640,480))
Look here for formatting tips for datetime.strftime
Probably best to put it inside a function that gives you the correct name, also checking if that file already exists and eventually adding a running number as well:
import datetime
import os
def getAviNameWithDate(nameIn="output.avi"):
"""Needs a file ending on .avi, inserts _<date> before .avi.
If file exists, it appends a additional _number after the <date>
ensuring filename uniqueness at this time."""
if not nameIn.endswith(".avi"):
raise ValueError("filename must end on .avi")
filename = nameIn.replace(".avi","_{0}.avi")
.format(datetime.datetime.now().strftime("%Y-%m-%d"))
if os.path.isfile(filename): # if already exists
fn2 = filename[0:-4]+'_{0}.avi' # modify pattern to include a number
count = 1
while os.path.isfile(fn2.format(count)): # increase number until file not exists
count += 1
return fn2.format(count) # return file with number in it
else: # filename ok, return it
return filename
# test it
for _ in range(5):
with open(getAviNameWithDate("a.avi"),"w") as w:
w.write("1")
Execute the snippit to see how it creates:
a_2018-02-25.avi
a_2018-02-25_1.avi
a_2018-02-25_2.avi
a_2018-02-25_3.avi
a_2018-02-25_4.avi
Related
I have written a program that uses the web-cam to monitor a machine, and when a movement is detected, I want to save the ‘movement’-frames into a time stamped video.
However, while the program is running, the latest video is viewable, but the previous versions are corrupted.
Ex:
Files:
Movement_11_25_01.avi (corrupted)
Movement_11_28_22.avi (corrupted)
Movement_11_33_21.avi (this is the latest video created, and it is viewable.)
And then another movement is detected;
Files:
Movement_11_25_01.avi (corrupted)
Movement_11_28_22.avi (corrupted)
Movement_11_33_21.avi (corrupted)
Movement_11_35_41.avi (this is the latest video created, and it is viewable.)
This is the code that runs in the end of every motion detected:
out = cv2.VideoWriter('Results\\'+self.name, self.fourcc, self.fps, (self.frame_width, self.frame_height))
print('Len Frames before saving video: ', len(self.frames))
for frame in self.frames:
out.write(frame)
out.release()
self.cap.release()
print('Video saved.')
cv2.destroyAllWindows()
self.frames = list()
# Open up a new instance of VideoCapture
self.cap = cv2.VideoCapture(file_path, cv2.CAP_DSHOW)
I suspect that the corruption is related to how the video file is stored while the program is running, but I cannot figure out how to save a video, close the connection to that file, and then create a new file.
Any help is apprichiated!
I have tried to close the cap = cv2.VideoCapture() and the out = cv2.VideoWriter('Results\\'+self.name, self.fourcc, self.fps, (self.frame_width, self.frame_height)) by running cap.release() and
out.release() but with no success. Only when the program is terminated, a uncurrupted file is generated, and it is the most recent file.
Edit 2022-11-07:
Here is an MRE that i run on windows 10, with Python 3.10.6, together with the modules numpy (1.23.2) and opencv-python (4.6.0.66).
I have noticed that in this MRE, the first file is saved in a workable format. However, the second and third file is corrupted. The main issue is the same, but reversed.
import cv2
import numpy as np
import time
from datetime import datetime
file_path = 0
cap = cv2.VideoCapture(file_path, cv2.CAP_DSHOW) # create a capture instance
startTime = time.time() # Starttider
date_time = datetime.fromtimestamp(startTime)
frames = list()
image = list()
frame_width = int( cap.get(cv2.CAP_PROP_FRAME_WIDTH))
frame_height =int( cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = 30
for _ in range(3):
# Get some images
for _ in range(60):
_, frame = cap.read()
frames.append(frame)
# Initiate a video file
fourcc = cv2.VideoWriter_fourcc('X','V','I','D')
date_time = datetime.fromtimestamp(time.time())
name = "v2Motiondetect_output"+str(date_time.strftime("%d-%m-%Y__ %H_%M_%S") )+ ".avi"
out = cv2.VideoWriter(name, fourcc, fps, (frame_width, frame_height))
print('Len Frames before saving video: ', len(frames))
# Write out all frames
for frame in frames:
out.write(frame)
print('Video Capture before ending program: ', out)
print('Frames before ending program: ', id(frames))
out.release()
cap.release()
print('Video Capture after ending program: ', out)
print('Frames after ending program: ', id(frames))
frames = list()
print('frames after it is overwritten with an empty list object:', id(frames))
cv2.destroyAllWindows()
time.sleep(2) # Needed to ensure different timestamps
I have code like this. I know it's not correct, but I'm new at this and not sure how to fix it. How do I make it so cv2 runs on every video I have in a folder, taking a frame every 3 seconds, and saving the frame images in a new folder within /data/ --- ex. /data/rise_of_skywalker?
Thanks
import cv2
import numpy as np
import os
def frame_capture(file):
cap = cv2.VideoCapture(file)
try:
if not os.path.exists('data'):
os.makedirs('data')
except OSError:
print('Error: Creating directory of data')
currentFrame = 0
while(True):
# Capture frame by frame
ret, frame = cap.read()
'''
(((how do I change this block here to get it for every 3 seconds?)))
'''
if currentFrame == 5:
name = './data/frame' + str(currentFrame) + '.jpg'
print ('Creating...' + name)
cv2.imwrite(name, frame)
# To stop duplicate images
currentFrame += 1
cap.release()
cv2.destroyAllWindows()
print ("Done!")
for file in os.listdir("/users/x/Desktop/y/videos"):
if file.endswith(".mp4"):
path=os.path.join("/users/x/Desktop/y/videos", file))
frame_capture(path)
If I understand correctly, what you want to do is to change the line if currentFrame == 5: to if currentFrame % (3 * fps) == 0:
And before that line, outside the loop, add fps = cap.get(cv2.CAP_PROP_FPS)
I want to convert my input video to a set of frames. I have read the post on
Python - Extracting and Saving Video Frames.
But I would like to have a function where I can insert the video as the parameter, not the location of the video file.
In the VideoCapture function below, it takes in the location of the video file.
import cv2
def vidtoframes(videoFile):
vidcap = cv2.VideoCapture(videoFile)
success,image = vidcap.read()
count = 0
while success:
cv2.imwrite("frame%d.jpg" % count, image) # save frame as JPEG file
success,image = vidcap.read()
print('Read a new frame: ', success)
count += 1
But is there a function or way to pass a video to the method and convert it to array of frames without saving anything onto the disk.
The video that is taken must be saved to a directory and then we can perform the functions upon it. That is how an application would work as well.
OO approch: write a sort of "VideoWrapper" class and derived classes:
from abc import abstractmethod
class VideoWrapper:
def __init__(self, path: str, chunk_size: int = 1):
self.path = path
self.chunk_size = chunk_size
#abstractmethod
def __iter__(self): ...
class VideoFileWrapper(VideoWrapper):
def __iter__(self):
chunk = []
cap = cv2.VideoCapture(self.path)
while cap.isOpened():
ret, frame = cap.read()
chunk.append(frame)
if len(chunk) == self.chunk_size:
yield chunk
chunk = []
class VideoFolderWrapper(VideoWrapper):
def __iter__(self):
chunk = []
for frame_path in glob(os.path.join(self.path, '*')):
frame = cv2.imread(frame_path)
chunk.append(frame)
if len(chunk) == self.chunk_size:
yield chunk
chunk = []
in that case you could pass a single class type across your code.
an even nicer class would implement __enter__ and __exit__ methods in order to use the with statement, exception handling and so on. that might be too much, a simpler "Pythonic" version will be:
def video_wrapper(path):
if os.path.isdir(path):
frames = list(glob(os.path.join(path, '*.png')))
frames.sort(key=file_name_order)
for frame_path in frames:
frame = cv2.cvtColor(cv2.imread(frame_path),cv2.COLOR_BGR2RGB)
yield frame
elif os.path.exists(path):
cap = cv2.VideoCapture(path)
while cap.isOpened():
ret, frame = cap.read()
yield frame
Yes! There is! But it will require a wee bit of setup. Everything is detailed here:
Streaming video in memory with OpenCV VideoWriter and Python BytesIO
The basics are that you need a tmpfs partition in linux, and utilize the tempfile functionality of Python (which just wraps mkstemp in linux again).
If you have a video file in memory already, something like:
video_bytes = s3.download('file.avi')
And just want to deal with it in memory (and continue to use OpenCV), then check out the other post I listed above.
Aim : Detect the motion and save only the motion periods in files with names of the starting time.
Now I met the issue about how to save the video to the files with video starting time.
What I tested :
I tested my program part by part. It seems that each part works well except the saving part.
Running status: No error. But in the saving folder, there is no video. If I use a static saving path instead, the video will be saved successfully, but the video will be override by the next video. My codes are below:
import cv2
import numpy as np
import time
cap = cv2.VideoCapture( 0 )
bgst = cv2.createBackgroundSubtractorMOG2()
fourcc=cv2.VideoWriter_fourcc(*'DIVX')
size = (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
n = "start_time"
while True:
ret, frame = cap.read()
dst = bgst.apply(frame)
dst = np.array(dst, np.int8)
if np.count_nonzero(dst)>3000: # use this value to adjust the "Sensitivity“
print('something is moving %s' %(time.ctime()))
path = r'E:\OpenCV\Motion_Detection\%s.avi' %n
out = cv2.VideoWriter( path, fourcc, 50, size )
out.write(frame)
key = cv2.waitKey(3)
if key == 32:
break
else:
out.release()
n = time.ctime()
print("No motion Detected %s" %n)
What I meant is:
import cv2
import numpy as np
import time
cap = cv2.VideoCapture( 0 )
bgst = cv2.createBackgroundSubtractorMOG2()
fourcc=cv2.VideoWriter_fourcc(*'DIVX')
size = (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)),int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
path = r'E:\OpenCV\Motion_Detection\%s.avi' %(time.ctime())
out = cv2.VideoWriter( path, fourcc, 16, size )
while True:
ret, frame = cap.read()
dst = bgst.apply(frame)
dst = np.array(dst, np.int8)
for i in range(number of frames in the video):
if np.count_nonzero(dst)<3000: # use this value to adjust the "Sensitivity“
print("No Motion Detected")
out.release()
else:
print('something is moving %s' %(time.ctime()))
#label each frame you want to output here
out.write(frame(i))
key = cv2.waitKey(1)
if key == 32:
break
cap.release()
cv2.destroyAllWindows()
If you see the code there will be a for loop, within which the process of saving is done.
I do not know the exact syntax involving for loop with frames, but I hope you have the gist of it. You have to find the number of frames present in the video and set that as the range in the for loop.
Each frame gets saved uniquely (see the else condition.) As I said I do not know the syntax. Please refer and follow this procedure.
Cheers!
anybody familiar with openCV know how to make it so the output is a different file each time. OR how to make it so the video appends to the original one.
here is the code I am working with
import RPi.GPIO as GPIO
import cv2
import numpy as np
import datetime
import time
GPIO.setmode(GPIO.BOARD)
GPIO.setup(11,GPIO.IN)
import os
# Setup the camera such that it closes
# when we are done with it.
os.chdir ("/home/pi/Videos")
cap = cv2.VideoCapture(0)
fourcc = cv2.VideoWriter_fourcc(*'MJPG')
while True:
if GPIO.input(11) == 1:
filename = datetime.datetime.now() .strftime ("%Y-%m-%d-%H.%M.%$
print("about to record")
out = cv2.VideoWriter('video.avi', fourcc, 20.0, (640,480))
ret, frame = cap.read()
if ret==True:
out.appendleft(frame)
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q') or GPIO.input(11) $
break
else:
break
else:
break
cap.release()
out.release()
cv2.destroyAllWindows()
thanks in advance for any and all help!
This function will store data in a progressive filename system
from os import path
def open_next_file(someData, template='incomingVideo{}.jpg'):
"""Creates a new file for storing new Firmware."""
## Store upto 100 file names
for serial in range(100):
if not path.exists(template.format(serial)):
## if file does not exist,
## enter data into the new file
with open(template.format(serial), 'wb+') as f:
f.write(someData)
break
else:
## if file already exists then,
## don't write on existing files
pass
return template.format(serial)
you can call this function everytime you want to write a new data to a new file viz. incomingVideo1.jpg or incomingVideo2.jpg
You can change the parameters according your needs.
Example
newFile = open_next_file(someDat="Write this inside")
print(newFile)
gives result as incomingVideoX.jpg where x depends on range() function in the loop