Skip to content

Latest commit

 

History

20 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Asciify

Convert images and videos into ASCII art. Each pixel is mapped to a character representing its brightness, rendered in full color or monochrome — with optional edge-detection overlays for a sketch-like look.

Before Asciify After Asciify
Pre-Asciify Post-Asciify

Features

  • Image conversion — Convert any image to an ASCII art render
  • Video conversion — Convert videos frame-by-frame with audio preserved
  • Full color or monochrome — Characters are drawn in the original pixel colors, or grayscale
  • Contour/edge overlay — Replaces brightness characters with directional edge characters (| / - \) using Laplacian + Canny edge detection and Sobel gradients
  • Multiprocessing — Frame conversion parallelized across all CPU cores
  • Chunked processing — Streams video in chunks to keep memory usage bounded
  • Low-res audio mode — Optionally downsamples audio to reduce output file size

Note

The script currently does not support outputting pure text, only rendered photos and images, although this a trivial modification that will be done in future.

Installation

Asciify uses a few dependencies. All of these can be installed via pip from the requirements.txt file.

pip install -r requirements.txt

Any other dependencies should come standard with Python 3.6+, and the luton.ttf font can be found in this repository.

Convert an Image

from ascii_converter import ascii_photo, AsciiConfig

ascii_photo("input.jpg", "output.png")

# With custom settings
cfg = AsciiConfig(scale_factor=0.2, monochrome=True)
ascii_photo("input.jpg", "output.png", cfg=cfg, progress_bar=True)

To asciify a video, use ascii_video() like so:

Convert a Video

from ascii_converter import ascii_video, AsciiConfig

ascii_video("input.mp4", "output.mp4")

# With contour overlay and full-res audio
cfg = AsciiConfig(overlay_contours=True, low_res_audio=False)
ascii_video("input.mp4", "output.mp4", cfg=cfg, progress_bar=True, chunk_size=128) # Chunk size is how many frames are processed in parallel in memory

Warning

Do not that if ascii_video() is used at all (in any script), the script that is initially run must contain the following lines.

from multiprocessing import freeze_support

if __name__ == "__main__":
 freeze_support()
 # Continue the code execution here ( i.e. call main() ).

This is for Windows, Linux, and likely MacOS machines, and is used to prevent subprocesses freezing from new creations.

Configuration

Most options are set via AsciiConfig:

Parameter Type Default Description
scale_factor float 0.15 Controls output resolution — fraction of the source width converted to ASCII columns
char_width int 7 Pixel width of each character cell (tune to match your font)
char_height int 9 Pixel height of each character cell
color_brightness float 1.0 Multiplier applied to RGB channels when coloring characters
pixel_brightness float 2.15 Multiplier applied to luminance before character selection — increase to use denser characters
monochrome bool False Render characters in grayscale instead of original colors
overlay_contours bool False Replace edge pixels with directional characters for a sketch/outline effect
contour_min_threshold int 0 Minimum threshold for Laplacian edge mask
contour_max_threshold int 255 Maximum threshold for Laplacian edge mask
low_res_audio bool True Downsample audio to 8kHz then upsample to 16kHz to reduce file size
num_workers int cpu_count() Number of parallel worker processes for frame conversion

To configure the characters used during the ASCII conversion (although not recommended), change the following 3 constants in asciify.py:

  • CHARS: Characters used in mapping pixel luminance, one string, darkest first
  • CONTOUR_CHARS: Characters used in mapping contours, one string, starting at 0 degrees rotating clockwise
  • FONT: Font used for the displayed characters, FreeTypeFont object from Pillow library

How It Works

Character mapping — A 256-entry lookup table maps each pixel's luminance value to one of 70 characters, ranging from dense ($@B%8&WM#*...) to empty (space). Brighter pixels get sparser characters.

Color — In color mode, each character is drawn using the original RGB value of the pixel it represents. In monochrome mode, the luminance value is used for all three channels.

Contour overlay — When enabled, edge detection runs on the grayscale frame. Pixels identified as edges are assigned one of four directional characters (|, /, -, \) based on the gradient angle from Sobel, giving outlines a hand-drawn appearance.

Video pipeline — Frames are read in chunks, converted in parallel using a multiprocessing.Pool, and written sequentially via FFMPEG_VideoWriter. Audio is extracted, optionally resampled, and muxed into the output.

Tips

  • Lower scale_factor for faster processing and a blockier look; higher for more detail and larger output files.
  • Increase pixel_brightness if your output looks mostly empty/white characters; decrease it if everything looks like @ or $.
  • overlay_contours works best on footage with clear edges — faces, objects, and architectural subjects tend to look great.
  • For fine-tuning contour detection, adjust contour_min_threshold and contour_max_threshold to control how aggressively Laplacian edges are included.
  • Set low_res_audio=False if audio quality matters; the default trades fidelity for smaller file sizes.
  • Set chunk_size in ascii_video to a value that balances concurrency and memory usage.

License

This project uses the MIT License.

About

A Python Script to "asciify" photos and videos.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages