Skip to content

Instantly share code, notes, and snippets.

@XCanG
Last active May 9, 2025 09:18
Show Gist options
  • Select an option

  • Save XCanG/b21f2c80d64f0df012ebe143c9c46224 to your computer and use it in GitHub Desktop.

Select an option

Save XCanG/b21f2c80d64f0df012ebe143c9c46224 to your computer and use it in GitHub Desktop.
Pixelate image. Use `pixelate.py --help` to get help message. Install required libraries `pip install opencv-python numpy typer`. General usage with default params: `pixelate.py img.png`
from typing import Annotated
from pathlib import Path
import cv2
import numpy as np
import typer
app = typer.Typer(no_args_is_help=True)
@app.command()
def main(
image: Annotated[Path, typer.Argument(help="Path to image")],
quantization_level: Annotated[int, typer.Option("--quantization-level", "-q", help="Number of levels of quantization, 0 - disabled", rich_help_panel="Params")] = 16,
pixel_size: Annotated[int, typer.Option("--pixel-size", "-p", help="Pixel size, 1 or 0 - disabled", rich_help_panel="Params")] = 10,
gamma: Annotated[float, typer.Option("--gamma", "-g", help="Adjust gamma, 1.0 - disabled, 0 - auto", rich_help_panel="Params")] = 0.0,
preview: Annotated[bool, typer.Option(help="Show preview of pixelated image", rich_help_panel="Debug")] = True,
output_dir: Annotated[Path | None, typer.Option("--output-dir", "-d", help="Specify output directory, default - input image directory", rich_help_panel="File")] = None,
output_name: Annotated[
str | None,
typer.Option("--output-name", "-n", help="Specify output file name, default - input image name + passed parameters", rich_help_panel="File"),
] = None,
) -> cv2.typing.MatLike:
"""
# Convert image to pixelated image
By default posterize image to 16 levels of quantization (improve sharpness before pixelation),
pixelate to 10x10 pixel size and adjust gamma based of size of pixel (as it become dimmed)
"""
im: cv2.typing.MatLike = cv2.imread(str(image))
im2: cv2.typing.MatLike
im3: cv2.typing.MatLike
im4: cv2.typing.MatLike
imf: cv2.typing.MatLike
if 255 > quantization_level > 0:
indices = np.arange(0, 256) # List of all colors
divider = np.linspace(0, 255, quantization_level + 1)[1] # we get a divider
quantiz = np.intp(np.linspace(0, 255, quantization_level)) # we get quantization colors
color_levels = np.clip(np.intp(indices / divider), 0, quantization_level - 1) # color levels 0, 1, 2...
palette = quantiz[color_levels] # type: ignore[palette] # Creating the palette
im2 = palette[im] # Applying palette on image
im2 = cv2.convertScaleAbs(im2) # Converting image back to uint8
else:
im2 = im
if pixel_size >= 2:
h, w, _ = im2.shape
sw, sh = max(round(w / pixel_size), 1), max(round(h / pixel_size), 1)
im3 = cv2.resize(im2, (sw, sh), interpolation=cv2.INTER_AREA) # Downscale
im4 = cv2.resize(im3, (sw * pixel_size, sh * pixel_size), interpolation=cv2.INTER_NEAREST) # Upscale
else:
im4 = im2
if gamma != 1.0: # Adjust gamma
# build a lookup table mapping the pixel values [0, 255] to their adjusted gamma values
if gamma <= 0.0:
gamma = 0.4 / pixel_size + 0.6 # Approximate influence on gamma by pixel_size
inv_gamma = 1.0 / gamma
table = np.array([((i / 255.0) ** inv_gamma) * 255 for i in np.arange(0, 256)]).astype("uint8")
imf = cv2.LUT(im4, table) # apply gamma correction using the lookup table
else:
imf = im4
if preview:
# cv2.namedWindow("preview", cv2.WINDOW_NORMAL) # | cv2.WINDOW_KEEPRATIO
cv2.imshow("preview", imf)
cv2.waitKey(5_000)
cv2.destroyAllWindows()
file_name = output_name or f"{image.stem}.q{quantization_level}.px{pixel_size}.g{gamma:.2f}{image.suffix}"
new_file = output_dir / file_name if output_dir else image.with_name(file_name)
print(f"Saving pixelated file to: {new_file}")
if new_file.suffix in (".jpg", ".jpeg"):
cv2.imwrite(str(new_file), imf, [int(cv2.IMWRITE_JPEG_QUALITY), 90]) # Set JPEG quality to 90%
else:
cv2.imwrite(str(new_file), imf)
return imf
if __name__ == "__main__":
app()
@XCanG
Copy link
Author

XCanG commented May 9, 2025

Pixelate image

Use pixelate.py --help to get help message.

Install required libraries:

pip install opencv-python numpy typer

General usage with default params:

pixelate.py img.png

Advanced usage:

pixelate.py --quantization-level 16 --pixel-size 10 --gamma 0.5 --no-preview --output-dir "some/path" --output-name new.png img.png
pixelate.py -q 16 -p 10 -g 0.5 --no-preview -d "some/path" -n new.png img.png

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment