OpenCV - Save video segments based on certion condition - python

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!

Related

When using VideoWriter in opencv-python the output video length is 0

I'm trying to read a video, put some shapes on it and write it out using opencv-python (using VideoWriter class):
def Mask_info(path):
"""This function will mask the information part of the video"""
video = cv.VideoCapture(path)
framenum = video.get(cv.CAP_PROP_FRAME_COUNT)
fps = video.get(cv.CAP_PROP_FPS)
fourcc = cv.VideoWriter_fourcc(*"vp09")
width = int(video.get(cv.CAP_PROP_FRAME_WIDTH))
height = int(video.get(cv.CAP_PROP_FRAME_HEIGHT))
size = (width,height)
if (video.isOpened ==False ):
print("Error while reading the file.")
result = cv.VideoWriter("masked_video.mp4",fourcc,fps,size)
while(True):
isTrue,frame = video.read()
cv.rectangle(frame,(65,0),(255,10),(0,0,0),-1)
cv.rectangle(frame,(394,0),(571,10),(0,0,0),-1)
if isTrue == True:
result.write(frame)
cv.imshow("Masked Video",frame)
if cv.waitKey(1) & 0xFF == ord("d"):
break
else:
break
video.release()
result.release()
cv.destroyAllWindows()
Mask_info("samplesound.webm")
The problem is that the output video length is zero, while the input video is 10 seconds.
To elaborate on my comment above:
You should verify that video.read() returns any valid frame.
It could be that due to path or other issue the VideoCapture failed to open the input file.
You attempt to draw the rectangles (using cv.rectangle) before the if that checks whether you have a valid frame.
But if video.read() failed (e.g. when reaching the end of the input) frame will be None. Then cv.rectangle will throw an exception causing the program to terminate without flushing and closing the output file.
Instead you should do the drawings inside the isTrue == True branch of the if:
if isTrue == True:
cv.rectangle(frame,(65,0),(255,10),(0,0,0),-1)
cv.rectangle(frame,(394,0),(571,10),(0,0,0),-1)
result.write(frame)
# ...

When saving multiple videos with OpenCV, it corrupts the previous generated video. Is it solvable?

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

How to restrict a camera on capturing and not capturing images on python, opencv?

I have a camera that faces an LED sensor that I want to restrict on capturing images when the object is in sight otherwise not capturing. I will designate a point or region where the color pixels will change as an object arrives it will wait for 3sec and then capture. Thereafter it will not capture the same object if it still remains in the designated region. Here are my codes.
import cv2
import numpy as np
import os
os.chdir('C:/Users/Man/Desktop')
previous_flag = 0
current_flag = 0
a = 0
video = cv2.VideoCapture(0)
while True:
ret, frame = video.read()
rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
cv2.imshow('Real Time', rgb)
cv2.waitKey(1)
if(rgb[400, 200, 0]>200): # selecting a point that will change in terms of pixel values
current_flag = 0
previous_flag = current_flag
print('No object Detected')
else: # object arrived
current_flag = 1
change_in_flags = current_flag - previous_flag
if(change_in_flags==1):
time.sleep(3)
cv2.imwrite('.trial/cam+str(a).jpg', rgb)
a += 1
previous_flag = current_flag
video.release()
cv2.destroyAllWindows()
When I implement the above program, for the first case (if) it prints several lines of No object Detected.
How can I reduce those sequentially printed lines for No object Detected statement? So that the program can just print one line without repetition.
I also tried to add a while loop to keep the current status true after a+=1 like:
while True:
previous_flag = current_flag
continue
It worked but the system became so slow is there any way to avoid such a while loop such that the system becomes faster? Any advice on that
import cv2
import numpy as np
import os
os.chdir('C:/Users/Man/Desktop')
state1=0
a = 0
video = cv2.VideoCapture(0)
while True:
ret, frame = video.read()
rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
cv2.imshow('Real Time', rgb)
cv2.waitKey(1)
if(rgb[400, 200, 0]>200): # selecting a point that will change in terms of pixel values
if(state1 == 0):
print('No object Detected')
state1=1
else: # object arrived
time.sleep(1)
if(state1==1)
print('Object is detected')
cv2.imwrite('./trial/cam+str(a).jpg', rgb)
a += 1
state1=0
video.release()
cv2.destroyAllWindows()

video to images then images to video in python

I'm trying to convert the following video to images
https://www.signingsavvy.com/media/mp4-ld/24/24851.mp4
however, I have done it by using OpenCV
# Importing all necessary libraries
import cv2
import os
# Read the video from specified path
cam = cv2.VideoCapture("C:\Users\ahmad\Hi_ASL.mp4")
print(cam.get(cv2.CAP_PROP_FPS))
try:
# creating a folder named data
if not os.path.exists('data'):
os.makedirs('data')
# if not created then raise error
except OSError:
print ('Error: Creating directory of data')
# frame
currentframe = 0
while(True):
# reading from frame
ret,frame = cam.read()
if ret:
# if video is still left continue creating images
name = './data/frame' + str(currentframe) + '.jpg'
# print ('Creating...' + name)
# writing the extracted images
cv2.imwrite(name, frame)
# increasing counter so that it will
# show how many frames are created
currentframe += 1
else:
break
# ret,frame = cam.read()
# Release all space and windows once done
cam.release()
cv2.destroyAllWindows()
After I have done it. I want to convert those images to video to be like the one above and I wrote this code
img = [img for img in os.listdir('data')]
frame = cv2.imread('data\' + img[0])
h , w , l = frame.shape
vid = cv2.VideoWriter('hiV.mp4' , 0 ,1 ,(w,h))
for imgg in img:
vid.write(cv2.imread('data\' + imgg))
cv2.destroyAllWindows()
vid.release()
The problem is the result of combining the images to a video using OpenCV is not the same as the original video. So, what is the problem? I want it to be the same as the original one.
The result of the code above is this video https://drive.google.com/file/d/16vwT35wzc95tBleK5VCpZJQkaLxSiKVd/view?usp=sharing
And thanks.
You should change cv2.VideoWriter('hiV.mp4' , 0 ,1 ,(w,h)) to cv2.VideoWriter('hiV.mp4' , 0 ,30 ,(w,h)) As the 1 sets the fps and that means that you write 1 frame every second and not 30 or 29.97(NTSC) as the original video.

Grab video frames from all videos in folder, process with openCV, save to own folder?

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)

Categories

Resources