How do you perform Multithreaded Frame Extraction in Python with OpenCV? - python

Hi Stackoverflow Users,
I'm currently trying to perform a multithreaded frame extraction using OpenCV. I've made such multithreaded operations before on other tasks, but for some reason it doesnt seem to work on the frame extraction. This is my Code:
import cv2
import os
import face_recognition
from PIL import Image
import multiprocessing
try:
if not os.path.exists('frames'):
os.makedirs('frames')
except OSError:
print('Error: Creating directory of frames')
try:
if not os.path.exists('faces'):
os.makedirs('faces')
except OSError:
print('Error: Creating directory of faces')
def frame_extract_1():
currentFrame_extract = 1
video_capture = cv2.VideoCapture("DOLFACE_1.mp4")
while(True):
ret1, frame = video_capture.read()
if ret1 == False:
break
name = 'frames/frame_' + str(currentFrame_extract) + '.jpg'
print(f"Processor 1 extracted Frame {currentFrame_extract}, saving it as Frame_{currentFrame_extract}.jpg")
cv2.imwrite(name, frame)
currentFrame_extract += 4
video_capture.release()
cv2.destroyAllWindows()
def frame_extract_2():
currentFrame_extract = 2
video_capture = cv2.VideoCapture("DOLFACE_1.mp4")
while(True):
ret2, frame = video_capture.read()
if ret2 == False:
break
name = 'frames/frame_' + str(currentFrame_extract) + '.jpg'
print(f"Processor 2 extracted Frame {currentFrame_extract}, saving it as Frame_{currentFrame_extract}.jpg")
cv2.imwrite(name, frame)
currentFrame_extract += 4
video_capture.release()
cv2.destroyAllWindows()
def frame_extract_3():
currentFrame_extract = 3
video_capture = cv2.VideoCapture("DOLFACE_1.mp4")
while(True):
ret3, frame = video_capture.read()
if ret3 == False:
break
name = 'frames/frame_' + str(currentFrame_extract) + '.jpg'
print(f"Processor 3 extracted Frame {currentFrame_extract}, saving it as Frame_{currentFrame_extract}.jpg")
cv2.imwrite(name, frame)
currentFrame_extract += 4
video_capture.release()
cv2.destroyAllWindows()
def frame_extract_4():
currentFrame_extract = 4
video_capture = cv2.VideoCapture("DOLFACE_1.mp4")
while(True):
ret4, frame = video_capture.read()
if ret4 == False:
break
name = 'frames/frame_' + str(currentFrame_extract) + '.jpg'
print(f"Processor 4 extracted Frame {currentFrame_extract}, saving it as Frame_{currentFrame_extract}.jpg")
cv2.imwrite(name, frame)
currentFrame_extract += 4
video_capture.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
video_file_path = "DOLFACE_1.mp4"
frame_extractor_1 = multiprocessing.Process(target=frame_extract_1)
frame_extractor_2 = multiprocessing.Process(target=frame_extract_2)
frame_extractor_3 = multiprocessing.Process(target=frame_extract_3)
frame_extractor_4 = multiprocessing.Process(target=frame_extract_4)
frame_extractor_1.start()
frame_extractor_2.start()
frame_extractor_3.start()
frame_extractor_4.start()
frame_extractor_1.join()
frame_extractor_2.join()
frame_extractor_3.join()
frame_extractor_4.join()
Do you know what I am doing wrong? Every "Processor" creates the full Video, without skipping 4 Frames and letting the other Processors do the remaining 3.

Related

Save a video with different file name each time we give a Trigger in opencv

