import cv2
import numpy as np
from PIL import Image
import subprocess
import os
import sys

def vectorize_png(
    input_png,
    output_svg,
    blur_strength=15,
    threshold=180
):
    if not os.path.exists(input_png):
        raise FileNotFoundError(input_png)

    # Load image
    img = cv2.imread(input_png, cv2.IMREAD_COLOR)

    # Convert to grayscale
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    # Edge-preserving smoothing (strong but clean)
    smooth = cv2.bilateralFilter(
        gray,
        d=blur_strength,
        sigmaColor=75,
        sigmaSpace=75
    )

    # Optional extra smoothing
    smooth = cv2.GaussianBlur(smooth, (7, 7), 0)

    # High-contrast threshold
    _, bw = cv2.threshold(
        smooth,
        threshold,
        255,
        cv2.THRESH_BINARY
    )

    # Invert for Potrace (expects black foreground)
    bw = 255 - bw

    # Save temporary PBM
    temp_pbm = "temp.pbm"
    Image.fromarray(bw).save(temp_pbm)

    # Run Potrace
    subprocess.run([
        "potrace",
        temp_pbm,
        "-s",           # SVG output
        "-o", output_svg,
        "--turdsize", "2",
        "--alphamax", "1.0",
        "--opttolerance", "0.2"
    ], check=True)

    os.remove(temp_pbm)
    print(f"Vectorized SVG saved to: {output_svg}")

if __name__ == "__main__":
    if len(sys.argv) != 3:
        print("Usage: python vectorize.py input.png output.svg")
        sys.exit(1)

    vectorize_png(sys.argv[1], sys.argv[2])
Edit

Pub: 17 Dec 2025 13:45 UTC

Views: 25