Skip to content

Commit

Permalink
Merge pull request #4 from vermavinay982/dev
Browse files Browse the repository at this point in the history
V3.0 time stacking added
  • Loading branch information
vermavinay982 authored Sep 18, 2021
2 parents b1f69ae + 1cede33 commit ff14492
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 43 deletions.
46 changes: 46 additions & 0 deletions CHANGELOG.md
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
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,17 +65,20 @@ path2 = '../../../cars.mp4'

videos = [path1, path2, path1, path2]
video_size = (300,300) # w/h
limit_video = 0 # video index of video that will decide to close streaming
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)
```


Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
numpy
opencv_python
tqdm
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

setup(
name='vigenpy',
version='0.2.4',
version='0.3.0',
description=short_desc,
license='MIT',
long_description=long_desc,
Expand Down
131 changes: 92 additions & 39 deletions vigenpy/video/stack_video.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__ = "vermavinay982@gmail.com"
__module_name__ = "[Stack Video]"
Expand All @@ -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
Expand All @@ -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

Expand All @@ -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:
Expand All @@ -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)

0 comments on commit ff14492

Please sign in to comment.