Last active
January 3, 2024 03:26
-
-
Save MotionDesignStudio/9374326 to your computer and use it in GitHub Desktop.
Python ASCII Video And ASCII Image Creator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Example: | |
Video | |
http://www.youtube.com/watch?v=yi5H_bnZzGc | |
[ Usage: To convert a video file to ASCII video with no audio. ] | |
./ascii_movie_image_ver_1.py myvideo.mkv 4 15 | |
“myvideo.mkv” is the name of your video file. Supported video files are limited based on your system. | |
“4” is the density of ASCII characters. | |
“15” is the font size. | |
Changing the density and font size changes the look and feel of the video. | |
[ Usage: To convert a image file to a ASCII image. ] | |
./ascii_movie_image_ver_1.py myimage.jpg 4 15 | |
“myimage.jpg” is the name of your image file. Supported image files are limited based on your system. | |
“4” is the density of ASCII characters. | |
“15” is the font size. | |
Changing the density and font size changes the look and feel of the image. | |
[ How To Modify ] | |
The following line: font = ImageFont.truetype("/usr/share/fonts/truetype/freefont/FreeMonoBold.ttf", fontsize, encoding="unic") | |
Is the path to the font being utilized. If you encounter errors with the font location point this to a location where your system stores a fixed width truetype font. | |
Modify any lines with “120,20,20” to change the background color of the image or video. | |
Modify any lines with “255,255,0” to change the font color. | |
The color is expressed as an RGB triplet (r,g,b), each component of which can vary from 0 to 255. If all the components are at zero the result is black; if all are at maximum, the result is the brightest representable white. | |
External link to FFMEG: | |
Modify this line to your external ffmpeg source. | |
subprocess.call(["./ffmpeg/ffmpeg", "-i", "%d.png", "-r", frame_rate, "-y", "-c:v", "libx264", "-preset", "slow", "-crf", "18", "-c:a", "copy", "-pix_fmt", "yuv420p", "output.mkv" ]) | |
[ Important ] | |
Non fixed width fonts might distort the image. | |
I use a static ffmpeg build because it runs faster and creates a smaller higher quality video. The ffmpeg commands I use is optimized for Youtube streaming. You can download the latest from. http://johnvansickle.com/ffmpeg/ | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import sys | |
import cv2 | |
import subprocess | |
from subprocess import call | |
import aalib | |
import Image | |
import PIL | |
from PIL import ImageFont | |
from PIL import Image | |
from PIL import ImageDraw | |
import imghdr | |
import ImageOps | |
import numpy as np | |
sys.dont_write_bytecode = True | |
videofilename=str(sys.argv[1]).strip() | |
#These two variables control the resolution and font size. They are interconnected. | |
#img_new_magnitude | |
#fontsize | |
try: | |
img_new_magnitude= int (str(sys.argv[2]).strip() ) | |
except : | |
img_new_magnitude=4 | |
try: | |
fontsize= int (str(sys.argv[3]).strip()) | |
except : | |
fontsize= 15 | |
font = ImageFont.truetype("/usr/share/fonts/truetype/freefont/FreeMonoBold.ttf", fontsize, encoding="unic") | |
def create_ascii_video_2(): | |
#Extract the image size: | |
image_width, image_height =calculate_image_size_from_video () | |
#Extract the number of rows and length of the string in pixels which is used for the image being | |
#created based on the width and height of the text. | |
how_many_rows, new_img_width = calculate_image_size_from_video_2 () | |
vc = cv2.VideoCapture(videofilename) | |
saved_file_name="" | |
frame_rate=str (vc.get(cv2.cv.CV_CAP_PROP_FPS)) | |
#Png file name counter | |
c=0 | |
if vc.isOpened(): | |
rval , frame = vc.read() | |
else: | |
rval = False | |
while rval: | |
rval, frame = vc.read() | |
#Check to see if file is a valid image. I notice the last frame of the video is an empty file at times: | |
try: | |
myimage= Image.fromarray(frame) | |
except (TypeError, AttributeError): | |
print ("cannot identify image while loop in function create_ascii_video_2", myimage) | |
continue | |
aalib_screen_width= int(image_width/25.28)*img_new_magnitude | |
aalib_screen_height= int(image_height/41.39)*img_new_magnitude | |
screen = aalib.AsciiScreen(width=aalib_screen_width, height=aalib_screen_height ) | |
myimage= Image.fromarray(frame).convert("L").resize(screen.virtual_size) | |
screen.put_image((0,0), myimage) | |
img=Image.new("RGBA", (new_img_width, how_many_rows*fontsize),(120,20,20)) | |
draw = ImageDraw.Draw(img) | |
y = 0 | |
for lines in screen.render().splitlines(): | |
draw.text( (0,y), lines, (255,255,0),font=font ) | |
y = y + fontsize | |
imagefit = ImageOps.fit(img, (image_width, image_height), Image.ANTIALIAS) | |
imagefit.save(str(c)+'.png', "PNG") | |
c = c + 1 | |
cv2.waitKey(1) | |
vc.release() | |
cv2.destroyAllWindows() | |
subprocess.call(["./ffmpeg/ffmpeg", "-i", "%d.png", "-r", frame_rate, "-y", "-c:v", "libx264", "-preset", "slow", "-crf", "18", "-c:a", "copy", "-pix_fmt", "yuv420p", "output.mkv" ]) | |
clean_up(c) | |
def create_ascii_image(): | |
myimage= Image.open(videofilename) | |
image_width, image_height = myimage.size | |
aalib_screen_width= int(image_width/24.9)*img_new_magnitude | |
aalib_screen_height= int(image_height/41.39)*img_new_magnitude | |
screen = aalib.AsciiScreen(width=aalib_screen_width, height=aalib_screen_height ) | |
myimage= Image.open(videofilename).convert("L").resize(screen.virtual_size) | |
screen.put_image((0,0), myimage) | |
y = 0 | |
how_many_rows = len ( screen.render().splitlines() ) | |
new_img_width, font_size = font.getsize (screen.render().splitlines()[0]) | |
img=Image.new("RGBA", (new_img_width, how_many_rows*fontsize),(120,20,20)) | |
draw = ImageDraw.Draw(img) | |
for lines in screen.render().splitlines(): | |
draw.text( (0,y), lines, (255,255,0),font=font ) | |
y = y + fontsize | |
imagefit = ImageOps.fit(img, (image_width, image_height), Image.ANTIALIAS) | |
imagefit.save("ascii_photo.png", "PNG") | |
def clean_up(howmuchtodelete): | |
i=0 | |
while i< howmuchtodelete : | |
subprocess.call(["rm", str(i)+".png" ]) | |
i=i+1 | |
def complete_alert_message(the_message): | |
font = ImageFont.truetype("/usr/share/fonts/truetype/freefont/FreeMonoBold.ttf",40) | |
img=Image.new("RGBA", (200,70),(120,20,20)) | |
draw = ImageDraw.Draw(img) | |
draw.text((5, 0),the_message,(255,255,0),font=font) | |
img.show() | |
def calculate_image_size_from_video (): | |
vc = cv2.VideoCapture(videofilename) | |
if vc.isOpened(): | |
rval , frame = vc.read() | |
#Extract the image size: | |
try: | |
myimage= Image.fromarray(frame) | |
return myimage.size | |
except IOError: | |
print ("cannot identify image file", myimage) | |
else: | |
print ("In fucntion calculate_image_size_from_video I could not find the video frame size." ) | |
def calculate_image_size_from_video_2 (): | |
#Extract the image size: | |
image_width, image_height =calculate_image_size_from_video () | |
vc = cv2.VideoCapture(videofilename) | |
if vc.isOpened(): | |
rval , frame = vc.read() | |
else: | |
rval = False | |
while rval: | |
rval, frame = vc.read() | |
#Check to see if file is a valid image. I notice the last frame of the video is an empty file at times: | |
try: | |
myimage= Image.fromarray(frame) | |
except (TypeError, AttributeError): | |
print ("cannot identify image", myimage) | |
continue | |
aalib_screen_width= int(image_width/25.28)*img_new_magnitude | |
aalib_screen_height= int(image_height/41.39)*img_new_magnitude | |
screen = aalib.AsciiScreen(width=aalib_screen_width, height=aalib_screen_height ) | |
myimage= Image.fromarray(frame).convert("L").resize(screen.virtual_size) | |
screen.put_image((0,0), myimage) | |
how_many_rows = len ( screen.render().splitlines() ) | |
new_img_width, font_size = font.getsize (screen.render().splitlines()[0]) | |
cv2.waitKey(1) | |
vc.release() | |
return (how_many_rows, new_img_width ) | |
def test_if_image_or_video (): | |
if imghdr.what(videofilename) != None : | |
print ("This is a image file.") | |
create_ascii_image() | |
else: | |
print ("This is probably not a image.") | |
create_ascii_video_2() | |
test_if_image_or_video () |
Similar implementation in Rust: https://github.com/Kagami/video-tools/tree/master/y2aa
How I get the char sequence out without making it a png?
how to run on recent ubuntu:
sudo apt install python3-opencv python3-autopep8 python3-aalib
autopep8 -i ascii_movie_image_ver_1.py
commented
import Image
changed
import ImageOps
to
from PIL import ImageOps
run with
python3 ascii_movie_image_ver_1.py imagefile.jpg
also had to modify line 52 to
frame_rate=str (vc.get(cv2.cv2.CAP_PROP_FPS))
Thanks for the update. I will modify for python 3. How have you used it?
…________________________________
From: Eliran Gonen <[email protected]>
Sent: Saturday, January 16, 2021 6:26:11 AM
To: MotionDesignStudio <[email protected]>
Cc: Motion Design Studio <[email protected]>; Author <[email protected]>
Subject: Re: MotionDesignStudio/ascii_movie_image_ver_1.py
@elig0n commented on this gist.
________________________________
also had to modify line 52 to
frame_rate=str (vc.get(cv2.cv2.CAP_PROP_FPS))
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub<https://gist.github.com/9374326#gistcomment-3596033>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/ABRPUWW5VLUF5BOY4ZBGJD3S2FZVHANCNFSM4OZ3C6NA>.
I ran it on some video files and it would only create output.mkv
That is the default output filename. This is why.
…________________________________________
From: elig0n <[email protected]>
Sent: Sunday, January 17, 2021 9:26 PM
To: MotionDesignStudio
Cc: Motion Design Studio; Author
Subject: Re: MotionDesignStudio/ascii_movie_image_ver_1.py
@elig0n commented on this gist.
________________________________
I ran it on some video files and it would only create output.mkv
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub<https://gist.github.com/9374326#gistcomment-3597439>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/ABRPUWRPSDD532OFG7CBS73S2OL4FANCNFSM4OZ3C6NA>.
I also had to manually set path to ffmpeg and itwould then only create red&yellow tinted videos & images
I actually thought this would play the ascii-video in terminal by terminal drawing commands
This is is the documentation. And tell you how to modify.
[ How To Modify ]
The following line: font = ImageFont.truetype("/usr/share/fonts/truetype/freefont/FreeMonoBold.ttf", fontsize, encoding="unic")
Is the path to the font being utilized. If you encounter errors with the font location point this to a location where your system stores a fixed width truetype font.
Modify any lines with “120,20,20” to change the background color of the image or video.
Modify any lines with “255,255,0” to change the font color.
The color is expressed as an RGB triplet (r,g,b), each component of which can vary from 0 to 255. If all the components are at zero the result is black; if all are at maximum, the result is the brightest representable white.
Let me know if that works for you.
…________________________________________
From: elig0n <[email protected]>
Sent: Sunday, January 17, 2021 10:51 PM
To: MotionDesignStudio
Cc: Motion Design Studio; Author
Subject: Re: MotionDesignStudio/ascii_movie_image_ver_1.py
@elig0n commented on this gist.
________________________________
it would only create red&yellow tinted videos & images
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub<https://gist.github.com/9374326#gistcomment-3597495>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/ABRPUWQ4I6BQMYCWXQNVVBDS2OV3TANCNFSM4OZ3C6NA>.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I think you should explicitly state what the dependencies are. I didn't know I had to find/install python-aalib