Skip to content
Snippets Groups Projects
Commit 6492ca5a authored by Quentin Bolsee's avatar Quentin Bolsee
Browse files

intial commit

parent 1aad8f90
No related branches found
No related tags found
No related merge requests found
import math
import numpy as np
import cv2
import argparse
import os
def parse_arguments():
usage_text = (
"Converts an image into a dithered svg file."
)
parser = argparse.ArgumentParser(description=usage_text)
parser.add_argument("-i", "--input", type=str,
help="Input filename.")
parser.add_argument("-o", "--output", type=str, default="",
help="Output filename (default: <filename_in>_dither.svg).")
parser.add_argument("--invert", action="store_true",
help="Output white dots on a black background.")
parser.add_argument("-n", "--number", type=int, default=100,
help="Number of dots horizontally (default=100).")
parser.add_argument("-a", type=float, default=0.1,
help="small diameter 0-1 (default:0.1).")
parser.add_argument("-b", type=float, default=0.82,
help="large diameter 0-1 (default:0.82).")
return parser.parse_known_args()
def int_constrain(a, a_min, a_max):
return np.clip(a.astype(np.int32), a_min, a_max)
def rescale(a, a_min, a_max):
a_min_obs = np.min(a)
a_max_obs = np.max(a)
a_norm = (a - a_min_obs) / (a_max_obs - a_min_obs)
return a_min + a_norm * (a_max - a_min)
def write_svg(filename, x, y, r, invert=False):
x_max = int(np.max(x))
y_max = int(np.max(y))
with open(filename, "w") as f:
if invert:
col_back = "black"
col_front = "white"
else:
col_back = "white"
col_front = "black"
f.write(f'<svg width="{x_max}" height="{y_max}" '
f'xmlns="http://www.w3.org/2000/svg" '
f'style="background-color:{col_back}">\n')
for xi, yi, ri in zip(x, y, r):
f.write(f'\t<circle cx="{xi:.2f}" cy="{yi:.2f}" r="{ri:.2f}" fill="{col_front}"/>\n')
f.write('</svg>\n')
def main():
args, _ = parse_arguments()
filename_in = args.input
if args.output == "":
filename_out = os.path.splitext(filename_in)[0] + f"_dither.svg"
else:
filename_out = args.output
img = cv2.imread(filename_in, cv2.IMREAD_UNCHANGED)
if len(img.shape) == 3:
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
f = math.sqrt(3) / 2
h, w = img.shape
n_x = args.number
n_y = int((1/f) * n_x * h / w)
d_x = w / n_x
d_y = d_x * f
img_blur = cv2.blur(img, (int(d_x), int(d_x)))
x = d_x * np.arange(n_x)
y = d_y * np.arange(n_y)
xx, yy = np.meshgrid(x, y)
xx[1::2, :] += d_x / 2
xx_f = xx.flatten()
yy_f = yy.flatten()
xx_f_samp = int_constrain(xx.flatten(), 0, w - 1)
yy_f_samp = int_constrain(yy.flatten(), 0, h - 1)
r_max = args.a*d_x/2
r_min = args.b*d_x/2
r_f = rescale(img_blur[yy_f_samp, xx_f_samp], r_min, r_max)
write_svg(filename_out, xx_f, yy_f, r_f, invert=args.invert)
if __name__ == "__main__":
main()
examples/cat.png

115 KiB

Source diff could not be displayed: it is too large. Options to address this: view the blob.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment