/pyxelate-video

Python class that generates pixel art from images

Primary LanguageJupyter NotebookMIT LicenseMIT

Super Pyxelate converts images to 8-bit pixel art. It is an improved, faster implementation of the original Pyxelate algorithm with palette transfer support and enhanced dithering. Or you can find the original version of pyxelate here.

This is an implemented version where you can convert videos and images into "pixel art". Follow this YouTube tutorial or if you have any questions feel free to join my discord and ask there.

Pixel art corgi

Setup

This repo's codes are made for Windows. No guarantee that it'll run on Linux or MacOS.

Start

Clone this repository and place it anywhere you want on your PC. We'll need the file path later.

Setup environment

We are going to use Anaconda3, download Anaconda3 if you don't have it.

Step 1. Create conda environment:

conda create -n pyxelate python=3.7
conda activate pyxelate

Step 2. Install the dependencies

cd WHERE_YOU_CLONED_THIS_REPO
pip install -r requirements.txt
conda install -c conda-forge ffmpeg
  • To reuse the created conda environment after you close the prompt, you just need to:
conda activate pyxelate

Usage

I've implemented so you can run it easily on both images or videos locally. If you want to utilize pyx() more, feel free to just edit the codes away.

Image

To run through pyxelate on a single image:

python image.py --input INPUT_IMAGE_PATH --palette INTEGERS --downsample_by INTEGERS
  • --input: The input image file path
  • --palette: find this many colors. Default is 7, so it'll find 7 colors.
  • --downsample_by: new image will be this many times smaller of the original in size. Default is 14, so it'll be 1/14th smaller. To use the default values, you don't have to specify the arguments in the command.

eg.

python image.py --input input/china6.jpg

Result would be in the output folder.

Video

To run through pyxelate on a single video:

python video.py --input INPUT_VIDEO_PATH --palette INTEGERS --downsample_by INTEGERS

See above for arguments explanations.

Video will use the very first frame's palette for the rest of the video. This is to prevent new palette being created, because it'll look horrible with flickering.

eg.

python video.py --input input/csgo.mp4 --palette 20 --downsample_by 6

Result would be in the output folder.

To view the video in a "pixel art" style, I suggest using this video player called MPC-HC.

To perform the "Integer Scaling" effect, you have to go settings “View” → “Options” → “Playback” → “Output” → “Resizer” → “Nearest neighbor”. The setting is available when using rendering engines “Video Mixing Renderer 9 (renderless)”, “Enhanced Video Renderer (custom presenter)” and “Sync Renderer”. A rendering engine can be selected via the “DirectShow Video” dropdown on the same settings’ page. credit

My implementation ends here.

FAQ

The source code is available under the MIT license but I would appreciate the credit if your work uses Pyxelate (for instance you may add me in the Special Thanks section in the credits of your videogame)!

How does it work?

Pyxelate downsamples images by (iteratively) dividing it to 3x3 tiles and calculating the orientation of edges inside them. Each tile is downsampled to a single pixel value based on the angle the magnitude of these gradients, resulting in the approximation of a pixel art. This method was inspired by the Histogram of Oriented Gradients computer vision technique.

Then an unsupervised machine learning method, a Bayesian Gaussian Mixture model is fitted (instead of conventional K-means) to find a reduced palette. The tied gaussians give a better estimate (than Euclidean distance) and allow smaller centroids to appear and then lose importance to larger ones further away. The probability mass function returned by the uncalibrated model is then used as a basis for different dithering techniques.

Preprocessing and color space conversion tricks are also applied for better results.

PROTIPs

  • There is no one setting fits all, try experimenting with different parameters for better results! A setting that generates visually pleasing result on one image might not work well for another.
  • The bigger the resulting image, the longer the process will take. Note that most parts of the algorithm are O(H*W) so an image that is twice the size will take 4 times longer to compute.
  • Assigning existing palettes will take longer for larger palettes, because LAB color distance has to be calculated between each color separately.
  • Dithering takes time (especially atkinson) as they are mostly implemented in plain python with loops. You look like a good pixel

TODOs

  • Add CLI tool for Pyxelate so images can be batch converted from command line.
  • Re-implement Pyxelate for animations / sequence of frames in video.
  • Include PIPENV python environment files instead of just setup.py.
  • Implement Yliluoma's ordered dithering algorithm and experiment with improving visuals through gamma correction.
  • Write a whitepaper on the Pyxelate algorithm.