Wrote the pillow code utilizing trebuchets to emulate an image.
This commit is contained in:
parent
bde120e28e
commit
fe8c2a2ef6
3 changed files with 81 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
*__pycache__*
|
||||||
|
*.egg-info*
|
|
@ -4,4 +4,53 @@ image and replicate it with flexible trebuchets.
|
||||||
|
|
||||||
Concept was inspired by OptArt by Robert Bosch.
|
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
|
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
30
treimage/__main__.py
Normal 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()
|
Loading…
Reference in a new issue