This is the process I am trying to achieve :
Live Stream is captured from webcam and the Image frames are stored in a particular folder.
Now, If I give a trigger the frames in that folder at that moment should be converted into a video and get saved with name eg. video1.mp4.
Now again if I press a trigger another video should be saved as video2.mp4.
I have attached the code here . If I press R , it is saving one video as a0.mp4 . But If I press again, nothing seems to happen.
def frametovideo(img_array):
for i in range(len(img_array)):
out.write(img_array[i])
if name == "main":
img_array = []
videono = 0
cap = cv2.VideoCapture(0)
for filename in glob.glob('./output/*.jpg'):
img = cv2.imread(filename)
height, width, layers = img.shape
size = (width,height)
img_array.append(img)
path = 'a' + str(videono) + '.mp4'
out = cv2.VideoWriter(path,cv2.VideoWriter_fourcc(*'mp4v'), 15, size)
while True:
ret, frame = cap.read()
if ret == True:
cv2.imshow("frame",frame)
k = cv2.waitKey(5) & 0xff
if k == ord('r'):
frametovideo(img_array)
videono += 1
You do not understanding how to save filenames Do not used operator. Used string format python 3.8 or later. Try this in below. Actually, you can modified key press.
import cv2
import os
i = 1
wait = 0
video = cv2.VideoCapture(0)
while video.isOpened():
ret, img = video.read()
cv2.imshow('live video', img)
# wait for user to press any key
key = cv2.waitKey(100)
# wait variable is to calculate waiting time
wait = wait+100
if key == ord('q'):
break
# when it reaches to 5000 milliseconds
# we will save that frame in given folder
if wait == 5000:
filename = f'Frame_{str(i)}.jpg'
# Save the images in given path
cv2.imwrite(filename, img)
i += 1
wait = 0
# close the camera
video.release()
# close open windows
cv2.destroyAllWindows()
Btw,look in line #27-34. Correct way to do this if __name__ == "__main__":

Stop video by its play time

I created a program to extract the video into frames.I need suggestion to stop the cv2.imshow() after when there is no more frames to show.
video frames count = 88
fps = 10.0
duration= int(8)
def reading_video():
read_input = cv2.VideoCapture(r"D:\data\input.mp4")
frame_rate = int(read_input.get(cv2.CAP_PROP_FRAME_COUNT)) # 88
print("total number of frames is ", frame_rate)
fps = read_input.get(cv2.CAP_PROP_FPS) #10.0
duration = int((frame_rate/fps) %60)# 8
print(duration) # 8.0
initial_frame = 0
while read_input.isOpened():
ret, frame = read_input.read()
if ret == True:
cv2.imshow('video_frame', frame)
write_path = r"D:\data\frame_output"
write_name = 'frame0' + str(initial_frame) + '.jpg'
cv2.imwrite(os.path.join(write_path, write_name), frame)
initial_frame += 1
if cv2.waitKey(0) & 0xFF == ord('c'):
break
else:
break
instance_variable = reading_video()
instance_variable.release()
cv2.destroyAllWindows()
If waitkey(int(duration)) then it played and after no frame i do getting cv2 Assertion error.
If waitkey(0) then i do getting AttributeError: 'NoneType' object has no attribute 'release'
reading_video() doesn't uses return so it returns None and you have
instance_variable = None
and later
None.release()
Inside reading_video() you should use
return read_input
or maybe even directly
read_input.release()
without instance_variable.release()

Extracting images from camera video at predetermined intervals

I have the code to get images from the video stream of a laptop camera. I want to reduce the photo saving interval to one photo per minute. The original code looks like this
# Importing all necessary libraries
import cv2
import os
# Read the video from specified path
cam = cv2.VideoCapture(0)
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
# Release all space and windows once done
cam.release()
cv2.destroyAllWindows()
For this task I try to use the parameter CAP_PROP_POS_MSEC
[...]
# Read the video from specified path
cam = cv2.VideoCapture(0)
cam.set(cv2.CAP_PROP_POS_MSEC,20000)
[...]
while(True):
[...]
# writing the extracted images
cv2.imwrite(name, frame)
cv2.waitKey()
[...]
But, the saving speed remains the same and I see the following error
videoio error v4l2 property pos_msec is not supported
I use Ubuntu 18.04, Python 3.7, and OpenCV 4.1.
Where do I have a mistake, and whether I chose the right way to minimize the load on my computer's resources?
UPD
Using the recommendation of J.D. this code is working
import cv2
import os
import time
prev_time = time.time()
delay = 1 # in seconds
# Read the video from specified path
cam = cv2.VideoCapture(0)
currentframe = 0
while (True):
# reading from frame
ret, frame = cam.read()
if ret:
if time.time() - prev_time > delay:
# 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)
currentframe += 1
prev_time = time.time()
else:
break
EDIT: this answer is not a good solution - due to the frame buffer, as described in the comments. Because of the relevant information in the comments I will leave the answer.
If you don't plan to expand the code to do other things, you can just use the waitkey:
cv2.waitKey(60000) will freeze code execution 60 secs.
If you want to expand the code, you have to create a time based loop:
import time
prev_time = time.time()
count = 0
delay = 1 # in seconds
while True:
if time.time()-prev_time > delay:
count += 1
print(count)
prev_time = time.time()
you should read separately and set the values again for each image, like this:
while(True):
cam = cv2.VideoCapture(0)
cam.set(cv2.CAP_PROP_POS_MSEC,20000)
# 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)
cv2.waitKey()
# increasing counter so that it will
# show how many frames are created
currentframe += 1
else:
break
cam.release()
and check your openCV version for python about the error.

