I would like to convert a basic SVG file containing polylines into the stroke-3 format used by sketch-rnn (and the quickdraw dataset).
To my understanding, each polyline point in stroke-3 format would be:
- stored as
[delta_x, delta_y, pen_up], where delta_x,delta_yrepresent the coordinates relative to the previous point andpen_upis a bit that is 1 when the pen is up (e.g.move_tooperation a-la turtle graphics) or 0 when the pen is down (e.g.line_tooperation a-la turtle graphics).
I've attempted to write the function and convert an SVG, but I when I render a test of the stroke-3 format I get an extra line.
My input SVG looks like this:
<?xml version="1.0" encoding="UTF-8"?><svg viewBox="0 0 900 900" xmlns="http://www.w3.org/2000/svg"><g fill="none" stroke="#00c000" stroke-linecap="round"><path d="m324.56 326.77h62.721 62.721 62.721 62.721"/><path d="m575.44 326.77 0.1772 62.891 0.1771 62.891 0.1772 62.891 0.1771 62.891"/><path d="m576.15 578.33h-63.075-63.075l-63.075-1e-4h-63.075"/><path d="m323.85 578.33 0.1772-62.891 0.1772-62.891 0.1772-62.891 0.1771-62.891"/><path d="m575.44 326.77 29.765-32.469 29.765-32.469" stroke="#c00000"/><path d="m634.97 261.83h-92.486-92.486l-92.486-1e-4h-92.486" stroke="#c00000"/><path d="m265.03 261.83 44.647 48.704 14.882 16.235" stroke="#c00000"/><path d="m323.85 578.33-15.092 13.725-30.183 27.45-15.092 13.725" stroke="#c0c000"/><path d="m263.48 633.23h93.258 93.258l93.258 1e-4h93.258" stroke="#c0c000"/><path d="m636.52 633.23-60.366-54.9" stroke="#c0c000"/><path d="m634.97 261.83 0.3863 92.851 0.3862 92.851 0.3863 92.851 0.3863 92.851" stroke="#0000c0"/><path d="m636.52 633.23h-93.258l-93.258-1e-4h-93.258-93.258" stroke="#0000c0"/><path d="m263.48 633.23 0.3863-92.851 0.3863-92.851 0.3863-92.851 0.3862-92.851" stroke="#0000c0"/></g></svg>Here is a visualisation where the lines parsed from the SVG file are rendered in thick green and the lines drawn from the converted stroke-3 format are rendered in thinner red: 
Notice the diagonal line on the right hand side face which isn't present in the original SVG.
I must be doing something wrong marking a line operation instead of a move operation somewhere, but I've been staring at the code for so long I can't spot the error.
This is a minimal example showing my attempt using svg.path:
import xml.etree.ElementTree as ET
import numpy as np
from svg.path import parse_path
from svg.path.path import Line, Move
cubeSVG = '<?xml version="1.0" encoding="UTF-8"?><svg viewBox="0 0 900 900" xmlns="http://www.w3.org/2000/svg"><g fill="none" stroke="#00c000" stroke-linecap="round"><path d="m324.56 326.77h62.721 62.721 62.721 62.721"/><path d="m575.44 326.77 0.1772 62.891 0.1771 62.891 0.1772 62.891 0.1771 62.891"/><path d="m576.15 578.33h-63.075-63.075l-63.075-1e-4h-63.075"/><path d="m323.85 578.33 0.1772-62.891 0.1772-62.891 0.1772-62.891 0.1771-62.891"/><path d="m575.44 326.77 29.765-32.469 29.765-32.469" stroke="#c00000"/><path d="m634.97 261.83h-92.486-92.486l-92.486-1e-4h-92.486" stroke="#c00000"/><path d="m265.03 261.83 44.647 48.704 14.882 16.235" stroke="#c00000"/><path d="m323.85 578.33-15.092 13.725-30.183 27.45-15.092 13.725" stroke="#c0c000"/><path d="m263.48 633.23h93.258 93.258l93.258 1e-4h93.258" stroke="#c0c000"/><path d="m636.52 633.23-60.366-54.9" stroke="#c0c000"/><path d="m634.97 261.83 0.3863 92.851 0.3862 92.851 0.3863 92.851 0.3863 92.851" stroke="#0000c0"/><path d="m636.52 633.23h-93.258l-93.258-1e-4h-93.258-93.258" stroke="#0000c0"/><path d="m263.48 633.23 0.3863-92.851 0.3863-92.851 0.3863-92.851 0.3862-92.851" stroke="#0000c0"/></g></svg>'
def svg_to_stroke3(svg_string):
# parse the doc
doc = ET.fromstring(svg_string)
# get paths
paths = doc.findall('.//{http://www.w3.org/2000/svg}path')
strokes = []
# previous x, y
px, py = 0, 0
for path_index, path in enumerate(paths):
stroke = parse_path(path.attrib['d'])
was_moving = False
for operation_index, operation in enumerate(stroke):
if isinstance(operation, Move):
mx = int(operation.start.real)
my = int(operation.start.imag)
# prep this end point for check as next line first point
was_moving = True
strokes.append([mx-px, my-py, 1])
# update previous (absolute) coordinates
px = mx
py = my
if isinstance(operation, Line):
sx = int(operation.start.real)
sy = int(operation.start.imag)
ex = int(operation.end.real)
ey = int(operation.end.imag)
if was_moving:
# append delta x, y relative to previous move operation
strokes.append([sx-px, sy-py, 0])
was_moving = False
# append delta x,y (line end relative to line start)
strokes.append([ex-sx, ey-sy, 0])
# update previous (absolute) coordinates
px = ex
py = ey
# update previous end point
strokes_np = np.array(strokes, dtype=np.int16)
return strokes_np
print(svg_to_stroke3(cubeSVG))
Additionally I've made the above available as an easy to run Google Colab Notebook.
from How to convert SVG polylines to quickdraw stroke-3 numpy format?

No comments:
Post a Comment