Un générateur de multi-drawstat à partir d'une image. L'un des plus optimisés à ce jour.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

142 lines
3.6 KiB

  1. #!/usr/bin/env python3
  2. from argparse import ArgumentParser
  3. from bresenham import bresenham
  4. from PIL import Image, ImageDraw
  5. from random import randint
  6. import sys
  7. rand = lambda: randint(0,255)
  8. def print_stats(img):
  9. pixels = img.getdata()
  10. count = sum([1 for i in pixels if i == 0])
  11. print("{} black pixels over {} ({:.1%})".format(count, len(pixels), count/len(pixels)))
  12. def get_lines(img):
  13. lines = []
  14. pixels = [(x, y) for x in range(img.width) for y in range(img.height) if img.getpixel((x, y)) == 0]
  15. i, n = 0, len(pixels) * len(pixels)
  16. print("Get lines:", end = "")
  17. for a in pixels:
  18. for b in pixels:
  19. line = list(bresenham(b[0], b[1], a[0], a[1]))
  20. r = len([0 for p in line if p not in pixels])
  21. if not r:
  22. lines.append(line)
  23. i += 1
  24. print("\rGet lines: {:.0%}".format(i / n), end = "")
  25. print("\rGet lines: complete")
  26. print("{} lines found".format(len(lines)))
  27. return lines
  28. def removing_doubles(lines):
  29. results = []
  30. i, n = 0, len(lines)
  31. print("Remove duplicated lines:", end = "")
  32. for l in lines:
  33. s = sorted(l)
  34. same = False
  35. for o in results:
  36. if sorted(o) == s:
  37. same = True
  38. break
  39. if same == False:
  40. results.append(l)
  41. i += 1
  42. print("\rRemove double lines: {:.0%}".format(i / n), end = "")
  43. print("\rRemove double lines: complete")
  44. print("{} lines kept".format(len(results)))
  45. return results
  46. def removing_useless(lines):
  47. results = []
  48. i, n = 0, len(lines)
  49. print("Remove useless lines:", end = "")
  50. for l in lines:
  51. inclusions = 0
  52. others = (x for x in lines if x != l)
  53. for k in others:
  54. if len(list(set(l).intersection(set(k)))) == len(l):
  55. inclusions += 1
  56. break
  57. if inclusions == 0 or len(l) == 1:
  58. results.append((len(l), l))
  59. i += 1
  60. print("\rRemove useless lines: {:.0%}".format(i / n), end = "")
  61. print("\rRemove useless lines: complete")
  62. print("{} lines kept".format(len(results)))
  63. return results
  64. def get_best_solution(img, lines):
  65. px_left = [(x, y) for x in range(img.width) for y in range(img.height) if img.getpixel((x, y)) == 0]
  66. results = []
  67. n = len(px_left)
  68. print("Draw:", end = "")
  69. while len(px_left):
  70. lines = [(sum([1 for p in l if p in px_left]), l) for n, l in lines]
  71. lines = sorted(lines)
  72. (p, line) = lines.pop()
  73. px_left = [p for p in px_left if p not in line]
  74. results.append((line[0], line[-1]))
  75. print("\rDraw: {:.0%}".format(1 - len(px_left)/n), end="")
  76. print("\rDraw: complete")
  77. print("Solution found in {} lines".format(len(results)))
  78. return results
  79. if __name__ == "__main__":
  80. parser = ArgumentParser(description='Generate the Multi DrawStat code for an image.')
  81. parser.add_argument('path', type=str, help='path of the image to process')
  82. parser.add_argument('-d', '--draw', type=bool, default=False, help='draw the result into a new file and display it')
  83. args = parser.parse_args()
  84. try:
  85. image = Image.open(args.path)
  86. except:
  87. sys.exit("Error! Unable to open file.")
  88. try:
  89. image = image.convert('1')
  90. except:
  91. sys.exit("Error! Unable to convert to 1bit")
  92. print_stats(image)
  93. lines = get_lines(image)
  94. lines = removing_doubles(lines)
  95. lines = removing_useless(lines)
  96. r = get_best_solution(image, lines)
  97. if draw:
  98. export = Image.new('RGB', image.size, 'white')
  99. drawer = ImageDraw.Draw(export)
  100. for ((a, b), (c, d)) in reversed(r):
  101. drawer.line((a, b, c, d), fill=(rand(), rand(), rand()))
  102. export = export.resize((export.width * 8, export.height * 8))
  103. export.save(args.path[:-4] + "_gen.png")
  104. export.show()
  105. print("\n\n=================================================\n\n")
  106. for l in r:
  107. print(l[0], l[1])
  108. print("\n\n=================================================\n\nDone!")