Skip to content

Instantly share code, notes, and snippets.

@kevinlinxc
Last active October 14, 2023 23:21
Show Gist options
  • Save kevinlinxc/4bcd1cafd28049bcd4dd0404fcafb440 to your computer and use it in GitHub Desktop.
Save kevinlinxc/4bcd1cafd28049bcd4dd0404fcafb440 to your computer and use it in GitHub Desktop.
Python functions used for Swain healing video: https://streamable.com/7041mg
"""
Code used to make Swain video wit healing annotation. Nothing special, just manual frame annotation (30 mins).
CV would have been over-engineering IMO.
pip install streamlit
pip install numpy
pip install opencv-python==4.5.5.62
Read the bottom of the code for run instructions.
"""
import cv2
import streamlit as st
from streamlit import session_state as state
import os
import glob
import numpy as np
def write_video_as_pngs(video_file, output_dir):
"""Step 1, split video into frames"""
if not os.path.isdir(output_dir):
os.mkdir(output_dir)
cap = cv2.VideoCapture(video_file)
frame_count = 0
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
output_path = os.path.join(output_dir, f"{frame_count}.png")
if not os.path.exists(output_path):
cv2.imwrite(output_path, frame)
frame_count += 1
if frame_count % 100 == 0:
print(f"Processed {frame_count}/{total_frames} frames")
print("Done")
def save_annotation(file_name):
"""
Helper used in step 2.
Callback function called when the Streamlit frame annotation form is submitted.
"""
text_input = state.text_input
print(file_name, text_input)
if text_input is not None and text_input != "":
with open("healing.txt", 'a') as f:
f.write(f"{os.path.basename(file_name)}:{text_input}\n")
state.index += 1
def streamlit_annotation():
"""
Step 2. Creates a Streamlit app that allows you to annotate frames. Just type the healing amount on the first
frame that you see it and hit the Submit button. The healing amount will be written to healing.txt and the
next frame will be shown. Repeat until the end of the video.
"""
if "index" not in state:
state['index'] = 0 # can change to another starting frame if you were interrupted while running the script
dir = os.path.join(os.getcwd(), "output")
files = sorted(glob.glob(f'{dir}/*.png'), key=len)
form = st.form("hi")
file_name = files[state.index]
img = cv2.imread(file_name)
form.image(img, channels="BGR")
form.text_input(f"Healing for frame {state.index}", key="text_input")
form.form_submit_button("Submit", on_click=save_annotation, args=[file_name])
def generate_video_with_text(original, healingtxt, output_name):
"""Step 3. Uses healing.txt to write healing text to a video. This video was overlaid onto the original in After Effects. """
with open(healingtxt, 'r') as f:
lines = f.readlines()
lines = [line.strip() for line in lines]
lines = [line.split(':') for line in lines]
lines = {line[0]: line[1] for line in lines}
cap = cv2.VideoCapture(original)
fps = cap.get(cv2.CAP_PROP_FPS)
frame_count = 0
# total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter(output_name, fourcc, fps, (1920, 1080))
files = sorted(glob.glob(f'output/*.png'), key=len)
total_healing = 0
for file in files:
frame_count += 1
if frame_count % 100 == 0:
print(f"Processed {frame_count} frames")
white_frame = np.zeros((1080, 1920, 3), np.uint8)
white_frame[:] = (255, 255, 255)
# write total healing onto the frame
cv2.putText(white_frame, f"Total Healing: {total_healing}", (50, 100), cv2.FONT_HERSHEY_SIMPLEX, 3, (0, 0, 0), 5)
out.write(white_frame)
if os.path.basename(file) in lines:
total_healing += int(lines[os.path.basename(file)])
if __name__ == '__main__':
# uncomment one step at a time to run
# for step 2, you need to run `streamlit run main.py` instead of the normal `python main.py`
# step 1: break video into pngs. Put your own video path ig if you're using this script. My video
# had the green health bar from the bottom left of the replay motion tracked onto the usual health bar
# using After effects. This took two separate recordings of the LoL replay.
write_video_as_pngs("swain_with_bar.mov", "output")
# step 2: show all the frames and annotate them in streamlit
# st.set_page_config(layout="wide")
# streamlit_annotation()
# step 3: generate opencv video with text from healing.txt
# generate_video_with_text("swain_with_bar.mov", "healing.txt", "output.mp4")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment