From 291967dd64e8091b791f576234489cd3e72f0f23 Mon Sep 17 00:00:00 2001 From: Lephenixnoir Date: Tue, 4 Jun 2019 18:08:22 -0400 Subject: [PATCH] improve performance by using more sets --- sprite-optimizer.py | 78 +++++++++++++++------------------------------ 1 file changed, 25 insertions(+), 53 deletions(-) diff --git a/sprite-optimizer.py b/sprite-optimizer.py index 63c6c1f..8788d84 100755 --- a/sprite-optimizer.py +++ b/sprite-optimizer.py @@ -32,8 +32,9 @@ def print_stats(img): def get_lines(img): """Generate all potential lines the image contains""" - lines = [] - pixels = [(x, y) for x in range(img.width) for y in range(img.height) if img.getpixel((x, y)) == 0] + lines = set() + lines_uniq = set() + 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) @@ -42,53 +43,21 @@ def get_lines(img): # for each pair of pixels, get the line for a in pixels: for b in pixels: - line = list(bresenham(a[0], a[1], b[0], b[1])) - is_in = True - for p in line: - if p not in pixels: - is_in = False - break + line = tuple(bresenham(*a, *b)) + line_uniq = tuple(sorted(line)) + # if image contains the line, put it on the array - if is_in: - lines.append(line) + if set(line).issubset(pixels) and line_uniq not in lines_uniq: + lines.add(line) + lines_uniq.add(line_uniq) i += 1 if progress: print("\rGet lines: {:.1%}".format(i / n), end = "") + if progress: print("\rGet lines: complete") - - if progress: print("{} lines found".format(len(lines))) - return lines - - -def removing_doubles(lines): - """Remove lines that are symetric""" - results = [] - n = len(lines) - - if progress: - print("Remove duplicated lines:", end = "") - # for each line, see if it's already in the output array - # beware not to change the orientation of the line (bresenham is not symetric) - # TODO: optimize a bit this operation - for i, l in enumerate(lines): - s = sorted(l) - same = False - for o in results: - if sorted(o) == s: - same = True - break - if same == False: - results.append(l) - if progress: - print("\rRemove double lines: {:.1%}".format(i / n), end = "") - if progress: - print("\rRemove double lines: complete") - - if progress: - print("{} lines kept".format(len(results))) - return results + return list(lines) def removing_useless(lines): @@ -99,18 +68,20 @@ def removing_useless(lines): if progress: print("Remove useless lines:", end = "") # for each line, see if there is a line that contains every pixel of it - for i, l in enumerate(lines): + lines_set = [ set(l) for l in lines ] + + for i, l in enumerate(lines_set): inclusions = 0 # others are all lines that are not l - others = (x for x in lines if x != l) - for k in others: - if len(list(set(l).intersection(set(k)))) == len(l): + for j, k in enumerate(lines_set): + if i == j: continue + if l.issubset(k): inclusions += 1 break # or len(l) == 1 : we keep single pixels to complete the image if necessary # TODO: do some tests to see if it's worth or not if inclusions == 0 or len(l) == 1: - results.append((len(l), l)) + results.append((len(l), lines[i], l)) if progress: print("\rRemove useless lines: {:.1%}".format(i / n), end = "") if progress: @@ -123,22 +94,24 @@ def removing_useless(lines): def get_best_solution(img, lines): """Compute an optimized solution. The magic part of the algorithm""" - px_left = [(x, y) for x in range(img.width) for y in range(img.height) if img.getpixel((x, y)) == 0] + 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) if progress: print("Draw:", end = "") # while the entier image has not been drown - while len(px_left): + while px_left: # define the length of lines - lines = [(sum([1 for p in l if p in px_left]) - len(l)/(2*max(img.size)), l) for n, l in lines] + lines = [(len(l_set.intersection(px_left)) - len(l)/(2*max(img.size)), + l, l_set) for n, l, l_set in lines] # sort them by length lines = sorted(lines) # pop the longest - (p, line) = lines.pop() + (p, line, line_set) = lines.pop() # define the pixels that are not covered by any lines - px_left = [p for p in px_left if p not in line] + px_left = px_left.difference(line_set) results.append((line[0], line[-1])) if progress: print("\rDraw: {:.0%}".format(1 - len(px_left)/n), end="") @@ -222,7 +195,6 @@ if __name__ == "__main__": if args.info: print_stats(image) lines = get_lines(image) - lines = removing_doubles(lines) lines = removing_useless(lines) lines = get_best_solution(image, lines) code = generate_code(lines, args) -- 2.44.0