making it pretty
This commit is contained in:
parent
64b1b91f21
commit
0d0fd3e638
2
draw.py
2
draw.py
|
@ -5,8 +5,8 @@ machine chooch.
|
|||
"""
|
||||
import os
|
||||
|
||||
import linedraw
|
||||
import stream
|
||||
import linedraw
|
||||
|
||||
def draw(rec_filename):
|
||||
"""
|
||||
|
|
204
linedraw.py
204
linedraw.py
|
@ -1,11 +1,15 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Takes a raster image file and vectorizes it to create line art usable by
|
||||
a pen plotter.
|
||||
"""
|
||||
import os
|
||||
from random import *
|
||||
import math
|
||||
from random import *
|
||||
|
||||
from PIL import Image, ImageDraw, ImageOps
|
||||
|
||||
no_cv = True
|
||||
export_path = "output/out.svg"
|
||||
draw_contours = True
|
||||
draw_hatch = False
|
||||
|
||||
|
@ -24,16 +28,18 @@ F_Blur = {
|
|||
(-2,1):4,(-1,1):9,(0,1):12,(1,1):9,(2,1):4,
|
||||
(-2,2):2,(-1,2):4,(0,2):5,(1,2):4,(2,2):2,
|
||||
}
|
||||
|
||||
F_SobelX = {
|
||||
(-1,-1): 1,
|
||||
(0,-1): 0,
|
||||
(1,-1): -1,
|
||||
(1,-1): -1,
|
||||
(-1,0): 2,
|
||||
(0,0): 0,
|
||||
(1,0): -2,
|
||||
(1,0): -2,
|
||||
(-1,1): 1,
|
||||
(0,1): 0,
|
||||
(1,1): -1}
|
||||
(1,1) -1}
|
||||
|
||||
F_SobelY = {
|
||||
(-1,-1): 1,
|
||||
(0,-1): 2,
|
||||
|
@ -41,27 +47,27 @@ F_SobelY = {
|
|||
(-1,0): 0,
|
||||
(0,0): 0,
|
||||
(1,0): 0,
|
||||
(-1,1): -1,
|
||||
(0,1): -2,
|
||||
(1,1): -1}
|
||||
(-1,1): -1,
|
||||
(0,1): -2,
|
||||
(1,1): -1}
|
||||
|
||||
def appmask(IM,masks):
|
||||
PX = IM.load()
|
||||
w,h = IM.size
|
||||
def appmask(image, masks):
|
||||
PX = image.load()
|
||||
w, h = image.size
|
||||
NPX = {}
|
||||
for x in range(0,w):
|
||||
for y in range(0,h):
|
||||
for x in range(0, w):
|
||||
for y in range(0, h):
|
||||
a = [0]*len(masks)
|
||||
for i in range(len(masks)):
|
||||
for p in masks[i].keys():
|
||||
if 0<x+p[0]<w and 0<y+p[1]<h:
|
||||
a[i] += PX[x+p[0],y+p[1]] * masks[i][p]
|
||||
if sum(masks[i].values())!=0:
|
||||
if 0 < x + p[0] < w and 0 < y + p[1] < h:
|
||||
a[i] += PX[x + p[0], y + p[1]] * masks[i][p]
|
||||
if sum(masks[i].values()) != 0:
|
||||
a[i] = a[i] / sum(masks[i].values())
|
||||
NPX[x,y]=int(sum([v**2 for v in a])**0.5)
|
||||
for x in range(0,w):
|
||||
for y in range(0,h):
|
||||
PX[x,y] = NPX[x,y]
|
||||
NPX[x,y] = int(sum([v**2 for v in a])**0.5)
|
||||
for x in range(0, w):
|
||||
for y in range(0, h):
|
||||
PX[x, y] = NPX[x, y]
|
||||
|
||||
|
||||
def distsum(*args):
|
||||
|
@ -71,8 +77,8 @@ def distsum(*args):
|
|||
"""
|
||||
dists = []
|
||||
for i in range(1, len(args):
|
||||
a = args[i][0]-args[i-1][0]
|
||||
b = args[i][1]-args[i-1][1]
|
||||
a = args[i][0] - args[i-1][0]
|
||||
b = args[i][1] - args[i-1][1]
|
||||
dist = (a**2 + b**2)**0.5
|
||||
dists.append(dist)
|
||||
return sum(dists)
|
||||
|
@ -83,14 +89,14 @@ def sortlines(lines):
|
|||
clines = lines[:]
|
||||
slines = [clines.pop(0)]
|
||||
while clines != []:
|
||||
x,s,r = None,1000000,False
|
||||
x, s, r = None, 1000000, False
|
||||
for l in clines:
|
||||
d = distsum(l[0],slines[-1][-1])
|
||||
dr = distsum(l[-1],slines[-1][-1])
|
||||
d = distsum(l[0], slines[-1][-1])
|
||||
dr = distsum(l[-1], slines[-1][-1])
|
||||
if d < s:
|
||||
x,s,r = l[:],d,False
|
||||
x, s, r = l[:], d, False
|
||||
if dr < s:
|
||||
x,s,r = l[:],s,True
|
||||
x, s, r = l[:], s, True
|
||||
|
||||
clines.remove(x)
|
||||
if r == True:
|
||||
|
@ -99,49 +105,48 @@ def sortlines(lines):
|
|||
return slines
|
||||
|
||||
|
||||
|
||||
def auto_canny(img, sigma=0.33):
|
||||
def auto_canny(image, sigma=0.33):
|
||||
"""
|
||||
Automatically determines appropriate upper and lower boundries for the Canny function.
|
||||
"""
|
||||
med = np.median(img)
|
||||
med = np.median(image)
|
||||
lower = int(max(0, (1.0 - sigma) * med))
|
||||
upper = int(min(255, (1.0 + sigma) * med))
|
||||
edges = cv2.Canny(img, lower, upper)
|
||||
edges = cv2.Canny(image, lower, upper)
|
||||
return edges
|
||||
|
||||
|
||||
def find_edges(IM):
|
||||
def find_edges(image):
|
||||
print("finding edges...")
|
||||
no_cv = True
|
||||
if no_cv:
|
||||
#appmask(IM,[F_Blur])
|
||||
appmask(IM,[F_SobelX,F_SobelY])
|
||||
#appmask(image, [F_Blur])
|
||||
appmask(image, [F_SobelX, F_SobelY])
|
||||
else:
|
||||
im = np.array(IM)
|
||||
im = cv2.GaussianBlur(im,(3,3),0)
|
||||
#im = cv2.Canny(im,100,200)
|
||||
im = auto_canny(im)
|
||||
IM = Image.fromarray(im)
|
||||
return IM.point(lambda p: p > 128 and 255)
|
||||
image = np.array(image)
|
||||
image = cv2.GaussianBlur(image, (3, 3), 0)
|
||||
#image = cv2.Canny(image,100,200)
|
||||
image = auto_canny(image)
|
||||
image = Image.fromarray(image)
|
||||
return image.point(lambda p: p > 128 and 255)
|
||||
|
||||
|
||||
def getdots(IM):
|
||||
def getdots(image):
|
||||
print("getting contour points...")
|
||||
PX = IM.load()
|
||||
PX = image.load()
|
||||
dots = []
|
||||
w,h = IM.size
|
||||
w, h = image.size
|
||||
for y in range(h-1):
|
||||
row = []
|
||||
for x in range(1,w):
|
||||
if PX[x,y] == 255:
|
||||
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)
|
||||
if x-row[-1][0] == row[-1][-1] + 1:
|
||||
row[-1] = (row[-1][0], row[-1][-1] + 1)
|
||||
else:
|
||||
row.append((x,0))
|
||||
row.append((x, 0))
|
||||
else:
|
||||
row.append((x,0))
|
||||
row.append((x, 0))
|
||||
dots.append(row)
|
||||
return dots
|
||||
|
||||
|
@ -150,110 +155,110 @@ def connectdots(dots):
|
|||
print("connecting contour points...")
|
||||
contours = []
|
||||
for y in range(len(dots)):
|
||||
for x,v in dots[y]:
|
||||
for x, v in dots[y]:
|
||||
if v > -1:
|
||||
if y == 0:
|
||||
contours.append([(x,y)])
|
||||
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)
|
||||
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)])
|
||||
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,))
|
||||
if contours[i][-1] == (closest, y-1):
|
||||
contours[i].append((x, y,))
|
||||
found = 1
|
||||
break
|
||||
if found == 0:
|
||||
contours.append([(x,y)])
|
||||
contours.append([(x, y)])
|
||||
for c in contours:
|
||||
if c[-1][1] < y-1 and len(c)<4:
|
||||
if c[-1][1] < y-1 and len(c) < 4:
|
||||
contours.remove(c)
|
||||
return contours
|
||||
|
||||
|
||||
def getcontours(IM,sc=2):
|
||||
def getcontours(image, 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)
|
||||
image = find_edges(image)
|
||||
image1 = IM.copy()
|
||||
image2 = image.rotate(-90, expand=True).transpose(Image.FLIP_LEFT_RIGHT)
|
||||
dots1 = getdots(image1)
|
||||
contours1 = connectdots(dots1)
|
||||
dots2 = getdots(IM2)
|
||||
dots2 = getdots(image2)
|
||||
contours2 = connectdots(dots2)
|
||||
|
||||
for i in range(len(contours2)):
|
||||
contours2[i] = [(c[1],c[0]) for c in contours2[i]]
|
||||
contours = contours1+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]
|
||||
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[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)):
|
||||
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),int(contours[i][j][1]+10)
|
||||
for i in range(0, len(contours)):
|
||||
for j in range(0, len(contours[i])):
|
||||
contours[i][j] = int(contours[i][j][0] + 10), int(contours[i][j][1] + 10)
|
||||
|
||||
return contours
|
||||
|
||||
|
||||
def hatch(IM,sc=16):
|
||||
def hatch(image, sc=16):
|
||||
print("hatching...")
|
||||
PX = IM.load()
|
||||
w,h = IM.size
|
||||
PX = image.load()
|
||||
w,h = image.size
|
||||
lg1 = []
|
||||
lg2 = []
|
||||
for x0 in range(w):
|
||||
for y0 in range(h):
|
||||
x = x0*sc
|
||||
y = y0*sc
|
||||
if PX[x0,y0] > 144:
|
||||
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)])
|
||||
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)])
|
||||
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])):
|
||||
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][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]
|
||||
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),int(lines[i][j][1]+sc)-j
|
||||
for i in range(0, len(lines)):
|
||||
for j in range(0, len(lines[i])):
|
||||
lines[i][j] = int(lines[i][j][0] + sc), int(lines[i][j][1] + sc) - j
|
||||
return lines
|
||||
|
||||
|
||||
|
@ -268,6 +273,7 @@ def sketch(path, export_path=None, resolution=1024, hatch_size=16, contour_simpl
|
|||
width = int(resolution/contour_simplify)
|
||||
height = int(resolution/contour_simplify*image.size[0]/image.size[1])
|
||||
lines += getcontours(image.resize((width, height)), contour_simplify)
|
||||
|
||||
if draw_hatch:
|
||||
width = int(resolution/hatch_size)
|
||||
height = int(resolution/hatch_size*image.size[0]/image.size[1])
|
||||
|
|
Loading…
Reference in New Issue
Block a user