Convert images to pencil sketches and extract contour paths for pen plotters and generative art.
Project description
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 |
|---|---|---|---|
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
- opencv-python >= 4.8
- numpy >= 1.24
- Pillow >= 10.0
License
MIT. See LICENSE for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file img2sktch-0.1.0.tar.gz.
File metadata
- Download URL: img2sktch-0.1.0.tar.gz
- Upload date:
- Size: 14.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
195c01ff49aff9a401b2f9846b1b9560ceaaef682cc3e90fd6f11ca4b26b45be
|
|
| MD5 |
b31a95aa4a4e4876a1c68eb22541e865
|
|
| BLAKE2b-256 |
accaac7b2b66ac93da761c16cf73f9d4f314cda35dc98ff7e95522c61f7401fd
|
File details
Details for the file img2sktch-0.1.0-py3-none-any.whl.
File metadata
- Download URL: img2sktch-0.1.0-py3-none-any.whl
- Upload date:
- Size: 13.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
560efbf1dffb43aabaf2459a2922b316e6bc49c472da1177d08a2cf82ec6509c
|
|
| MD5 |
5c92b5d7301f2ae17c594e04fcc4e24c
|
|
| BLAKE2b-256 |
3a600384b723f63a0e5d8de72cb4a412ed4572f6f9631075fe1bf3b17c6c8b02
|