diff --git a/README.md b/README.md index 6eec0fa..2d5c895 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # linedraw Convert images to vectorized line drawings for plotters. -![Alt text](./screenshots/1.png?raw=true "") +![Alt text](./docs/assets/1.png?raw=true "") - Exports polyline-only svg file with optimized stroke order for plotters; - Sketchy style powered by Perlin noise; @@ -9,44 +9,57 @@ Convert images to vectorized line drawings for plotters. ## Dependencies Python 2 or 3, PIL/Pillow, numpy, OpenCV (Optional for better performance) +```shell +pip install -r requirements.txt +``` + ## Usage Convert an image to line drawing and export .SVG format: ```shell -$ python linedraw.py -i input.jpg -o output.svg +python linedraw.py -i input.jpg -o output.svg ``` Command specs: ``` -usage: linedraw.py [-h] [-i [INPUT_PATH]] [-o [OUTPUT_PATH]] [-b] [-nc] [-nh] - [--no_cv] [--hatch_size [HATCH_SIZE]] - [--contour_simplify [CONTOUR_SIMPLIFY]] +usage: linedraw.py [-h] [-i [INPUT_PATH]] [-o [OUTPUT_PATH]] [-r [RESOLUTION]] [-b] [-nc] [-nh] [--no-cv] [--hatch-size [HATCH_SIZE]] [--contour-simplify [CONTOUR_SIMPLIFY]] [-v] + [--save-settings] Convert image to vectorized line drawing for plotters. -optional arguments: +options: -h, --help show this help message and exit -i [INPUT_PATH], --input [INPUT_PATH] - Input path + Input image path -o [OUTPUT_PATH], --output [OUTPUT_PATH] - Output path. - -b, --show_bitmap Display bitmap preview. - -nc, --no_contour Don't draw contours. - -nh, --no_hatch Disable hatching. - --no_cv Don't use openCV. - --hatch_size [HATCH_SIZE] + Output image path + -r [RESOLUTION], --resolution [RESOLUTION] + Resolution of the output image + -b, --show-bitmap Display bitmap preview. + -nc, --no-contour Don't draw contours. + -nh, --no-hatch Disable hatching. + --no-cv Don't use openCV. + --hatch-size [HATCH_SIZE] Patch size of hatches. eg. 8, 16, 32 - --contour_simplify [CONTOUR_SIMPLIFY] + --contour-simplify [CONTOUR_SIMPLIFY] Level of contour simplification. eg. 1, 2, 3 + -v, --visualize Visualize the output using turtle + --save-settings To Save the settings to a json file + ``` Python: ```python import linedraw + +linedraw.argument.resolution = 512 # set arguments lines = linedraw.sketch("path/to/img.jpg") # return list of polylines, eg. - # [[(x,y),(x,y),(x,y)],[(x,y),(x,y),...],...] - -linedraw.visualize(lines) # simulates plotter behavior - # draw the lines in order using turtle graphics. +# [[(x,y),(x,y),(x,y)],[(x,y),(x,y),...],...] + +linedraw.visualize(lines) # simulates plotter behavior +# draw the lines in order using turtle graphics. ``` +## Future Plans +1. Rasterised Output +2. GUI for the tool \ No newline at end of file diff --git a/screenshots/1.png b/docs/assets/1.png similarity index 100% rename from screenshots/1.png rename to docs/assets/1.png diff --git a/images/cameraman.tif b/images/cameraman.tif deleted file mode 100755 index 7f21122..0000000 Binary files a/images/cameraman.tif and /dev/null differ diff --git a/images/lenna.png b/images/lenna.png deleted file mode 100644 index 59ef68a..0000000 Binary files a/images/lenna.png and /dev/null differ diff --git a/images/peppers.png b/images/peppers.png deleted file mode 100644 index 8fb25c2..0000000 Binary files a/images/peppers.png and /dev/null differ diff --git a/images/test.jpg b/images/test.jpg deleted file mode 100644 index ea01a22..0000000 Binary files a/images/test.jpg and /dev/null differ diff --git a/line_draw/__init__.py b/line_draw/__init__.py new file mode 100644 index 0000000..d927c62 --- /dev/null +++ b/line_draw/__init__.py @@ -0,0 +1 @@ +from line_draw.helper import sketch \ No newline at end of file diff --git a/line_draw/default.py b/line_draw/default.py new file mode 100644 index 0000000..d60a0d3 --- /dev/null +++ b/line_draw/default.py @@ -0,0 +1,29 @@ +import json + +class Default: + export_path = "output/out.svg" + show_bitmap = False + draw_contours = True + draw_hatch = True + no_cv = False + hatch_size = 16 + contour_simplify = 2 + resolution = 1024 + save_settings = False + + def save(self,settings_path): + print("Savings settings to a JSON file") + file = open(settings_path, 'w') + data = { + "resolution": self.resolution, + "show_bitmap": self.show_bitmap, + "draw_contours": self.draw_contours, + "draw_hatch": self.draw_hatch, + "use_opencv": not self.no_cv, + "hatch_size": self.hatch_size, + "contour_simplify": self.contour_simplify + } + json.dump(data,file) + file.close() + +argument = Default() \ No newline at end of file diff --git a/filters.py b/line_draw/filters.py similarity index 100% rename from filters.py rename to line_draw/filters.py diff --git a/line_draw/helper.py b/line_draw/helper.py new file mode 100644 index 0000000..48cec95 --- /dev/null +++ b/line_draw/helper.py @@ -0,0 +1,235 @@ +from PIL import Image, ImageOps, ImageDraw +import line_draw.perlin as perlin +from datetime import datetime +import os + +from line_draw.filters import appmask, F_SobelX, F_SobelY +from line_draw.default import argument +from line_draw.util import distsum, is_image_file, extract_file_name_and_extension +from line_draw.strokesort import sortlines + + +def sketch(input_path, output_path:str): + IMAGE = None + + if not is_image_file(input_path): + return print("Please provide the path for an image.") + + out_file, out_ext = extract_file_name_and_extension(output_path) + + if not out_file: + in_file, in_ext = extract_file_name_and_extension(input_path) + out_ext = '.svg' + if not output_path.endswith('/'): + output_path += '/' + output_path += in_file + out_ext + + if out_ext != '.svg': + return print("Currently we can only save as svg file") + + try: + IMAGE = Image.open(input_path) + except FileNotFoundError: + return print("The Input File wasn't found. Check Path") + + width, height = IMAGE.size + + IMAGE = IMAGE.convert("L") + IMAGE = ImageOps.autocontrast(IMAGE, 10) + + lines = [] + + if argument.draw_contours: + lines += get_contours(IMAGE.resize((argument.resolution // argument.contour_simplify, + argument.resolution // argument.contour_simplify * height // width))) + + if argument.draw_hatch: + lines += hatch(IMAGE.resize( + (argument.resolution // argument.hatch_size, argument.resolution // argument.hatch_size * height // width))) + + lines = sortlines(lines) + + if argument.show_bitmap: + disp = Image.new("RGB", (argument.resolution, argument.resolution * height // width), (255, 255, 255)) + draw = ImageDraw.Draw(disp) + for l in lines: + draw.line(l, (0, 0, 0), 5) + disp.show() + + # if out_ext != '.svg': + # now = datetime.now() + # svg_path = output_path.rsplit('/', 1)[0] + now.strftime("%Y%m%d%H%M%S%f") + '.svg' + # else: + # svg_path = output_path + + file = open(output_path, 'w') + file.write(make_svg(lines)) + file.close() + + # if out_ext != '.svg': + # if not is_image_file(output_path): + # return "Output path is not an image path" + # rasterise_image(svg_path,output_path) + # os.remove(svg_path) + print(len(lines), "strokes.") + if argument.save_settings: + argument.save(os.path.dirname(output_path) + '/settings.json') + print("done.") + return lines + + +def get_contours(image): + print("Generating Contours....") + image = find_edges(image) + image_copy1 = image.copy() + image_copy2 = image.rotate(-90, expand=True).transpose(Image.FLIP_LEFT_RIGHT) + image_copy1_dots = get_dots(image_copy1) + image_copy1_contours = connect_dots(image_copy1_dots) + image_copy2_dots = get_dots(image_copy2) + image_copy2_contours = connect_dots(image_copy2_dots) + + for i in range(len(image_copy2_contours)): + image_copy2_contours[1] = [(c[1], c[0]) for c in image_copy2_contours[i]] + contours = image_copy1_contours + image_copy2_contours + + for i in range(len(contours)): + for j in range(len(contours)): + if len(contours[i]) > 0 and len(contours[j]) > 0: + if distsum(contours[j][0], contours[i][-1]) < 8: + contours[i] = contours[i] + contours[j] + contours[j] = [] + + for i in range(len(contours)): + contours[i] = [contours[i][j] for j in range(0, len(contours[i]), 8)] + + contours = [c for c in contours if len(c) > 1] + + for i in range(0, len(contours)): + contours[i] = [(v[0] * argument.contour_simplify, v[1] * argument.contour_simplify) for v in contours[i]] + + for i in range(0, len(contours)): + for j in range(0, len(contours[i])): + contours[i][j] = int(contours[i][j][0] + 10 * perlin.noise(i * 0.5, j * 0.1, 1)), int( + contours[i][j][1] + 10 * perlin.noise(i * 0.5, j * 0.1, 2)) + + return contours + + +def find_edges(image): + print("Fining Edges....") + if argument.no_cv: + appmask(image, [F_SobelX, F_SobelY]) + else: + import numpy as np + import cv2 + image = np.array(image) + image = cv2.GaussianBlur(image, (3, 3), 0) + image = cv2.Canny(image, 100, 200) + image = Image.fromarray(image) + return image.point(lambda p: p > 128 and 255) + + +def get_dots(image): + print("Getting contour points...") + PX = image.load() + dots = [] + width, height = image.size + for y in range(height - 1): + row = [] + for x in range(1, width): + if PX[x, y] == 255: + if len(row) > 0: + if x - row[-1][0] == row[-1][-1] + 1: + row[-1] = (row[-1][0], row[-1][-1] + 1) + else: + row.append((x, 0)) + else: + row.append((x, 0)) + dots.append(row) + return dots + + +def connect_dots(dots): + print("Connecting contour points....") + contours = [] + for y in range(len(dots)): + for x, v in dots[y]: + if v > -1: + if y == 0: + contours.append([(x, y)]) + else: + closest = -1 + cdist = 100 + for x0, v0 in dots[y - 1]: + if abs(x0 - x) < cdist: + cdist = abs(x0 - x) + closest = x0 + if cdist > 3: + contours.append([(x, y)]) + else: + found = 0 + for i in range(len(contours)): + if contours[i][-1] == (closest, y - 1): + contours[i].append((x, y,)) + found = 1 + break + if found == 0: + contours.append([(x, y)]) + for c in contours: + if c[-1][1] < y - 1 and len(c) < 4: + contours.remove(c) + return contours + + +def hatch(image): + print("Hatching....") + PX = image.load() + width, height = image.size + lg1 = [] + lg2 = [] + for x0 in range(width): + for y0 in range(height): + x = x0 * argument.hatch_size + y = y0 * argument.hatch_size + if PX[x0, y0] > 144: + pass + elif PX[x0, y0] > 64: + lg1.append([(x, y + argument.hatch_size / 4), (x + argument.hatch_size, y + argument.hatch_size / 4)]) + elif PX[x0, y0] > 16: + lg1.append([(x, y + argument.hatch_size / 4), (x + argument.hatch_size, y + argument.hatch_size / 4)]) + lg2.append([(x + argument.hatch_size, y), (x, y + argument.hatch_size)]) + else: + lg1.append([(x, y + argument.hatch_size / 4), (x + argument.hatch_size, y + argument.hatch_size / 4)]) + lg1.append([(x, y + argument.hatch_size / 2 + argument.hatch_size / 4), + (x + argument.hatch_size, y + argument.hatch_size / 2 + argument.hatch_size / 4)]) + lg2.append([(x + argument.hatch_size, y), (x, y + argument.hatch_size)]) + lines = [lg1, lg2] + for k in range(0, len(lines)): + for i in range(0, len(lines[k])): + for j in range(0, len(lines[k])): + if lines[k][i] != [] and lines[k][j] != []: + if lines[k][i][-1] == lines[k][j][0]: + lines[k][i] = lines[k][i] + lines[k][j][1:] + lines[k][j] = [] + lines[k] = [l for l in lines[k] if len(l) > 0] + lines = lines[0] + lines[1] + for i in range(0, len(lines)): + for j in range(0, len(lines[i])): + lines[i][j] = int(lines[i][j][0] + argument.hatch_size * perlin.noise(i * 0.5, j * 0.1, 1)), int( + lines[i][j][1] + argument.hatch_size * perlin.noise(i * 0.5, j * 0.1, 2)) - j + return lines + + +def make_svg(lines): + print("Generating SVG file....") + out = '' + for l in lines: + l = ",".join([str(p[0] * 0.5) + "," + str(p[1] * 0.5) for p in l]) + out += '\n' + out += '' + return out + + +def rasterise_image(svg_image, raster_image): + print("Converting image....") + # to be implemented diff --git a/perlin.py b/line_draw/perlin.py similarity index 100% rename from perlin.py rename to line_draw/perlin.py diff --git a/strokesort.py b/line_draw/strokesort.py similarity index 92% rename from strokesort.py rename to line_draw/strokesort.py index 748e6d5..c98c2ba 100644 --- a/strokesort.py +++ b/line_draw/strokesort.py @@ -1,6 +1,6 @@ from random import * from PIL import Image, ImageDraw, ImageOps -from util import * +from line_draw.util import * def sortlines(lines): @@ -38,8 +38,8 @@ def visualize(lines): turtle.mainloop() if __name__=="__main__": - import linedraw + import line_draw #linedraw.draw_hatch = False - lines = linedraw.sketch("Lenna") + lines = line_draw.sketch("Lenna") #lines = sortlines(lines) visualize(lines) \ No newline at end of file diff --git a/line_draw/util.py b/line_draw/util.py new file mode 100644 index 0000000..8867080 --- /dev/null +++ b/line_draw/util.py @@ -0,0 +1,22 @@ +import os +def midpt(*args): + xs,ys = 0,0 + for p in args: + xs += p[0] + ys += p[1] + return xs/len(args),ys/len(args) + +def distsum(*args): + return sum([ ((args[i][0]-args[i-1][0])**2 + (args[i][1]-args[i-1][1])**2)**0.5 for i in range(1,len(args))]) + + +def is_image_file(file_path): + image_extensions = ['.jpg', '.jpeg', '.png'] + tmp,ext = extract_file_name_and_extension(file_path) + return ext in image_extensions + + +def extract_file_name_and_extension(file_path): + file_name_with_extension = os.path.basename(file_path) + file_name, file_extension = os.path.splitext(file_name_with_extension) + return file_name, file_extension \ No newline at end of file diff --git a/linedraw.py b/linedraw.py index 467c27d..789bb02 100644 --- a/linedraw.py +++ b/linedraw.py @@ -1,263 +1,68 @@ -from random import * -import math import argparse -from PIL import Image, ImageDraw, ImageOps - -from filters import * -from strokesort import * -import perlin -from util import * - -no_cv = False -export_path = "output/out.svg" -draw_contours = True -draw_hatch = True -show_bitmap = False -resolution = 1024 -hatch_size = 16 -contour_simplify = 2 - -try: - import numpy as np - import cv2 -except: - print("Cannot import numpy/openCV. Switching to NO_CV mode.") - no_cv = True - -def find_edges(IM): - print("finding edges...") - if no_cv: - #appmask(IM,[F_Blur]) - appmask(IM,[F_SobelX,F_SobelY]) - else: - im = np.array(IM) - im = cv2.GaussianBlur(im,(3,3),0) - im = cv2.Canny(im,100,200) - IM = Image.fromarray(im) - return IM.point(lambda p: p > 128 and 255) - - -def getdots(IM): - print("getting contour points...") - PX = IM.load() - dots = [] - w,h = IM.size - for y in range(h-1): - row = [] - for x in range(1,w): - if PX[x,y] == 255: - if len(row) > 0: - if x-row[-1][0] == row[-1][-1]+1: - row[-1] = (row[-1][0],row[-1][-1]+1) - else: - row.append((x,0)) - else: - row.append((x,0)) - dots.append(row) - return dots - -def connectdots(dots): - print("connecting contour points...") - contours = [] - for y in range(len(dots)): - for x,v in dots[y]: - if v > -1: - if y == 0: - contours.append([(x,y)]) - else: - closest = -1 - cdist = 100 - for x0,v0 in dots[y-1]: - if abs(x0-x) < cdist: - cdist = abs(x0-x) - closest = x0 - - if cdist > 3: - contours.append([(x,y)]) - else: - found = 0 - for i in range(len(contours)): - if contours[i][-1] == (closest,y-1): - contours[i].append((x,y,)) - found = 1 - break - if found == 0: - contours.append([(x,y)]) - for c in contours: - if c[-1][1] < y-1 and len(c)<4: - contours.remove(c) - return contours - - -def getcontours(IM,sc=2): - print("generating contours...") - IM = find_edges(IM) - IM1 = IM.copy() - IM2 = IM.rotate(-90,expand=True).transpose(Image.FLIP_LEFT_RIGHT) - dots1 = getdots(IM1) - contours1 = connectdots(dots1) - dots2 = getdots(IM2) - contours2 = connectdots(dots2) - - for i in range(len(contours2)): - contours2[i] = [(c[1],c[0]) for c in contours2[i]] - contours = contours1+contours2 - - for i in range(len(contours)): - for j in range(len(contours)): - if len(contours[i]) > 0 and len(contours[j])>0: - if distsum(contours[j][0],contours[i][-1]) < 8: - contours[i] = contours[i]+contours[j] - contours[j] = [] - - for i in range(len(contours)): - contours[i] = [contours[i][j] for j in range(0,len(contours[i]),8)] - - - contours = [c for c in contours if len(c) > 1] - - for i in range(0,len(contours)): - contours[i] = [(v[0]*sc,v[1]*sc) for v in contours[i]] - - for i in range(0,len(contours)): - for j in range(0,len(contours[i])): - contours[i][j] = int(contours[i][j][0]+10*perlin.noise(i*0.5,j*0.1,1)),int(contours[i][j][1]+10*perlin.noise(i*0.5,j*0.1,2)) - - return contours - - -def hatch(IM,sc=16): - print("hatching...") - PX = IM.load() - w,h = IM.size - lg1 = [] - lg2 = [] - for x0 in range(w): - for y0 in range(h): - x = x0*sc - y = y0*sc - if PX[x0,y0] > 144: - pass - - elif PX[x0,y0] > 64: - lg1.append([(x,y+sc/4),(x+sc,y+sc/4)]) - elif PX[x0,y0] > 16: - lg1.append([(x,y+sc/4),(x+sc,y+sc/4)]) - lg2.append([(x+sc,y),(x,y+sc)]) - - else: - lg1.append([(x,y+sc/4),(x+sc,y+sc/4)]) - lg1.append([(x,y+sc/2+sc/4),(x+sc,y+sc/2+sc/4)]) - lg2.append([(x+sc,y),(x,y+sc)]) - - lines = [lg1,lg2] - for k in range(0,len(lines)): - for i in range(0,len(lines[k])): - for j in range(0,len(lines[k])): - if lines[k][i] != [] and lines[k][j] != []: - if lines[k][i][-1] == lines[k][j][0]: - lines[k][i] = lines[k][i]+lines[k][j][1:] - lines[k][j] = [] - lines[k] = [l for l in lines[k] if len(l) > 0] - lines = lines[0]+lines[1] - - for i in range(0,len(lines)): - for j in range(0,len(lines[i])): - lines[i][j] = int(lines[i][j][0]+sc*perlin.noise(i*0.5,j*0.1,1)),int(lines[i][j][1]+sc*perlin.noise(i*0.5,j*0.1,2))-j - return lines - - -def sketch(path): - IM = None - possible = [path,"images/"+path,"images/"+path+".jpg","images/"+path+".png","images/"+path+".tif"] - for p in possible: - try: - IM = Image.open(p) - break - except FileNotFoundError: - print("The Input File wasn't found. Check Path") - exit(0) - pass - w,h = IM.size - - IM = IM.convert("L") - IM=ImageOps.autocontrast(IM,10) - - lines = [] - if draw_contours: - lines += getcontours(IM.resize((resolution//contour_simplify,resolution//contour_simplify*h//w)),contour_simplify) - if draw_hatch: - lines += hatch(IM.resize((resolution//hatch_size,resolution//hatch_size*h//w)),hatch_size) - - lines = sortlines(lines) - if show_bitmap: - disp = Image.new("RGB",(resolution,resolution*h//w),(255,255,255)) - draw = ImageDraw.Draw(disp) - for l in lines: - draw.line(l,(0,0,0),5) - disp.show() - - f = open(export_path,'w') - f.write(makesvg(lines)) - f.close() - print(len(lines),"strokes.") - print("done.") - return lines +from line_draw import sketch +from line_draw.default import argument +from line_draw.strokesort import visualize +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Convert image to vectorized line drawing for plotters.') + parser.add_argument('-i', '--input', dest='input_path', + default='lenna', action='store', nargs='?', type=str, + help='Input image path') -def makesvg(lines): - print("generating svg file...") - out = '' - for l in lines: - l = ",".join([str(p[0]*0.5)+","+str(p[1]*0.5) for p in l]) - out += '\n' - out += '' - return out + parser.add_argument('-o', '--output', dest='output_path', + default=argument.export_path, action='store', nargs='?', type=str, + help='Output image path') + parser.add_argument('-r', '--resolution', dest='resolution', + default=argument.resolution, action='store', nargs='?', type=int, + help='Resolution of the output image') + parser.add_argument('-b', '--show-bitmap', dest='show_bitmap', + const=not argument.show_bitmap, default=argument.show_bitmap, action='store_const', + help='Display bitmap preview.') -if __name__ == "__main__": - parser = argparse.ArgumentParser(description='Convert image to vectorized line drawing for plotters.') - parser.add_argument('-i','--input',dest='input_path', - default='lenna',action='store',nargs='?',type=str, - help='Input path') + parser.add_argument('-nc', '--no-contour', dest='no_contour', + const=argument.draw_contours, default=not argument.draw_contours, action='store_const', + help="Don't draw contours.") - parser.add_argument('-o','--output',dest='output_path', - default=export_path,action='store',nargs='?',type=str, - help='Output path.') + parser.add_argument('-nh', '--no-hatch', dest='no_hatch', + const=argument.draw_hatch, default=not argument.draw_hatch, action='store_const', + help='Disable hatching.') - parser.add_argument('-b','--show_bitmap',dest='show_bitmap', - const = not show_bitmap,default= show_bitmap,action='store_const', - help="Display bitmap preview.") + parser.add_argument('--no-cv', dest='no_cv', + const=not argument.no_cv, default=argument.no_cv, action='store_const', + help="Don't use openCV.") - parser.add_argument('-nc','--no_contour',dest='no_contour', - const = draw_contours,default= not draw_contours,action='store_const', - help="Don't draw contours.") - - parser.add_argument('-nh','--no_hatch',dest='no_hatch', - const = draw_hatch,default= not draw_hatch,action='store_const', - help='Disable hatching.') + parser.add_argument('--hatch-size', dest='hatch_size', + default=argument.hatch_size, action='store', nargs='?', type=int, + help='Patch size of hatches. eg. 8, 16, 32') - parser.add_argument('--no_cv',dest='no_cv', - const = not no_cv,default= no_cv,action='store_const', - help="Don't use openCV.") + parser.add_argument('--contour-simplify', dest='contour_simplify', + default=argument.contour_simplify, action='store', nargs='?', type=int, + help='Level of contour simplification. eg. 1, 2, 3') + parser.add_argument('-v', '--visualize', dest='visualize', + const=True, default=False, action='store_const', + help='Visualize the output using turtle') - parser.add_argument('--hatch_size',dest='hatch_size', - default=hatch_size,action='store',nargs='?',type=int, - help='Patch size of hatches. eg. 8, 16, 32') - parser.add_argument('--contour_simplify',dest='contour_simplify', - default=contour_simplify,action='store',nargs='?',type=int, - help='Level of contour simplification. eg. 1, 2, 3') + parser.add_argument('--save-settings', dest='save_settings', + const=not argument.save_settings, default=argument.save_settings, action='store_const', + help='To Save the settings to a json file') args = parser.parse_args() - + + input_path = args.input_path export_path = args.output_path - draw_hatch = not args.no_hatch - draw_contours = not args.no_contour - hatch_size = args.hatch_size - contour_simplify = args.contour_simplify - show_bitmap = args.show_bitmap - no_cv = args.no_cv - sketch(args.input_path) + argument.draw_hatch = not args.no_hatch + argument.contour_simplify = not args.no_contour + argument.hatch_size = args.hatch_size + argument.contour_simplify = args.contour_simplify + argument.show_bitmap = args.show_bitmap + argument.no_cv = args.no_cv + argument.resolution = args.resolution + argument.save_settings = args.save_settings + lines = sketch(input_path, export_path) + if args.visualize: + if lines: + visualize(lines) diff --git a/output/out.svg b/output/out.svg deleted file mode 100644 index 1bdc321..0000000 --- a/output/out.svg +++ /dev/null @@ -1,1275 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..ed07be1 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +Pillow +Numpy +opencv-python \ No newline at end of file diff --git a/util.py b/util.py deleted file mode 100644 index 235c3ed..0000000 --- a/util.py +++ /dev/null @@ -1,9 +0,0 @@ -def midpt(*args): - xs,ys = 0,0 - for p in args: - xs += p[0] - ys += p[1] - return xs/len(args),ys/len(args) - -def distsum(*args): - return sum([ ((args[i][0]-args[i-1][0])**2 + (args[i][1]-args[i-1][1])**2)**0.5 for i in range(1,len(args))])