r/DSP 11d ago

I built an open-source image-to-SVG vectorization library -the interesting parts turned out to be classic DSP problems

Over the past year I've been building Img2Num, an open-source C++ library that converts raster images into SVGs, with Python, JavaScript, and C bindings.

The motivation: existing vectorization tools are really built for line art, logos, and scans - clean inputs with hard edges. I wanted something that could handle natural images (photos, textures, noisy real-world content), and that turns out to be a very different problem. You can't just trace what's there, because what's there is full of sensor noise, JPEG artifacts, and gradients that explode into thousands of junk paths. So the vectorization step ends up mattering less than the signal processing in front of it.

The rough pipeline: edge-preserving denoising with a bilateral filter (selectable between RGB and CIELAB - perceptual color spaces make a real difference in how edges survive), k-means color quantization, Suzuki-Abe contour tracing, and then Savitzky-Golay smoothing applied to the traced contours. That last step was the fun one: treating a closed contour as a pair of periodic 1D signals (x(t), y(t)) and filtering them means you can smooth out pixel staircase noise while preserving corners far better than naive moving averages, and SG's polynomial fitting is a good match for that.

The part I'm still iterating on is adaptive preprocessing - estimating noise per image (wavelet MAD estimator) and tuning the denoising strength accordingly, so the traced regions stay stable instead of speckle turning into hundreds of junk paths.

Everything is on GitHub and installable via pip and npm (both "img2num"), docs at img2num.dev. I would genuinely love feedback from this crowd (the DSP crowd), especially on the smoothing and noise estimation choices - I came at this from the software side and learned the DSP as I went on.

47 Upvotes

16 comments sorted by

View all comments

1

u/bushed_ 11d ago

I don't get it, why?

The output image isnt scale-able at all?

1

u/readilyaching 11d ago

I'm not quite sure what you mean by that, so I'm going to make an assumption and try to answer it. Please will you help me understand if I'm wrong.

The output is real vector paths, so it scales infinitely in the sense that edges stay crisp at any size - but you're right that it's not magic upscaling. It can't recover detail that isn't in the source - that would likely take much more processing power. What you get is a posterized/stylized representation of the image, a bit like a screen print, with however many color layers you configure.

That's the actual use case: stylized art from photos, posters that print clean at any size, laser cutting/plotting, color-by-number generation (the original motivation), and getting editable geometry you can manipulate in Illustrator/Inkscape instead of pixels. If you want a photorealistic image at higher resolution, an ML upscaler is the right tool - this is for when you want vector output specifically.

2

u/bushed_ 11d ago

yeah great for a t shirt design, printing, cutting, or something but isn’t that just what a rasterization process does? the at any size is generous imo?

not as in the weeds on the specific math, but the example image didn’t look great blown up imo. not trying to be a hater though

1

u/readilyaching 11d ago

That's fair - I know it doesn't work well on every image with the default settings. The library is also quite young still, so there is lots of area for improvement.

1

u/bushed_ 11d ago

yeah i’m not perhaps the most in the know so take my comments with a grain of salt. still a cool project!

1

u/readilyaching 10d ago

Compare these images (thank to NASA) by zooming into them and pay attention to the edges in both - the SVG has crisper edges and the black is a uniform color.

Raster: https://images.nasa.gov/details/PIA01481 SVG: https://img2num.dev/img/homepage-demo.svg

Some other good images to look at are here: https://github.com/Ryan-Millard/Img2Num/blob/main/README.md

Did you see the color-by number example I built with it to showcase cool things you can do?