1+ import imageio
2+ import numpy as np
3+ import time
4+ import os
5+ import math
6+ import glob
7+
8+ from PIL import Image
9+
10+ frames_between_keyframes = 60
11+ maximum_keyframe_number = 728
12+ zoom_scale = 2.0
13+
14+ # log1.1 of 2 is 7.27
15+ # 60 / that is 8.25, so lets take 8 frames per keyframe
16+
17+ # Arguments for ffmpeg
18+ kargs = {
19+ 'macro_block_size' : 8 ,
20+ 'fps' : 60 ,
21+ 'format' : 'FFMPEG' ,
22+ 'quality' : 8
23+ }
24+
25+ t0 = time .time ()
26+
27+ segment = 0
28+ segment_names = []
29+
30+ framebuffer = []
31+
32+ writer = imageio .get_writer (f"segment_{ segment :08} .mp4" , ** kargs )
33+ segment_names .append (f"segment_{ segment :08} .mp4" )
34+
35+ files = glob .glob ("output/*.png" )
36+ files .sort ()
37+
38+ # We start with the previous image, this is modified
39+ previous_keyframe = Image .open (files [0 ])
40+
41+ (width , height ) = (previous_keyframe .width , previous_keyframe .height )
42+ (scaled_width , scaled_height ) = (int (zoom_scale * width ), int (zoom_scale * height ))
43+
44+ val1 = (scaled_width - width ) // 2
45+ val2 = (scaled_height - height ) // 2
46+
47+ placement_box = (val1 , val2 , val1 + width , val2 + height )
48+
49+ for i in range (0 , maximum_keyframe_number ):
50+ # Creates 10 second segments
51+ if (i * frames_between_keyframes ) % 600 == 0 and i != 0 :
52+ # Add current_framebuffer frames
53+ for frame in reversed (framebuffer ):
54+ writer .append_data (frame )
55+
56+ segment += 1
57+
58+ framebuffer = []
59+
60+ # Writer for adding frames to the video
61+ writer = imageio .get_writer (f"segment_{ segment :08} .mp4" , ** kargs )
62+ segment_names .append (f"segment_{ segment :08} .mp4" )
63+
64+ next_keyframe = Image .open (files [i + 1 ])
65+
66+ # This has to be nearest
67+ scaled_keyframe = next_keyframe .resize ((scaled_width , scaled_height ), resample = Image .NEAREST )
68+
69+ scaled_keyframe .paste (previous_keyframe , placement_box )
70+
71+ current_scale = zoom_scale
72+ factor = 10 ** (math .log10 (zoom_scale ) / frames_between_keyframes )
73+
74+ for j in range (0 , frames_between_keyframes ):
75+ # zoom = 1.0 + (2**(1.0 - j / frames_between_keyframes) - 1.0) * (zoom_scale - 1.0)
76+ # zoom = zoom_scale**(1.0 - j / frames_between_keyframes)
77+ # zoom = zoom_scale**((1.0 - j / frames_between_keyframes))
78+ current_scale /= factor
79+
80+ temp1 = (1.0 - 1.0 / current_scale ) * (scaled_width // 2 )
81+ temp2 = (1.0 - 1.0 / current_scale ) * (scaled_height // 2 )
82+ temp3 = scaled_width - temp1
83+ temp4 = scaled_height - temp2
84+
85+ next_frame = scaled_keyframe .crop ((temp1 , temp2 , temp3 , temp4 )).resize ((width , height ), resample = Image .LANCZOS )
86+
87+ framebuffer .append (np .array (next_frame ))
88+
89+ elapsed = time .time () - t0
90+ print (f"{ i * frames_between_keyframes + j + 1 } /{ maximum_keyframe_number * frames_between_keyframes + 1 } { elapsed :.2f} s { ((i * frames_between_keyframes + j + 1 )/ elapsed ):.2f} fps" )
91+
92+ previous_keyframe = scaled_keyframe .resize ((width , height ), resample = Image .LANCZOS )
93+
94+
95+ framebuffer .append (np .array (previous_keyframe ))
96+
97+ for frame in reversed (framebuffer ):
98+ writer .append_data (frame )
99+
100+ with open ('segments.txt' , 'w' ) as f :
101+ for segment in reversed (segment_names ):
102+ f .write (f"file '{ segment } '\n " )
103+
104+ writer .close ()
105+
106+ elapsed = time .time () - t0
107+ print (f"{ maximum_keyframe_number * frames_between_keyframes + 1 } /{ maximum_keyframe_number * frames_between_keyframes + 1 } { elapsed :.2f} s { ((maximum_keyframe_number * frames_between_keyframes + 1 )/ elapsed ):.2f} fps" )
108+
109+ os .system ("ffmpeg -y -f concat -safe 0 -i segments.txt -c copy output.mp4" )
0 commit comments