SoFunction
Updated on 2024-11-13

Python3 video to character animation example code

Python3 video to character animation, the specific code is shown below:

# -*- coding:utf-8 -*-
import json
import os
import subprocess
from pathlib import Path
from cv2 import cv2
import numpy as np
from time import time
import webbrowser
play_chars_js = '''
let i = 0;
(function(){
  let img = frames[i++];
  let html = ""
  for(let line of img){
    for(let char of line){
      let [[r,g,b], ch] = char;
      html += '<span style="color:rgb(' + r + ', ' + g + ', '+ b + ');">'+ ch + '</span>'
      // html += '<span style="background-color:rgb(' + r + ', ' + g + ', '+ b + ');">'+ ch + '</span>'
    }
    html += "<br>"
  }
  ("video-panel")[0].innerHTML = html
}, 1000/fps);
("audio")[0].play();
'''
class VideoToHtml:
  # pixel shapes, because the color is already controlled by rgb, here pixels can actually be randomly arranged
  pixels = "$#@&%ZYXWVUTSRQPONMLKJIHGFEDCBA098765432?][}{/)(><zyxwvutsrqponmlkjihgfedcba*+1-."
  def __init__(self, video_path, fps_for_html=8, time_interval=None):
    """
    :param video_path: string, path to video file
    :param fps_for_html: frame rate of the generated html.
    :param time_interval: time_interval of the video (start time, end time) in seconds.
    """
    self.video_path = Path(video_path)
    # Create a VideoCapture object from the specified file.
     = (video_path)
     = (cv2.CAP_PROP_FRAME_WIDTH)
     = (cv2.CAP_PROP_FRAME_HEIGHT)
    self.frames_count_all = (cv2.CAP_PROP_FRAME_COUNT)
     = (cv2.CAP_PROP_FPS)
    self.resize_width = None
    self.resize_height = None
    self.frames_count = 0
    self.fps_for_html = fps_for_html
    self.time_interval = time_interval
  def video2mp3(self):
    """# Call ffmpeg to get mp3 audio file """"
    mp3_path = self.video_path.with_suffix('.mp3')
    ('ffmpeg -i ' + str(self.video_path) + ' -f mp3 ' + str(mp3_path), shell=True)
    return mp3_path
  def set_width(self, width):
    """It can only be reduced and always maintain the aspect ratio"""
    if width >= :
      return False
    else:
      self.resize_width = width
      self.resize_height = int( * (width / ))
      return True
  def set_height(self, height):
    """It can only be reduced and always maintain the aspect ratio"""
    if height >= :
      return False
    else:
      self.resize_height = height
      self.resize_width = int( * (height / ))
      return True
  def resize(self, img):
    """
    Convert img to desired size
    Principle: only reduce, not enlarge.
    """
    # If you don't specify it, you don't need to resize it.
    if not self.resize_width or not self.resize_height:
      return img
    else:
      size = (self.resize_width, self.resize_height)
      return (img, size, interpolation=cv2.INTER_CUBIC)
  def get_img_by_pos(self, pos):
    """Get the frame at the specified position."""
    # Move the pointer to the position of the specified frame
    (cv2.CAP_PROP_POS_FRAMES, pos)
    # () Introduction to return values:
    # ret Boolean indicating whether the image is read or not
    # frame is an image matrix of type .
    ret, frame = ()
    return ret, frame
  def get_frame_pos(self):
    """Generate the position of the frame to be acquired, using inert summation."""
    step =  / self.fps_for_html
    # If not specified
    if not self.time_interval:
      self.frames_count = int(self.frames_count_all / step) # Update count
      return (int(step * i) for i in range(self.frames_count))
    # If specified
    start, end = self.time_interval
    pos_start = int( * start)
    pos_end = int( * end)
    self.frames_count = int((pos_end - pos_start) / step) # Update count
    return (pos_start + int(step * i) for i in range(self.frames_count))
  def get_imgs(self):
    assert ()
    for i in self.get_frame_pos():
      ret, frame = self.get_img_by_pos(i)
      if not ret:
        print("Read failed. Jumped out of loop.")
        break
      yield (frame) # Inert summation
    # Space to be released at the end
    ()
  def get_char(self, gray):
    percent = gray / 255 # Converts to between 0-1
    index = int(percent * (len() - 1)) # Get the index
    return [index]
  def get_json_pic(self, img):
    """Test phase, not practical."""
    json_pic = []
    # The width and height are just the opposite of size, mind you. (This is a numpy feature.)
    height, width, channel = 
    # Converted to grayscale and used to select appropriate characters
    img_gray = (img, cv2.COLOR_BGR2GRAY)
    for y in range(height):
      line = []
      for x in range(width):
        r, g, b = img[y][x]
        gray = img_gray[y][x]
        char = self.get_char(gray)
        ([[int(r), int(g), int(b)], char])
      json_pic.append(line)
    return (json_pic)
  def write_html_with_json(self, file_name):
    """Test phase, not practical."""
    mp3_path = self.video2mp3()
    time_start = time()
    with open(file_name, 'w') as html:
      # Remember to set the monospace font width or you won't be able to play #
      ('<!DOCTYPE html>'
            '<html>'
            '<body style="font-family: monospace; font-size: small; font-weight: bold; text-align: center; line-height: 0.8;">'
            '<div class="video-panel"></div>'
            f'<audio src="{mp3_path.name}" autoplay controls></audio>'
            '</body>'
            '<script>'
            'var frames=[\n')
      try:
        i = 0
        for img in self.get_imgs():
          json_pic = self.get_json_pic(img)
          (f"{json_pic},")
          if i % 20:
            print(f"degree of progress (on project):{i/self.frames_count * 100:.2f}%, elapsed time:{time() - time_start:.2f}")
          i += 1
      finally:
        ('\n];\n'
              f'let fps={self.fps_for_html};\n'
              f'{play_chars_js}'
              '</script>\n'
              '</html>')
def main():
  # Video path, change it to your own
  video_path = "ceshi.mp4"
  video2html = VideoToHtml(video_path, fps_for_html=8)
  video2html.set_width(120)
  html_name = Path(video_path).with_suffix(".html").name
  video2html.write_html_with_json(html_name)
if __name__ == "__main__":
  main()

summarize

The above is a small introduction to the Python3 video to character animation example code, I hope to help you, if you have any questions please leave me a message, I will reply to you in a timely manner. I would also like to thank you very much for your support of my website!
If you find this article helpful, please feel free to reprint it, and please note the source, thank you!