Camera-based precision alignment for laser engraving with sub-millimeter accuracy
LightBurn Auto-Align eliminates manual positioning by using ArUco markers and computer vision to automatically align designs with physical materials. Place your item in a jig, take a photo, and the system calculates exact positioning for LightBurn.
- ArUco marker-based alignment - Sub-mm precision using computer vision
- Camera calibration - Corrects for lens distortion
- Homography mapping - Accurate pixel-to-millimeter coordinate transformation
- LightBurn integration - Direct UDP communication to load and start jobs
- Complete workflow - From camera capture to engraving in seconds
pip3 install -r requirements.txtpython3 generate_markers.pyThis creates markers/aruco_board.pdf. Print at 100% scale and mount markers on a flat jig at the exact positions shown.
# Generate calibration pattern
python3 calibrate.py generate
# Capture calibration images
python3 calibrate.py capture --num-images 20
# Run calibration
python3 calibrate.py calibrate calibration_images/*.jpg# With text design
python3 align_tool.py --text "Hello" --rect 50 50 100 30 --send
# With image design
python3 align_tool.py --design logo.png --rect 60 60 80 80 --sendArguments:
--rect X Y WIDTH HEIGHT- Design position and size in millimetersX, Y- Position from bottom-left corner (0,0)WIDTH, HEIGHT- Design dimensions
--text "TEXT"- Create text design--design FILE- Use image file (PNG)--send- Send to LightBurn automatically--start- Auto-start job (requires--send)
| Module | Purpose |
|---|---|
align_tool.py |
Main CLI - complete workflow |
aruco_align.py |
ArUco detection and homography |
design_warp.py |
Design warping and export |
lightburn_udp.py |
LightBurn UDP communication |
calibrate.py |
Camera calibration tool |
generate_markers.py |
Marker board generator |
test_alignment.py |
Test suite |
config/jigs/default.json- Marker positions for your jigconfig/camera.yml- Camera calibration data (optional)
# Default 200x200mm board with 40mm markers
python3 generate_markers.py
# Custom size
python3 generate_markers.py --size 150 --marker-size 30# Step 1: Generate chessboard pattern
python3 calibrate.py generate
# Step 2: Capture images (move chessboard to different positions/angles)
python3 calibrate.py capture --num-images 20
# Step 3: Calculate calibration
python3 calibrate.py calibrate calibration_images/*.jpgCalibration corrects lens distortion for higher accuracy.
# Detect markers and calculate alignment
python3 aruco_align.py camera_snapshot.jpg --design 50 50 100 80
# Without camera calibration
python3 aruco_align.py camera_snapshot.jpg --camera-calib ""This creates:
camera_snapshot_aligned.jpg- Visualization showing detected markers- Alignment data (printed to console)
# Export aligned design
python3 design_warp.py alignment_data.json --text "TEST" --output output/design.png
# With custom DPI
python3 design_warp.py alignment_data.json --design logo.png --dpi 600 --format svg# Check if LightBurn is running
python3 lightburn_udp.py ping
# Load file
python3 lightburn_udp.py load output/design.png
# Load and start
python3 lightburn_udp.py load output/design.png --startNote: Enable UDP in LightBurn: Edit → Device Settings → Enable UDP
python3 align_tool.py \
--text "Serial #12345" \
--rect 70 70 60 20 \
--send --start- Opens camera to capture jig photo (press SPACE)
- Detects markers and calculates position
- Creates text design at 70,70 (60x20mm)
- Exports aligned PNG
- Sends to LightBurn and starts job
python3 align_tool.py \
--camera-image snapshot.jpg \
--design company_logo.png \
--rect 50 50 100 100 \
--format svgUses existing camera image instead of capturing new one.
# Capture once
python3 align_tool.py --camera-image jig.jpg --text "Item 1" --rect 30 30 50 30
python3 align_tool.py --camera-image jig.jpg --text "Item 2" --rect 30 80 50 30
python3 align_tool.py --camera-image jig.jpg --text "Item 3" --rect 30 130 50 30Reuse the same camera image for batch positioning.
Origin (0,0) is at BOTTOM-LEFT of engraving area
(0,200) Y ↑ (200,200)
┌────────────────────┐
│ │
│ Engraving Area │
│ │
└────────────────────┘ → X
(0,0) (200,0)
All measurements in millimeters.
Run the test suite to verify everything works:
python3 test_alignment.pyThis creates a synthetic test image with ArUco markers and validates:
- Marker detection
- Homography calculation
- Alignment workflow
- Design export
Expected output: 4/4 tests passed
-
Overhead camera - USB webcam mounted above laser bed
- Rigidly mounted to avoid movement
- Sufficient resolution (1080p+ recommended)
- Even lighting (avoid glare)
-
Flat jig - Base platform with mounted ArUco markers
- Print
markers/aruco_board.pdfat 100% scale - Mount markers at exact positions shown
- Ensure jig is flat and stable
- Print
- Mount camera 300-500mm above bed
- Use diffuse LED lighting
- Place camera directly above center of engraving area
- Secure jig to laser bed (tape, magnets, or clamps)
Expected accuracy with proper calibration:
- Position: ±0.5mm
- Rotation: ±0.5°
- Size: ±1% of design dimensions
Factors affecting accuracy:
- Camera calibration quality
- Marker print precision
- Jig stability
- Lighting conditions
- Camera resolution
- Ensure markers are clearly visible in camera view
- Check lighting (avoid glare on markers)
- Verify markers printed at correct size
- Try adjusting camera position/angle
- Run camera calibration (
calibrate.py) - Verify marker positions match configuration
- Check jig is flat and stable
- Ensure markers are printed at 100% scale
- Enable UDP in LightBurn:
Edit → Device Settings → Enable UDP - Check LightBurn is running
- Try:
python3 lightburn_udp.py ping
- Verify DPI settings:
Edit → Settings → File Settings → SVG Import DPI - Set to match export DPI (default: 300)
- Try PNG export instead of SVG
lightburn-auto-align/
├── align_tool.py # Main workflow CLI
├── aruco_align.py # ArUco detection & alignment
├── design_warp.py # Design warping & export
├── lightburn_udp.py # LightBurn UDP interface
├── calibrate.py # Camera calibration
├── generate_markers.py # Marker board generator
├── test_alignment.py # Test suite
├── requirements.txt # Python dependencies
├── README.md # This file
├── RESEARCH.md # Technical research notes
├── config/
│ ├── camera.yml # Camera calibration (created by calibrate.py)
│ └── jigs/
│ └── default.json # Jig configuration
├── markers/
│ ├── aruco_board.pdf # Printable marker board
│ └── aruco_board.png # Preview image
├── calibration/
│ └── calibration_chessboard.pdf # Camera calibration pattern
├── output/ # Exported designs
└── test_output/ # Test results
- Dictionary: DICT_4X4_50
- Marker IDs: 0, 1, 2, 3 (corners)
- Detection: OpenCV ArUco module
- Pose estimation: Sub-pixel corner detection
- Algorithm: RANSAC-based homography calculation
- Transform: Maps millimeter coordinates → pixel coordinates
- Accuracy: Sub-pixel precision with 4+ markers
- PNG: Raster image with embedded DPI metadata
- SVG: Vector format with embedded raster image
- Port: 19840 (fixed, not configurable)
- Reply Port: 19841
- Commands: PING, STATUS, LOADFILE, START, CLOSE
Create multiple jig configs for different setups:
# Create custom jig
python3 generate_markers.py --size 300 --output-dir markers/large
# Use custom jig
python3 align_tool.py --jig-config config/jigs/custom.json ...from align_tool import AlignmentWorkflow
workflow = AlignmentWorkflow()
designs = [
("Item A", (30, 30, 50, 30)),
("Item B", (30, 80, 50, 30)),
("Item C", (30, 130, 50, 30)),
]
for text, rect in designs:
workflow.run_complete_workflow(
design_rect_mm=rect,
text=text,
camera_image_path="jig.jpg",
send_to_lb=True
)- Python 3.7+
- OpenCV 4.8+ (with contrib modules)
- NumPy 1.24+
- Pillow 10.0+
- USB webcam
- LightBurn software
This is a personal project for laser engraving automation. Feel free to fork and adapt for your own setup.
This project is provided as-is for personal and educational use.
Created: October 18, 2025 Status: ✓ Complete - Production Ready Version: 1.0.0