commit
70c8fc94e5
2 changed files with 145 additions and 0 deletions
@ -0,0 +1,141 @@
|
||||
#!/usr/bin/env python3 |
||||
|
||||
from argparse import ArgumentParser |
||||
from bresenham import bresenham |
||||
from PIL import Image, ImageDraw |
||||
from random import randint |
||||
import sys |
||||
|
||||
|
||||
rand = lambda: randint(0,255) |
||||
|
||||
|
||||
def print_stats(img): |
||||
pixels = img.getdata() |
||||
count = sum([1 for i in pixels if i == 0]) |
||||
print("{} black pixels over {} ({:.1%})".format(count, len(pixels), count/len(pixels))) |
||||
|
||||
|
||||
def get_lines(img): |
||||
lines = [] |
||||
pixels = [(x, y) for x in range(img.width) for y in range(img.height) if img.getpixel((x, y)) == 0] |
||||
|
||||
i, n = 0, len(pixels) * len(pixels) |
||||
|
||||
print("Get lines:", end = "") |
||||
for a in pixels: |
||||
for b in pixels: |
||||
line = list(bresenham(b[0], b[1], a[0], a[1])) |
||||
r = len([0 for p in line if p not in pixels]) |
||||
if not r: |
||||
lines.append(line) |
||||
i += 1 |
||||
print("\rGet lines: {:.0%}".format(i / n), end = "") |
||||
print("\rGet lines: complete") |
||||
|
||||
print("{} lines found".format(len(lines))) |
||||
return lines |
||||
|
||||
|
||||
def removing_doubles(lines): |
||||
results = [] |
||||
i, n = 0, len(lines) |
||||
|
||||
print("Remove duplicated lines:", end = "") |
||||
for l in lines: |
||||
s = sorted(l) |
||||
same = False |
||||
for o in results: |
||||
if sorted(o) == s: |
||||
same = True |
||||
break |
||||
if same == False: |
||||
results.append(l) |
||||
i += 1 |
||||
print("\rRemove double lines: {:.0%}".format(i / n), end = "") |
||||
print("\rRemove double lines: complete") |
||||
|
||||
print("{} lines kept".format(len(results))) |
||||
return results |
||||
|
||||
|
||||
def removing_useless(lines): |
||||
results = [] |
||||
i, n = 0, len(lines) |
||||
|
||||
print("Remove useless lines:", end = "") |
||||
for l in lines: |
||||
inclusions = 0 |
||||
others = (x for x in lines if x != l) |
||||
for k in others: |
||||
if len(list(set(l).intersection(set(k)))) == len(l): |
||||
inclusions += 1 |
||||
break |
||||
if inclusions == 0 or len(l) == 1: |
||||
results.append((len(l), l)) |
||||
i += 1 |
||||
print("\rRemove useless lines: {:.0%}".format(i / n), end = "") |
||||
print("\rRemove useless lines: complete") |
||||
|
||||
print("{} lines kept".format(len(results))) |
||||
return results |
||||
|
||||
|
||||
def get_best_solution(img, lines): |
||||
px_left = [(x, y) for x in range(img.width) for y in range(img.height) if img.getpixel((x, y)) == 0] |
||||
results = [] |
||||
n = len(px_left) |
||||
|
||||
print("Draw:", end = "") |
||||
while len(px_left): |
||||
lines = [(sum([1 for p in l if p in px_left]), l) for n, l in lines] |
||||
lines = sorted(lines) |
||||
(p, line) = lines.pop() |
||||
px_left = [p for p in px_left if p not in line] |
||||
results.append((line[0], line[-1])) |
||||
print("\rDraw: {:.0%}".format(1 - len(px_left)/n), end="") |
||||
print("\rDraw: complete") |
||||
|
||||
print("Solution found in {} lines".format(len(results))) |
||||
return results |
||||
|
||||
|
||||
|
||||
if __name__ == "__main__": |
||||
parser = ArgumentParser(description='Generate the Multi DrawStat code for an image.') |
||||
parser.add_argument('path', type=str, help='path of the image to process') |
||||
parser.add_argument('-d', '--draw', type=bool, default=False, help='draw the result into a new file and display it') |
||||
|
||||
args = parser.parse_args() |
||||
|
||||
try: |
||||
image = Image.open(args.path) |
||||
except: |
||||
sys.exit("Error! Unable to open file.") |
||||
|
||||
try: |
||||
image = image.convert('1') |
||||
except: |
||||
sys.exit("Error! Unable to convert to 1bit") |
||||
|
||||
print_stats(image) |
||||
lines = get_lines(image) |
||||
lines = removing_doubles(lines) |
||||
lines = removing_useless(lines) |
||||
r = get_best_solution(image, lines) |
||||
|
||||
if draw: |
||||
export = Image.new('RGB', image.size, 'white') |
||||
drawer = ImageDraw.Draw(export) |
||||
for ((a, b), (c, d)) in reversed(r): |
||||
drawer.line((a, b, c, d), fill=(rand(), rand(), rand())) |
||||
export = export.resize((export.width * 8, export.height * 8)) |
||||
export.save(args.path[:-4] + "_gen.png") |
||||
export.show() |
||||
|
||||
print("\n\n=================================================\n\n") |
||||
|
||||
for l in r: |
||||
print(l[0], l[1]) |
||||
|
||||
print("\n\n=================================================\n\nDone!") |
Loading…
Reference in new issue