Wrote the pillow code utilizing trebuchets to emulate an image.

This commit is contained in:
Brandon Rozek 2020-06-05 21:09:51 -04:00
parent bde120e28e
commit fe8c2a2ef6
3 changed files with 81 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
*__pycache__*
*.egg-info*

View file

@ -4,4 +4,53 @@ image and replicate it with flexible trebuchets.
Concept was inspired by OptArt by Robert Bosch.
"""
from typing import Optional, Tuple
from PIL import Image, ImageDraw
import numpy as np
from . import trebuchet
__all__ = ['trebuchet', 'create']
WHITE = (255, 255, 255)
def create(image_path: str, shape: trebuchet.FlexibleTrebuchet = trebuchet.D,
color: Optional[Tuple[int, int, int]] = (26, 95, 138), scale: int = 2):
"""
Creates an image out of trebuchet tiles as close to the original image as possible.
Inspired by the OptArt book by Robert Bosch.
Parameters
==========
image_path: str
The path of the image that we wish to emulate
color: Optional[Tuple[int, int, int]]
A RGB tuple containing the color of the Trebuchet tile.
If None, then we average the color of the surrounding area.
scale: int
The multiplicative scale of the width and height of a Trebuchet tile.
"""
if shape is None:
shape = trebuchet.D
if scale is None:
scale = 2
with Image.open(image_path) as im:
with Image.new('RGB', im.size, WHITE) as new_im:
grayscale_im = im.convert(mode='L')
draw = ImageDraw.Draw(new_im)
width, height = im.size
length = 4 * scale
for x in range(0, width, length):
for y in range(0, height, length):
gray_tile = grayscale_im.crop((x, y, x + length, y + length))
brightness = np.asarray(gray_tile).mean() / 255
p = shape(x, y, scale, brightness)
tile_color = color
if color is None:
tile = im.crop((x, y, x + length, y + length))
avg_color = tuple(np.asarray(tile).mean((0, 1)))
tile_color = tuple(int(c) for c in tuple(avg_color))
draw.polygon(p.points, fill=tile_color)
return new_im

30
treimage/__main__.py Normal file
View file

@ -0,0 +1,30 @@
from argparse import ArgumentParser
from . import create, trebuchet
parser = ArgumentParser(description="Create an image out of trebuchet tiles similar to image specified")
parser.add_argument("image_path", type=str, help="The image to emulate.")
parser.add_argument("--shape", type=str, help="The trebuchet shape (A, B, C, D)")
parser.add_argument("--color", type=str, help="The RGB value specified as \"r,g,b\"")
parser.add_argument("--scale", type=int, help="The multiplicative scale for the trebuchet height and width.")
args = vars(parser.parse_args())
image_path = args['image_path']
shape = args['shape']
if shape is not None:
shape = dict(
a=trebuchet.A,
b=trebuchet.B,
c=trebuchet.C,
d=trebuchet.D
)[args['shape'].lower()]
color = args['color']
if color is not None:
color = tuple(int(c) for c in args['color'].split(","))
assert len(color) == 3
scale = args['scale']
im = create(image_path, shape, color, scale)
im.show()