Advertisement
Guest User

Untitled

a guest
May 4th, 2021
67
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 10.12 KB | None | 0 0
  1. import os
  2. from datetime import datetime, timedelta
  3. import time
  4. import subprocess
  5. from PIL import Image, ImageDraw, ImageFont
  6. import numpy as np
  7. from math import radians, floor, ceil
  8. from easing_functions import CubicEaseInOut
  9. from moviepy.editor import ImageSequenceClip, VideoClip
  10.  
  11.  
  12. def pol2cart(r, phi):
  13.     x = r * np.cos(phi)
  14.     y = r * np.sin(phi)
  15.     return(x, y)
  16.  
  17.  
  18. def maprange(a, b, s):
  19.     (a1, a2), (b1, b2) = a, b
  20.     return b1 + ((s - a1) * (b2 - b1) / (a2 - a1))
  21.  
  22.  
  23. def calc_ellipse_coords(r, a, width):
  24.     width = width - 2
  25.     x1, y1 = pol2cart(r - 2, radians(a - 90))  # r - 2
  26.     x2, y2 = pol2cart(r - width, radians(a - 90))
  27.     ax, ay = (r + x2 + (x1 - x2) / 2), (r + y2 + (y1 - y2) / 2)
  28.     left_corner = (ax - width / 2, ay - width / 2)
  29.     right_corner = (ax + width / 2, ay + width / 2)
  30.     return left_corner, right_corner
  31.  
  32.  
  33. def draw_fade_in_frames(background, starting_from, n_frames):
  34.     # 0.5 second of fade in animation -----------------------
  35.     for f in range(starting_from, n_frames):
  36.         img = background.copy()
  37.         draw = ImageDraw.Draw(img, mode='RGBA')
  38.         # draw numbers
  39.         draw.text((x, y), f"{00:02}:{00:02}", fill=red, font=font)
  40.         # draw dot
  41.         color = (255, 0, 0, ceil(maprange([0, n_frames], [0, 255], f)))
  42.         draw.ellipse((dims[0]/2 - width / 2 + 1, 0, dims[0]/2 + width / 2 - 1, width - 1),
  43.                         fill=color, outline=None, width=0)
  44.  
  45.         if antialiasing:
  46.             img = img.resize(
  47.                 (dims[0] // multiplier, dims[1] // multiplier),
  48.                 antialiasing
  49.             )
  50.         img.save(f'img/{f}.jpg')
  51.  
  52.  
  53. def draw_in_anim_frames(background, starting_from, n_frames):
  54.     # 3 seconds of `in` animation -----------------------
  55.     in_frames = n_frames
  56.     # ease numbers animation
  57.     m = CubicEaseInOut(0, mins, in_frames)
  58.     h = CubicEaseInOut(0, hours, in_frames)
  59.     total_m = CubicEaseInOut(0, hours % 12 * 60 + mins, in_frames)
  60.     for f in range(in_frames):
  61.         img = background.copy()
  62.         draw = ImageDraw.Draw(img)
  63.         # draw numbers
  64.         text = f"{round(h.ease(f)):02}:{round(m.ease(f)):02}"
  65.         draw.text((x, y), text, fill=red, font=font)
  66.         # draw curves
  67.         # === hour curve
  68.         h_offset = maprange([0, 1440/2], [0, 360], total_m.ease(f))
  69.         h_curve_box = (0, 0, dims[0], dims[1])
  70.         draw.arc(h_curve_box, start=-90, end=-90 +
  71.                     h_offset, fill=red, width=width)
  72.         # === === dot stuff
  73.         r = (h_curve_box[3] - h_curve_box[0]) / 2
  74.         left_corner, right_corner = calc_ellipse_coords(r, h_offset, width)
  75.         draw.ellipse((*left_corner, *right_corner),
  76.                         fill=red, outline=None, width=0)
  77.         draw.ellipse((dims[0]/2 - width / 2 + 1, 0, dims[0]/2 + width / 2 - 1, width - 1),
  78.                         fill=red, outline=None, width=0)
  79.  
  80.         # === minute curve
  81.         m_offset = maprange([0, 60], [0, 360], m.ease(f))
  82.         m_curve_box = (width + spacing, width + spacing,
  83.                         dims[0] - width - spacing, dims[1] - width - spacing)
  84.         draw.arc(m_curve_box, start=-90, end=-90 +
  85.                     m_offset, fill=red, width=int(width/2))
  86.  
  87.         if antialiasing:
  88.             img = img.resize(
  89.                 (dims[0] // multiplier, dims[1] // multiplier),
  90.                 antialiasing
  91.             )
  92.         img.save(f'img/{starting_from + f}.jpg')
  93.  
  94.  
  95. def draw_still_frames(background, starting_from, n_frames):
  96.     # 2 seconds of still image --------------------------
  97.     still_frames = n_frames
  98.     img = background.copy()
  99.     draw = ImageDraw.Draw(img)
  100.     # draw numbers
  101.     draw.text((x, y), f"{hours:02}:{mins:02}", fill=red, font=font)
  102.     # draw curves
  103.     # === hour curve
  104.     h_offset = maprange([0, 1440/2], [0, 360], hours % 12*60+mins)
  105.     h_curve_box = (0, 0, dims[0], dims[1])
  106.     draw.arc(h_curve_box, start=-90, end=-90 +
  107.                 h_offset, fill=red, width=width)
  108.     # === === dot stuff
  109.     r = (h_curve_box[3] - h_curve_box[0])/2
  110.     left_corner, right_corner = calc_ellipse_coords(r, h_offset, width)
  111.     draw.ellipse((*left_corner, *right_corner),
  112.                     fill=red, outline=None, width=0)
  113.     draw.ellipse((dims[0]/2 - width / 2 + 1, 0, dims[0]/2 + width / 2 - 1, width - 1),
  114.                     fill=red, outline=None, width=0)
  115.     # === minute curve
  116.     m_offset = maprange([0, 60], [0, 360], mins)
  117.     m_curve_box = (width + spacing, width + spacing,
  118.                     dims[0] - width - spacing, dims[1] - width - spacing)
  119.     draw.arc(m_curve_box, start=-90, end=-90 +
  120.                 m_offset, fill=red, width=int(width/2))
  121.  
  122.     # save n_frames copies (this part of animation is a stop frame, not actually an animation)
  123.     for i in range(still_frames):
  124.         if antialiasing:
  125.             img = img.resize(
  126.                 (dims[0] // multiplier, dims[1] // multiplier),
  127.                 antialiasing
  128.             )
  129.         img.save(f'img/{starting_from + i}.jpg')
  130.  
  131.  
  132. def draw_out_anim_frames(background, starting_from, n_frames):
  133.     # 1 second of `out` animation -----------------------
  134.     out_frames = n_frames
  135.     m = CubicEaseInOut(mins, 60, out_frames)
  136.     h = CubicEaseInOut(hours, 24, out_frames)
  137.     total_m = CubicEaseInOut(hours % 12 * 60 + mins, 12*60, out_frames)
  138.     for f in range(out_frames):
  139.         img = background.copy()
  140.         draw = ImageDraw.Draw(img)
  141.         # draw numbers
  142.         a = round(h.ease(f))
  143.         b = round(m.ease(f))
  144.         text = f"{a if a!=24 else 00:02}:{b if b!=60 else 00:02}"
  145.         draw.text((x, y), text, fill=red, font=font)
  146.         # draw curves
  147.         # hour curve
  148.         h_offset = maprange([0, 1440/2], [0, 360], total_m.ease(f))
  149.         h_curve_box = (0, 0, dims[0], dims[1])
  150.         draw.arc(h_curve_box, start=-90, end=-90 +
  151.                     h_offset, fill=red, width=width)
  152.         # dot stuff
  153.         r = (h_curve_box[3] - h_curve_box[0])/2
  154.         left_corner, right_corner = calc_ellipse_coords(r, h_offset, width)
  155.         draw.ellipse((*left_corner, *right_corner),
  156.                         fill=red, outline=None, width=0)
  157.         draw.ellipse((dims[0]/2 - width / 2 + 1, 0, dims[0]/2 + width / 2 - 1, width - 1),
  158.                         fill=red, outline=None, width=0)
  159.         # minute curve
  160.         m_offset = maprange([0, 60], [0, 360], m.ease(f))
  161.         m_curve_box = (width + spacing, width + spacing,
  162.                         dims[0] - width - spacing, dims[1] - width - spacing)
  163.         draw.arc(m_curve_box, start=-90, end=-90 +
  164.                     m_offset, fill=red, width=int(width / 2))
  165.  
  166.         if antialiasing:
  167.             img = img.resize(
  168.                 (dims[0] // multiplier, dims[1] // multiplier),
  169.                 antialiasing
  170.             )
  171.         img.save(f'img/{starting_from + f}.jpg')
  172.  
  173.  
  174. def draw_fade_out_frames(background, starting_from, n_frames):
  175.     # 0.5 second of fade out animation -----------------------
  176.     fade_out_frames = n_frames
  177.     for f in range(fade_out_frames):
  178.         img = background.copy()
  179.         draw = ImageDraw.Draw(img, mode='RGBA')
  180.         # draw numbers
  181.         draw.text((x, y), f"{00:02}:{00:02}", fill=red, font=font)
  182.         # draw curves
  183.         # hour curve
  184.         color = (255, 0, 0, round(
  185.             maprange([0, fade_out_frames], [255, 0], f)))
  186.         draw.ellipse((0, 0, dims[0], dims[1]),
  187.                         fill=None, outline=color, width=width)
  188.         # minute curve
  189.         draw.ellipse((width+spacing, width+spacing, dims[0] - (width+spacing), dims[1] - (width+spacing)),
  190.                         fill=None, outline=color, width=width//2)
  191.  
  192.         if antialiasing:
  193.             img = img.resize(
  194.                 (dims[0] // multiplier, dims[1] // multiplier),
  195.                 antialiasing
  196.             )
  197.         img.save(f'img/{starting_from + f}.jpg')
  198.  
  199.  
  200. def make_overlay(dt_obj, antialiasing=True):
  201.     # img settings
  202.     # if antialiasing option is True, scale image by multiplier size with ANTIALIAS flag,
  203.     # draw stuff, then scale image down by multiplier with the same ANTIALIAS flag
  204.     if antialiasing:
  205.         multiplier = 2
  206.     else:
  207.         multiplier = 1
  208.  
  209.     # background image dimentions shoud be equal e.g. square image
  210.     dims = (800 * multiplier, 800 * multiplier)
  211.  
  212.     red = (255, 0, 0, 255)
  213.  
  214.     hours = dt_obj.hour
  215.     mins = dt_obj.minute
  216.     # duration settings
  217.     # duration = 7 seconds
  218.     d0, d1, d2, d3, d4 = 0.5, 2, 2, 2, 0.5
  219.     fps = 30
  220.     fade_in_frames = round(fps * d0)
  221.     in_frames = fps * d1
  222.     still_frames = fps * d2
  223.     out_frames = fps * d3
  224.     fade_out_frames = round(fps * d4)
  225.  
  226.     # text settings
  227.     font = ImageFont.truetype('dig_mono.ttf', size=170 * multiplier)
  228.     x, y = 210 * multiplier, 240 * multiplier
  229.  
  230.     # curve settings
  231.     width = 16 * multiplier
  232.     spacing = 6 * multiplier
  233.  
  234.     with (Image.open('t1000.jpg')).resize(dims, antialiasing) as background:
  235.         draw_fade_in_frames(background, 0, fade_in_frames)
  236.         draw_in_anim_frames(background, fade_in_frames, in_frames)
  237.  
  238.         frame_offset = fade_in_frames
  239.         draw_still_frames(background, frame_offset + in_frames, still_frames)
  240.  
  241.         frame_offset = fade_in_frames + in_frames
  242.         draw_out_anim_frames(background, frame_offset +
  243.                              still_frames, out_frames)
  244.  
  245.         frame_offset = fade_in_frames + in_frames + still_frames
  246.         draw_fade_out_frames(background, frame_offset +
  247.                              out_frames, fade_out_frames)
  248.  
  249.  
  250. def create_video(dt):
  251.     # Duration: 0.5s + 2s + 2s + 2s + 0.5
  252.     filename = f"vid/{dt.hour:02}_{dt.minute:02}.mp4"
  253.     if os.path.isfile(filename):
  254.         return filename
  255.  
  256.     make_overlay(dt, True)
  257.  
  258.     ffmpeg = "/home/pi/FFmpeg/ffmpeg"
  259.     cmd = [ffmpeg, '-framerate', '30', '-i', 'img/%d.jpg', '-c:v',
  260.            'libx264', '-pix_fmt', 'yuv420p', '-threads', '4', '-b:v', '5120k', f'{filename}']
  261.     subprocess.call(cmd)
  262.  
  263.     os.system('rm img/*')
  264.     return filename
  265.  
  266.  
  267. def render_all_videos():
  268.     for h in range(24):
  269.         for m in range(60):
  270.             dt = datetime(2020, 1, 1, h, m, 1)
  271.             create_video(dt)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement