diff --git a/vectorizing/__init__.py b/vectorizing/__init__.py index 8079cd4..bbd83ac 100644 --- a/vectorizing/__init__.py +++ b/vectorizing/__init__.py @@ -35,8 +35,8 @@ def process_binary(img): solver = BinarySolver(img) return solver.solve() -def process_color(img, color_count, timer): - solver = ColorSolver(img, color_count, timer) +def process_color(img, color_count, tolerance, timer): + solver = ColorSolver(img, color_count, tolerance, timer) return solver.solve() def validate_args(args): @@ -56,12 +56,17 @@ def validate_args(args): if not only_numbers: return False + tolerance = args.get("tolerance") + if tolerance is not None and tolerance < 0: + return False + return SimpleNamespace( - crop_box = box, - solver = solver, - url = args.get('url'), - raw = args.get('raw'), - color_count = args.get('color_count'), + crop_box=box, + solver=solver, + url=args.get("url"), + raw=args.get("raw"), + color_count=args.get("color_count"), + tolerance=args.get("tolerance"), ) def invalid_args(): @@ -87,6 +92,10 @@ def index(): color_count = args.color_count raw = args.raw crop_box = args.crop_box + tolerance = args.tolerance + + if tolerance is None: + tolerance = 0.2 try: timer = Timer() @@ -105,7 +114,7 @@ def index(): else: timer.start_timer('Color Solver - Total') - solved = process_color(img, color_count, timer) + solved = process_color(img, color_count, tolerance, timer) timer.end_timer() compound_paths, colors, width, height = solved @@ -122,7 +131,7 @@ def index(): timer.end_timer() timer.start_timer('Bounds Creation') - bounds = compound_path_list_bounds(compound_paths) + bounds = compound_path_list_bounds(compound_paths, tolerance) timer.end_timer() app.logger.info(timer.timelog()) diff --git a/vectorizing/geometry/bounds.py b/vectorizing/geometry/bounds.py index bc665d8..00dd99f 100644 --- a/vectorizing/geometry/bounds.py +++ b/vectorizing/geometry/bounds.py @@ -34,19 +34,19 @@ def compute_total_bounds(bounds_list): ) # Calculates bounds of a path made out CubicBeziers and SegmentLists -def path_bounds(path): - bounds = [item.bounds() for item in path] +def path_bounds(path, tolerance): + bounds = [item.bounds(tolerance) for item in path] return compute_total_bounds(bounds) # Calculates bounds of a compound path, meaning a list of paths -def compound_path_bounds(compound_path): - bounds = [path_bounds(path) for path in compound_path] +def compound_path_bounds(compound_path, tolerance): + bounds = [path_bounds(path, tolerance) for path in compound_path] return compute_total_bounds(bounds) # Calculates bounds of a list of compound paths -def compound_path_list_bounds(compound_path_list): +def compound_path_list_bounds(compound_path_list, tolerance): bounds = [ - compound_path_bounds(compound_path) + compound_path_bounds(compound_path, tolerance) for compound_path in compound_path_list if len(compound_path) > 0 ] diff --git a/vectorizing/geometry/cubic_bezier.py b/vectorizing/geometry/cubic_bezier.py index 29f1b23..4490d6b 100644 --- a/vectorizing/geometry/cubic_bezier.py +++ b/vectorizing/geometry/cubic_bezier.py @@ -79,14 +79,14 @@ def subdivide(points): ) @njit -def flatten(points): +def flatten(points, tolerance): stack = [points] flattened = [] while len(stack): first = stack.pop() - if is_flat_enough(first): + if is_flat_enough(first, tolerance): flattened.append(first[0]) flattened.append(first[1]) @@ -113,9 +113,9 @@ def scaled(self, s): self.p3 * s ) - def flattened(self): + def flattened(self, tolerance): points = (tuple(self.p0), tuple(self.p1), tuple(self.p2), tuple(self.p3)) - return SegmentList(np.array(flatten(points))) + return SegmentList(np.array(flatten(points, tolerance))) - def bounds(self): - return self.flattened().bounds() \ No newline at end of file + def bounds(self, tolerance): + return self.flattened(tolerance).bounds(tolerance) \ No newline at end of file diff --git a/vectorizing/geometry/potrace.py b/vectorizing/geometry/potrace.py index 695b380..b3edabc 100644 --- a/vectorizing/geometry/potrace.py +++ b/vectorizing/geometry/potrace.py @@ -55,8 +55,11 @@ def unfold_polygon(folded_polygon): # Given a compound path, it converts it to a compound polygon # by flattening curves. # All coordinates can be scaled for convenience (see pyclipper) -def compound_path_to_compound_polygon(compound_path, scale = 1): - polygons = [[item.flattened().scaled(scale) for item in path] for path in compound_path] +def compound_path_to_compound_polygon(compound_path, tolerance, scale=1): + polygons = [ + [item.flattened(tolerance).scaled(scale) for item in path] + for path in compound_path + ] return [unfold_polygon(folded_polygon) for folded_polygon in polygons] # Given a compound polygon, it converts it to a compound path. diff --git a/vectorizing/geometry/segment_list.py b/vectorizing/geometry/segment_list.py index f488cae..61192da 100644 --- a/vectorizing/geometry/segment_list.py +++ b/vectorizing/geometry/segment_list.py @@ -11,13 +11,13 @@ def __init__(self, points): def scaled(self, s): return SegmentList(self.points * s) - def flattened(self): + def flattened(self, _): return self def to_list(self): return list(self.points) - def bounds(self): + def bounds(self, _): t = self.points.T x = t[0] y = t[1] diff --git a/vectorizing/solvers/color/ColorSolver.py b/vectorizing/solvers/color/ColorSolver.py index f047a29..9fdb854 100644 --- a/vectorizing/solvers/color/ColorSolver.py +++ b/vectorizing/solvers/color/ColorSolver.py @@ -7,11 +7,12 @@ from vectorizing.solvers.color.bitmaps import create_bitmaps class ColorSolver: - def __init__(self, img, color_count, timer): + def __init__(self, img, color_count, tolerance, timer): color_count = color_count or ColorSolver.DEFAULT_COLOR_COUNT color_count = max(color_count, ColorSolver.MIN_COLOR_COUNT) color_count = min(color_count, ColorSolver.MAX_COLOR_COUNT) self.color_count = color_count + self.tolerance = tolerance self.img = limit_size(img) @@ -34,7 +35,7 @@ def solve(self): self.timer.end_timer() self.timer.start_timer('Polygon Clipping') - compound_paths = remove_layering(traced_bitmaps) + compound_paths = remove_layering(traced_bitmaps, self.tolerance) self.timer.end_timer() return [ diff --git a/vectorizing/solvers/color/clip.py b/vectorizing/solvers/color/clip.py index 42d5adc..a409566 100644 --- a/vectorizing/solvers/color/clip.py +++ b/vectorizing/solvers/color/clip.py @@ -13,14 +13,14 @@ # NOTE: The clipper library uses integer coordinates only for numerical robustness. # That's why coordinates are scaled by a big factor, to preserve precision. -def remove_layering(traced_bitmaps): +def remove_layering(traced_bitmaps, tolerance): compound_paths = [ potrace_path_to_compound_path(traced) for traced in traced_bitmaps ] compound_polygons = [ - compound_path_to_compound_polygon(compound_path, SCALE) + compound_path_to_compound_polygon(compound_path, tolerance, SCALE) for compound_path in compound_paths ]