How to rewind a video in OpenCV Python in 2019?

I know there are many similar questions asked in 2012 or something.
It is 2019, and in 2012, the only solution was to store the frames in memory or write them and then read them in reverse order.
But I was wondering, if there is a new function to read OpenCV frames in reverse order.
I am looking for a solution something like this:
if rewind == False:
ret,frame = cap.read()
else:
ret,frame = cap.read(rewind=True)
Any solution similar to this one?
or something like this:
if rewind == False:
ret,frame = cap.read()
else:
cap.goBackOneFrame()
ret,frame = cap.read()
Edit:
I tried
if rewind == False:
ret, frame = cap.read() #Read frame
counter += 1
else:
cap.set(cv2.CAP_PROP_POS_FRAMES, counter-1)
counter -= 1
ret, frame = cap.read()
and it works, but the rewind speed is slow. I think my PC is taking more time in processing it?
import cv2
# Grab the current frame.
my_check , vid = cap.read()
# use counter variable for
# Counting frames
counter = 0
check = True
frame_list = []
while(check == True):
cv2.imwrite("frame%d.jpg" %counter , vid)
check , vid = cap.read()
frame_list.append(vid)
# increment the counter by 1
counter += 1
frame_list.pop()
# looping in the List of frames.
for frame in frame_list:
# show the frame.
cv2.imshow("Frame" , frame)
if cv2.waitKey(25) and 0xFF == ord("q"):
break
cap.release()
# close any open windows
cv2.destroyAllWindows()
frame_list.reverse()
for frame in frame_list:
cv2.imshow("Frame" , frame)
if cv2.waitKey(25) and 0xFF == ord("q"):
break
cap.release()
cv2.destroyAllWindows()

How to differentiating and storing the differentiated frames in a specified place

Have attached the source code for frame differentiating and storing the differentiated frames in a specified place but am getting an error in indentation of error..post this problem as a question in stack overflow..i am restricted to question for a particular period..upload the code too
filename.py
import cv2
import os
import glob
def extractFrames(pathIn, pathOut):
os.mkdir(pathOut)
cap = cv2.VideoCapture(pathIn)
count = 0
while (cap.isOpened()):
# Capture frame-by-frame
ret, frame = cap.read()
current_frame_gray = cv2.cvtColor(current_frame, cv2.COLOR_BGR2GRAY)
previous_frame_gray = cv2.cvtcolor(previous_frame, cv2.COLOR_BGR2GRAY)
frame_diff = cv2.absdiff(current_frame_gray,previous_frame_gray)
if ret == True:
print('Read %d frame: ' % count, ret)
cv2.imwrite(os.path.join(pathOut, "frame{:d}.jpg".format(count)), frame_diff) # save frame as JPEG file
count += 1
else:
break
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()
def main():
extractFrames('C:/Users/yaazmoha/Desktop/BE PROJECT/INPUT/Tiger in field(1080P_HD).mp4', 'fd3')
if __name__=="__main__":
main()
Fixed your code. You had some indentation errors. Since Python does not use braces like C++, it requires proper indentation to separate code.
import cv2
import os
import glob
def extractFrames(pathIn, pathOut):
os.mkdir(pathOut)
cap = cv2.VideoCapture(pathIn)
count = 0
while (cap.isOpened()):
# Capture frame-by-frame
ret, current_frame = cap.read()
current_frame_gray = cv2.cvtColor(current_frame, cv2.COLOR_BGR2GRAY)
if count > 1:
previous_frame_gray = cv2.cvtcolor(previous_frame, cv2.COLOR_BGR2GRAY)
frame_diff = cv2.absdiff(current_frame_gray,previous_frame_gray)
if ret == True:
print('Read %d frame: ' % count, ret)
cv2.imwrite(os.path.join(pathOut, "frame{:d}.jpg".format(count)), frame_diff) # save frame as JPEG file
count += 1
else:
break
previous_frame = current_frame
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()
def main():
extractFrames(r"C:\Users\mathesn\Downloads\Wildlife.mp4", 'fd3')
if __name__=="__main__":
main()
I took liberties to fix other sections of your code. But there are some other fixes that this code needs, like creating a directory only if it doesn't exist, maintaining a colored version of the frame so that cv2.cvtColor() does not fail, etc., but I''ll leave those to you.

Categories