142 lines
3.6 KiB
Python
142 lines
3.6 KiB
Python
|
#!/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!")
|