Skip to main content

img2sktch

img2sktch is a Python library for converting images to pencil sketches and extracting contour paths. It grew out of a hardware pen plotter project and works equally well for generative art, image preprocessing, and anywhere you want a clean line representation of a photo.

"if a non-stochastic data-less approach can be taken to solving a problem, then machine learning should never be applied."


Installation

pip install img2sktch

For development:

git clone https://github.com/NacreousDawn596/img2sktch
cd img2sktch
pip install -e ".[dev]"

Quick start

import img2sktch as i2s

# Load from file, bytes, PIL, or numpy — all work the same way
frame = i2s.from_file("photo.jpg")

# Apply a pencil sketch
sketch = i2s.PencilSketch(blur_sigma=21)(frame)

# Save
i2s.to_file(sketch, "sketch.png")

Examples

Original Pencil Edge Hatch
Original Pencil Edge Hatch

Sketch modes

PencilSketch

Classic dodge-blend effect. Works by blurring the inverted grayscale image and blending it back with the original using a color-dodge formula.

from img2sktch import PencilSketch

sketch = PencilSketch(
    blur_sigma=21,       # gaussian blur strength on the inverted image
    sharpen_value=None,  # optional int to apply an unsharp kernel after dodge
)(frame)

EdgeSketch

Canny edge detection, inverted so you get black lines on white.

from img2sktch import EdgeSketch

sketch = EdgeSketch(
    threshold1=1,
    threshold2=81,
    blur_ksize=9,
    invert=True,
)(frame)

HatchSketch

Hatching lines overlaid on shadow regions, inspired by pen-and-ink illustration.

from img2sktch import HatchSketch

sketch = HatchSketch(
    num_directions=4,   # number of hatch angles
    spacing=6,          # pixels between lines
    angle_offset=0.0,
    blur_sigma=3,
)(frame)

I/O helpers

The library accepts and returns images in whatever format you have them in.

import img2sktch as i2s
from PIL import Image
import io

# From file path
frame = i2s.from_file("photo.jpg")

# From raw bytes (e.g. received over a network or from an upload)
with open("photo.jpg", "rb") as f:
    frame = i2s.from_bytes(f.read())

# From a file-like object (BytesIO, requests.Response.raw, etc.)
buf = io.BytesIO(open("photo.jpg", "rb").read())
frame = i2s.from_bytes(buf)

# From a PIL Image
pil_img = Image.open("photo.jpg")
frame = i2s.from_pil(pil_img)

# From a numpy array (grayscale or BGRA are handled automatically)
frame = i2s.from_numpy(some_array)

Saving is symmetric:

# To file
i2s.to_file(sketch, "out.png")
i2s.to_file(sketch, "out.jpg", quality=90)

# To raw bytes (for serving over HTTP, saving to a database, etc.)
raw = i2s.to_bytes(sketch, fmt=".png")
raw = i2s.to_bytes(sketch, fmt=".jpg", quality=85)

# To a BytesIO buffer
buf = i2s.to_bytesio(sketch, fmt=".png")  # returns io.BytesIO, cursor at 0

# To a PIL Image
pil = i2s.to_pil(sketch)

Contour extraction

Extract simplified polylines from a sketch image. Useful for pen plotters, laser cutters, or anywhere that needs vector paths rather than raster output.

from img2sktch import PencilSketch, image_to_contours

sketch = PencilSketch()(frame)
contours = image_to_contours(
    sketch,
    simplification=1.0,    # epsilon as % of arc length; 0 = no simplification
    canny_threshold1=50,
    canny_threshold2=150,
    pen_diameter=2.0,
    max_width=2000,
    multiplier=4.5,
    min_area=10.0,
)
# contours is a list of [(x, y), ...] polylines, centered on the origin

Export to SVG

from img2sktch import contours_to_svg

svg = contours_to_svg(contours, width=800, height=800, stroke="black", stroke_width=1.0)
with open("sketch.svg", "w") as f:
    f.write(svg)

Export to Arduino (.ino)

Generate ready-to-flash Arduino code for a 3-motor pen plotter:

from img2sktch.contours import contours_to_arduino

code = contours_to_arduino(contours, scale=1.0, offset_x=0, offset_y=0)
with open("drawing.ino", "w") as f:
    f.write(code)

Image transforms

from img2sktch.transform import resize, crop_center, pad_to_square, rotate, auto_contrast

# Resize — aspect-ratio preserved if only one dimension given
small = resize(frame, width=800)
small = resize(frame, scale=0.5)

# Crop the center 512x512 pixels
cropped = crop_center(frame, 512, 512)

# Pad to square with white fill
square = pad_to_square(frame, fill=255)

# Rotate 30 degrees, canvas expands to fit
rotated = rotate(frame, angle=30, expand=True, fill=255)

# Stretch contrast to full range
enhanced = auto_contrast(frame)

Command-line interface

A img2sktch command is installed alongside the package.

# Apply a pencil sketch
img2sktch sketch photo.jpg out.png --mode pencil --blur-sigma 21

# Apply edge sketch, resize first
img2sktch sketch photo.jpg out.png --mode edge --width 1024

# Hatch sketch
img2sktch sketch photo.jpg out.png --mode hatch --hatch-directions 4 --hatch-spacing 8

# Extract contours and export as SVG
img2sktch contours photo.jpg sketch.svg --simplification 1.0

# Extract contours and generate Arduino code
img2sktch contours photo.jpg drawing.ino --max-width 2200 --multiplier 6

# Pipe image bytes from stdin
cat photo.jpg | img2sktch sketch - out.png

Project structure

img2sktch/
    img2sktch/
        __init__.py     # public API
        sketch.py       # PencilSketch, EdgeSketch, HatchSketch
        contours.py     # image_to_contours, contours_to_svg, contours_to_arduino
        transform.py    # resize, crop_center, pad_to_square, rotate, auto_contrast
        io.py           # from_file, from_bytes, from_pil, to_file, to_bytes, to_pil, ...
        cli.py          # CLI entry point
    pyproject.toml
    LICENSE
    README.md

Dependencies


License

MIT. See LICENSE for details.

Metadata

Release files for img2sktch 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for img2sktch 0.1.0
File Size Uploaded
img2sktch-0.1.0.tar.gz 14.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for img2sktch 0.1.0
File Interpreter ABI Platform
img2sktch-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 27.7 kB

Release files / img2sktch-0.1.0.tar.gz

Download URL img2sktch-0.1.0.tar.gz
Size 14.3 kB
Tags Source
SHA-256 checksum
How to use checksums
195c01ff49aff9a401b2f9846b1b9560ceaaef682cc3e90fd6f11ca4b26b45be
BLAKE2b-256 checksum
How to use checksums
accaac7b2b66ac93da761c16cf73f9d4f314cda35dc98ff7e95522c61f7401fd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.5

Release files / img2sktch-0.1.0-py3-none-any.whl

Download URL img2sktch-0.1.0-py3-none-any.whl
Size 13.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
560efbf1dffb43aabaf2459a2922b316e6bc49c472da1177d08a2cf82ec6509c
BLAKE2b-256 checksum
How to use checksums
3a600384b723f63a0e5d8de72cb4a412ed4572f6f9631075fe1bf3b17c6c8b02
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.5

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page