-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from vermavinay982/dev
V3.0 time stacking added
- Loading branch information
Showing
5 changed files
with
146 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
Changelog | ||
|
||
V0.3 | ||
- Done | ||
- Added time stack axis | ||
- Display function updated | ||
- Video limit using time duration | ||
- Logs will tell the duration of video written, for human help | ||
- Pending | ||
- Getting the frame out | ||
- Convert into class form | ||
- Axis 3 - shuffle in the middle | ||
|
||
V0.2 | ||
- Done | ||
- If its q or Q it will work well to exit the code | ||
- Multiple videos can be added to stack now | ||
- Size fixed for single video via parameter, Giving the option to choose the size of video for user | ||
- Limit_video index added - that video which will close the code None - infinite code run | ||
- Video writer - when video is over - write the video in the end (if that doesn't work well - we will make it to write continuously | ||
- If fps is fixed - thats fine who cares | if fps not fixed - calculate the fps for video | ||
- Author name changed, gif added, gif created, image uploaded to git, | ||
- added MIT licence so anyone can contribute and use the product https://choosealicense.com/licenses/mit/ | ||
- Pending | ||
- Fixing the size of output video by user - done | ||
- Write one function to loop in the videos and generate frame - thats it - and keep other functions to get input as frame and perform the actions - so if someone wants specific thing - cool they can do that - if not then use the default function - it will use too much ram | ||
- Time based - enter the time in seconds after that it will break the video writing easy but cool - done | ||
- Next time | ||
- Tqdm as requirement to be added | ||
- Sending frame out to be used | ||
- Converting it to class - to enable frame wise stacking - if you want to do directly do hstack vstack - why using this thing? | ||
- Grid based output or people can repeat the activity twice | ||
- Or I can do it for them, run 2 functions in 1 function - find the size - and use it | ||
- Axis 3 = when one frame of one and another of other - thats easy - just append the frame directly into the main stack of frames - run the adding thing twice and both frames will be added at once. - done | ||
|
||
V0.1 | ||
- Added | ||
- Video is streaming so to watch the output | ||
- Vstack and hstack is added as axis 0 and 1 | ||
- q to stop the processing is added | ||
- Future Addition | ||
- It cant work with more than 2 videos - solved | ||
- Getting the frame out, is not possible | ||
- Using the frame as input to create a combined output | ||
- Writing the videos if user passes the path - done | ||
- Choose which video time to be taken as end of video - done |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
numpy | ||
opencv_python | ||
tqdm |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,7 @@ | |
__copyright__ = "Copyright 2021, Vinay Verma" | ||
__credits__ = ["Vinay Verma"] | ||
__license__ = "MIT" | ||
__version__ = "0.1.0" | ||
__version__ = "0.3.0" | ||
__maintainer__ = "Vinay Verma" | ||
__email__ = "[email protected]" | ||
__module_name__ = "[Stack Video]" | ||
|
@@ -13,47 +13,33 @@ | |
import numpy as np | ||
from tqdm import tqdm | ||
|
||
def write_video(frame_list, video_name, output_shape, writer_fps): | ||
def write_video(frame_list, video_name, output_shape, writer_fps, duration): | ||
fourcc = cv2.VideoWriter_fourcc(*"mp4v") | ||
height, width = output_shape | ||
|
||
if duration is not None: | ||
stop_frame = writer_fps * duration | ||
|
||
out = cv2.VideoWriter(video_name, fourcc, int(writer_fps), (width, height)) | ||
frame_counter = 0 | ||
for encoded_frame in tqdm(frame_list): | ||
frame_encoded = np.frombuffer(encoded_frame, np.uint8) | ||
frame = cv2.imdecode(frame_encoded, cv2.IMREAD_COLOR) | ||
out.write(frame) | ||
out.release() | ||
return video_name | ||
|
||
def stack_video( | ||
videos:list=[], | ||
axis:int=0, | ||
size=(300,400), | ||
limit_video=None, | ||
write_path=None, | ||
writer_fps=None, | ||
display=False | ||
)->str: | ||
""" | ||
stack_video | ||
frame_counter+=1 | ||
|
||
if duration is not None: | ||
if frame_counter>stop_frame: | ||
break # Video Duration Achieved | ||
|
||
Write or display the video after stacking it | ||
""" | ||
if limit_video is None and write_path is not None: | ||
print("Cant write an infinite video, Keep a limit video") | ||
return None | ||
out.release() | ||
|
||
frame_list = list() # storing video frames to write | ||
for video in videos: | ||
if not os.path.exists(video): | ||
print(f'Video {video} Not There') | ||
return None | ||
else: | ||
print(f'Video {video} Found') | ||
total_duration = frame_counter/writer_fps | ||
return video_name, total_duration | ||
|
||
caps = [cv2.VideoCapture(cam) for cam in videos] | ||
fps = min([cap.get(cv2.CAP_PROP_FPS) for cap in caps]) | ||
print("Min FPS of Video is :",fps) | ||
def axis_stack(caps, videos, size, axis, display): | ||
frame_list = list() # storing video frames to write | ||
past_frame=[] | ||
start = True | ||
video_over = False | ||
|
@@ -63,23 +49,26 @@ def stack_video( | |
for i,cap in enumerate(caps): | ||
ret, frame = cap.read() | ||
if not ret: | ||
# Video Still Not Over, Loop Again | ||
caps[i] = cv2.VideoCapture(videos[i]) | ||
print('Video Ended, RESTARTING',videos[i]) | ||
frame = past_frame[i] | ||
|
||
# Limiting Video Ended, Stop Now | ||
if i==limit_video: | ||
print(f'{videos[i]} Video Ended, Stopping Now',) | ||
video_over = True | ||
# break # stop for both cams later will buffer | ||
|
||
if start: | ||
# only initialize at start | ||
# Save Past in case of frame drop | ||
start = False | ||
# in case of frame drop | ||
past_frame = [frame for i in videos] | ||
|
||
past_frame[i]=frame | ||
frame = cv2.resize(frame, size) | ||
frames.append(frame) | ||
frames.append(frame) # combined frames in array | ||
|
||
if video_over: break | ||
|
||
|
@@ -90,22 +79,84 @@ def stack_video( | |
resized_frame = np.vstack(frames) | ||
|
||
output_shape = resized_frame.shape[:2] | ||
_, encoded_frame = cv2.imencode('.jpg', resized_frame) | ||
flag, encoded_frame = cv2.imencode('.jpg', resized_frame) | ||
frame_list.append(encoded_frame) | ||
|
||
if display: | ||
cv2.imshow('test',resized_frame) | ||
wait_key = cv2.waitKey(1) | ||
|
||
if ord('q')== wait_key or ord('Q')== wait_key: | ||
if ord('q')==wait_key or ord('Q')==wait_key: | ||
break | ||
return frame_list, output_shape | ||
|
||
def time_stack(caps, videos, size, display): | ||
frame_list = list() # storing video frames to write | ||
for i,cap in enumerate(caps): | ||
while True: | ||
ret, frame = cap.read() | ||
if not ret: | ||
print('Video Ended, Closed',videos[i]) | ||
break # frame is NONE | ||
|
||
resized_frame = cv2.resize(frame, size) | ||
output_shape = resized_frame.shape[:2] | ||
flag, encoded_frame = cv2.imencode('.jpg', resized_frame) | ||
frame_list.append(encoded_frame) | ||
|
||
if display: | ||
cv2.imshow('test',resized_frame) | ||
wait_key = cv2.waitKey(1) | ||
|
||
if ord('q')==wait_key or ord('Q')==wait_key: | ||
break | ||
return frame_list, output_shape | ||
|
||
def stack_video( | ||
videos:list=[], | ||
axis:int=0, | ||
size=(300,400), | ||
limit_video=None, | ||
write_path=None, | ||
writer_fps=None, | ||
display=False, | ||
duration=None | ||
)->str: | ||
""" | ||
stack_video | ||
Write or display the video after stacking it | ||
""" | ||
if limit_video is None and write_path is not None: | ||
print("Cant write an infinite video, Keep a limit video") | ||
return None | ||
|
||
for video in videos: | ||
if not os.path.exists(video): | ||
print(f'Video {video} Not There') | ||
return None | ||
else: | ||
print(f'Video {video} Found') | ||
|
||
caps = [cv2.VideoCapture(cam) for cam in videos] | ||
fps = min([cap.get(cv2.CAP_PROP_FPS) for cap in caps]) | ||
print(f"Min FPS of All Videos is :{fps:.2f}") | ||
|
||
if axis==2: | ||
frame_list, output_shape = time_stack(caps, videos, size, display=display) | ||
|
||
if axis==1: | ||
frame_list, output_shape = axis_stack(caps, videos, size, axis=axis, display=display) | ||
|
||
if axis==0: | ||
frame_list, output_shape = axis_stack(caps, videos, size, axis=axis, display=display) | ||
|
||
if writer_fps is None: | ||
writer_fps = fps | ||
|
||
if write_path: | ||
video_name = write_video(frame_list, write_path, output_shape, writer_fps=writer_fps) | ||
print("Video written sucessfully at :",video_name) | ||
video_name, vid_duration = write_video(frame_list, write_path, output_shape, writer_fps=writer_fps, duration=duration) | ||
print(f"Video written sucessfully at :{video_name} || With Duration {vid_duration:.2f} seconds") | ||
return video_name | ||
|
||
if display: | ||
|
@@ -117,17 +168,19 @@ def stack_video( | |
path1 = '../../../archery.mp4' | ||
path2 = '../../../cars.mp4' | ||
|
||
videos = [path1, path2, path1, path2] | ||
videos = [path1, path2] | ||
video_size = (300,300) # w/h | ||
limit_video = 0 # video index, that will decide to close streaming | ||
video_path = 'test.mp4' | ||
video_duration = 4 # in seconds default None | ||
|
||
output_video = stack_video( | ||
videos, | ||
axis=0, | ||
axis=2, | ||
size=video_size, | ||
limit_video=limit_video, | ||
write_path=video_path, | ||
writer_fps=None, | ||
display=True) | ||
display=True, | ||
duration=video_duration) | ||
print(output_video) |