Skip to main content

Gridfinity Pic-to-Bin

Generate 3D-printable gridfinity bins with custom tool cutouts from phone camera photos.

A printed ArUco marker template handles perspective correction and automatic scale calibration. The rest of the pipeline — SAM2 segmentation, vectorization, layout packing, and Fusion 360 bin generation — runs automatically.

Contents


Quick start

  1. Install the pipelinepip install gridfinity-pic-to-bin. Optionally add the web app for a browser UI and the Fusion 360 add-in for the 3D model.
  2. Print the ArUco templategenerate-phone-template --paper-size letter. One-time setup; print at exactly 100% scale, no fit-to-page.
  3. Photograph the tool on the template — lay the tool in the dotted zone, shoot from above with all 8 markers in frame, and measure the tool's depth with calipers.
  4. Run the pipelinepic-to-bin photo.jpg --tool-height 17. Produces bin_config.json, a combined DXF, and 1:1 fit-test printouts you can lay the real tool on before printing.
  5. Build the bin in Fusion 360 — click Solid → Create → Gridfinity Pic-to-Bin, then export STL or STEP and slice it.

Prefer a browser to a terminal? pic-to-bin-web replaces step 4 with drag-and-drop upload, live progress, and a layout preview — see Web app.


Installation

Three pieces. Only the first is required.

# What Command
1 The core code — the pipeline that turns photos into a bin config pip install gridfinity-pic-to-bin
2 The web app (optional) — browser frontend over the same pipeline pip install "gridfinity-pic-to-bin[web]"
3 The Fusion 360 add-in (optional) — turns the bin config into a solid model pic-to-bin-fusion install

The [web] extra is a superset, so #2 on its own also installs #1. #3 is a command from #1 that copies files into Fusion 360's add-ins folder; it needs Fusion 360 itself already installed.

Run these from a dedicated working folder — see Where to run these commands. A virtual environment is optional but recommended; see Virtual environments.

1. The core code (required)

pip install gridfinity-pic-to-bin

Everything that actually does the work: ArUco template generation, photo preprocessing (marker detection, perspective correction, scale calibration), SAM2 segmentation and vectorization, layout packing, the Fusion 360 config writer, and the add-in installer.

Install it if you are happy driving the pipeline from a terminal. It is also the base for both other pieces, so there is no way to skip it.

It gives you these commands:

Command Purpose
pic-to-bin Run the whole pipeline: photos → bin_config.json
generate-phone-template Make the printable ArUco template PDF
preprocess-phone Photo → rectified, scale-calibrated image
trace-tool Rectified image → tool outline DXF/SVG
layout-tools Pack tool DXFs into one bin footprint
prepare-bin Combined layout → Fusion 360 config JSON
pic-to-bin-fusion Install/uninstall the Fusion 360 add-in

Dependencies (installed automatically): ultralytics (SAM2), opencv-python, numpy, ezdxf, potracer, pyclipper, matplotlib, Pillow, pillow-heif.

2. The web app (optional)

pip install "gridfinity-pic-to-bin[web]"
pic-to-bin-web --port 8000          # http://localhost:8000

A FastAPI server plus a Lit frontend layered on top of the core code. It does not reimplement the pipeline — it calls the same run_pipeline() the CLI calls. What it adds is the interaction layer: drag-and-drop photo upload, live step-by-step progress streamed over SSE, an in-browser layout preview with printable fit-test downloads, a cheap Re-do loop that re-packs the layout without re-tracing, and one-click downloads of the DXF/PDF/JSON.

Install it if:

  • You want a GUI instead of memorizing CLI flags.
  • You want to review the layout preview and tweak parameters interactively before committing to a 3D print.
  • You want to serve other people. The web app is multi-user by design: per-job UUID directories, a GPU semaphore so concurrent jobs queue instead of fighting over SAM2, and a TTL sweep for old jobs.

Extra dependencies pulled in by [web]: fastapi, uvicorn[standard], python-multipart, sse-starlette, anthropic, python-dotenv.

See Web app below for usage, and pic_to_bin/web/README.md for hosting it behind a public reverse proxy.

3. The Fusion 360 add-in (optional)

pic-to-bin-fusion install

Copies the bundled add-in into Fusion 360's own add-ins directory (%APPDATA%\Autodesk\Autodesk Fusion 360\API\AddIns\pic_to_bin\ on Windows, ~/Library/Application Support/Autodesk/Autodesk Fusion 360/API/AddIns/pic_to_bin/ on macOS). Nothing is installed into Fusion 360 itself — you need Fusion already installed, and it only runs on Windows and macOS.

Once enabled inside Fusion, a Gridfinity Pic-to-Bin button appears under Solid → Create. Clicking it reads a bin_config.json and builds the whole parametric bin — body, stacking lip, deck, tool pockets, finger slots, and gridfinity base pads — in a fresh document, with optional STL/STEP/PNG export.

Install it if you want the finished 3D model. Steps #1 and #2 stop at bin_config.json plus DXF/PDF files; this is the piece that turns those into printable geometry. Skip it if you only want the 1:1 fit-test printouts, or if you plan to import the DXF into some other CAD package yourself.

The command is idempotent — re-run it after upgrading the package to refresh the installed copy. pic-to-bin-fusion uninstall removes it.

See Fusion 360 integration below for enabling the add-in inside Fusion and what gets built.

Where to run these commands

pip install does not care which directory you are in — but three things that come after it do, so it is worth setting up one working folder now and running everything from there:

  • pic-to-bin writes its results to generated/ relative to the current directory, and with no image arguments it processes every PNG/JPG in the current directory.
  • pic-to-bin-web creates its web_jobs/ directory in the current directory.
  • Ultralytics downloads the SAM2 weights (sam2.1_l.pt, several hundred MB) on the first trace, into the directory you ran from.

So: make a dedicated folder in your home directory and run every command from there. The two venv lines below are optional — see Virtual environments for why you'd want one.

Windows — PowerShell, not "Run as Administrator":

mkdir $HOME\pic-to-bin
cd $HOME\pic-to-bin
py -m venv .venv                  # optional
.\.venv\Scripts\Activate.ps1      # optional
pip install "gridfinity-pic-to-bin[web]"

$HOME\pic-to-bin resolves to C:\Users\<you>\pic-to-bin. If Activate.ps1 is blocked by execution policy, run Set-ExecutionPolicy -Scope CurrentUser RemoteSigned once, then retry.

macOS — Terminal:

mkdir -p ~/pic-to-bin
cd ~/pic-to-bin
python3 -m venv .venv             # optional
source .venv/bin/activate         # optional
pip install "gridfinity-pic-to-bin[web]"

Every later session, cd back to that folder before running pic-to-bin — and, if you made a venv, re-activate it first (.\.venv\Scripts\Activate.ps1 on Windows, source .venv/bin/activate on macOS).

Locations to avoid on both platforms:

Avoid Why
Windows Desktop/Documents while OneDrive backup is on; macOS Desktop/Documents while iCloud "Desktop & Documents Folders" is on Sync fights the multi-hundred-MB SAM2 weights and the per-job output folders, and cloud-only eviction can make files disappear mid-run
C:\Program Files, /Applications, /usr/local/lib Require admin rights; pip should never be writing there
sudo pip install … Never needed, and it can break OS tooling that depends on the system Python
Deeply nested Windows paths Some tooling still trips over the 260-character MAX_PATH limit

pic-to-bin-fusion install is the one exception to the working-folder rule: it copies files into Fusion 360's own add-ins directory, so it can be run from anywhere.

Virtual environments (optional)

A virtual environment is a private folder of Python packages that belongs to one project instead of the whole machine. It is optional. If this is the only Python project on your computer, pip install gridfinity-pic-to-bin into your normal Python works fine.

Reasons to use one anyway:

  • This package is heavy. ultralytics pulls in PyTorch and torchvision — a couple of GB — and ultralytics, opencv-python and matplotlib each constrain the numpy version. Installed machine-wide, that can break an unrelated project that wanted a different numpy or torch build.
  • Some Pythons refuse the machine-wide install. Homebrew Python on macOS and most Linux distro Pythons mark themselves "externally managed" (PEP 668) and reject pip install outside a venv with error: externally-managed-environment. Windows python.org installs have no such restriction.
  • Clean uninstall. Deleting the .venv folder removes every one of the ~100 transitive dependencies at once. Undoing a machine-wide install means chasing them individually.
  • Reproducibility. You can throw the venv away and rebuild it if an upgrade goes sideways, without touching anything else.

Setting one up is the two lines already shown above. For the details:

From source

Clone wherever you normally keep code — C:\Users\<you>\source\ on Windows, ~/src on macOS — again avoiding cloud-synced folders:

git clone https://github.com/justinhardin/gridfinity-pic-to-bin.git
cd gridfinity-pic-to-bin
python3 -m venv .venv          # optional; Windows: py -m venv .venv
source .venv/bin/activate      # optional; Windows: .\.venv\Scripts\Activate.ps1
pip install -e ".[web]"        # or ".[dev]" / "." for core only

An editable install still runs from anywhere, so you can keep the checkout here and run pic-to-bin from your working folder — or run it from the checkout and let generated/ land next to the source (it is gitignored).


Step 1: Print the template

Generate and print a template for your paper size. Print at exactly 100% scale — no fit-to-page.

generate-phone-template --paper-size letter --output template.pdf
Options:
  --paper-size {a4,letter,legal}   Paper size (default: a4)
  --output PATH                    Output PDF path (default: phone_template_<size>.pdf)

The template places 8 ArUco markers (IDs 0–7) — 4 corners and 4 edge midpoints — around a dotted placement zone. The markers are 20 mm squares with ~20 mm margins from the paper edge.

Placement zone sizes by paper:

Paper Placement zone (W × H)
A4 130 × 217 mm
Letter 136 × 199 mm
Legal 136 × 275 mm

Step 2: Take the photo

  1. Lay the printed template on a flat surface.
  2. Place the tool inside the dotted placement zone.
  3. Photograph from above. Moderate angles are fine — perspective is corrected automatically.
  4. All 8 markers should be visible (3 minimum, 8 ideal).
  5. Measure the tool's depth with calipers — you'll need it for --tool-height.

Lighting tips: Use diffuse overhead light. Avoid harsh shadows across the markers. Do not cover markers with the tool.

Format: JPEG, PNG, or HEIC/HEIF (iPhone) are all supported.


Step 3: Run the pipeline

Single tool

pic-to-bin photo.jpg --tool-height 17

Multiple tools (one photo each)

pic-to-bin a.jpg b.jpg --tool-height 0=17 --tool-height 1=14

Tool indices correspond to image order. Each tool's DXF is traced separately and packed into one bin.

Specifying paper size

pic-to-bin photo.jpg --tool-height 17 --paper-size a4

The paper size must match what you printed. Default is letter.

Shallow drawer (no stacking lip)

pic-to-bin photo.jpg --tool-height 17 --stacking false

Drops the 4.4 mm stacking lip for shorter bins in shallow drawers. Pocket depth is unchanged.

All pic-to-bin options

positional:
  images                        Photo files to process (default: all PNG/JPG in cwd)

required:
  --tool-height VALUE           Tool depth in mm. Use INDEX=VALUE per tool
                                (e.g. --tool-height 0=17 --tool-height 1=14)

optional:
  --paper-size {a4,letter,legal}  Template paper size (default: legal)
  --tolerance MM                  Extra clearance on top of a 2 mm baseline
                                  (default: 0 = 2 mm physical clearance).
                                  Positive = looser fit, negative = tighter,
                                  -2 = exact-trace match.
  --axial-tolerance MM            Extra clearance only along the tool's
                                  principal axis (default: 'auto'; 2 mm
                                  floor + taper-proportional bonus).
                                  Compensates for SAM2 length under-
                                  detection.
  --phone-height MM               Camera height above template, mm (default: 480).
                                  Drives the parallax-compensation scale-down.
  --gap MM                        Minimum gap between tools in layout, mm (default: 3.0)
  --bin-margin MM                 Extra clearance from tool extent to bin wall (default: 0)
  --min-units-x N                 Minimum X grid size in units (default: 1)
  --min-units-y N                 Minimum Y grid size in units (default: 1)
  --min-units-z N                 Minimum Z grid size in height units (default: 1).
                                  Floor on the auto height; ignored when
                                  --height-units is set.
  --max-units N                   Max gridfinity grid size per axis (default: 7)
  --height-units N                Force bin height in gridfinity units (default: auto)
  --stacking BOOL                 Generate stacking lip (default: true). Set
                                  false for a shorter bin without the lip.
  --slots BOOL                    Generate finger-access slots (default: true)
  --output-dir DIR                Output directory (default: generated/)
  --straighten-threshold DEG      Max degrees to auto-straighten trace (default: 45, 0=off)
  --max-refine-iterations N       SAM2 cleanup iterations (default: 5)
  --max-concavity-depth MM        Max acceptable concavity loss, mm (default: 3.0)
  --mask-erode MM                 Post-SAM mask erosion (default: 0). Use 0.3-0.5
                                  only if your photos have a clear shadow halo.
  --sam-model WEIGHTS             SAM2 model file (default: sam2.1_l.pt)
  --skip-trace                    Skip tracing, reuse existing DXFs in generated/

Bin sizing logic

  • The bin auto-sizes to the smallest gridfinity unit count that fits the tool: ceil((tool_height + 1mm) / 7mm) height units.
  • The pocket floor sits 1 mm above the bin floor.
  • The deck rises to half the tool's height — the upper half of the tool stands proud for finger access; the lower half is buried in the pocket.
  • The combined cutout (pocket + finger slot) is centered in the bin floor; slack from rounding up to whole gridfinity units is distributed evenly on all four sides.

Output files

generated/
  <stem>/
    <stem>_rectified.png       Perspective-corrected image (scanner equivalent)
    <stem>_trace.dxf           Tool outline DXF (inner + tolerance + finger slot)
    <stem>_trace.svg           SVG preview of the trace
  combined_layout.dxf          All tools packed into a bin footprint
  layout_preview.png           Screen-viewable layout preview (matplotlib, 150 DPI)
  layout_actual_size.pdf       1:1 scale fit-test drawing (PDF page = bin footprint)
  layout_actual_size.svg       1:1 scale fit-test drawing (SVG width/height in mm)
  bin_config.json              Fusion 360 input config

The layout_actual_size.pdf and .svg files are sized to the bin's exact mm dimensions — print at "Actual size" / 100% scale (NOT "Fit to page") and lay your real tool on top to verify the fit before committing to a 3D print.

After Fusion runs:

generated/
  gridfinity_bin.stl
  gridfinity_bin.step
  gridfinity_bin_preview.png  Viewport screenshot of the finished bin

Web app (browser frontend)

A FastAPI + Lit web wrapper exposes the same pipeline through a browser. Multi-user ready: per-job UUID directories, GPU semaphore around SAM2 so concurrent submissions queue rather than fight over the GPU, SSE-streamed progress.

pip install "gridfinity-pic-to-bin[web]"      # or: pip install -e ".[web]"
pic-to-bin-web --port 8000

Open http://localhost:8000, drag in a photo, fill in the tool height, watch the step tracker, review the layout preview (with print-at-actual-size PDF / SVG downloads to test fit), then click Proceed to generate the bin config.

The browser back button navigates between screens (form → progress → preview → downloads). The form fields all have an (i) info button next to their label that opens a modal with a multi-paragraph explanation.

To replace the default esm.sh Lit import with a vendored local copy:

python -m pic_to_bin.web.vendor_lit

Running individual steps

You can run each stage of the pipeline independently.

Preprocess a photo

Detect markers, correct perspective, and save the rectified image:

preprocess-phone photo.jpg --paper-size letter --output-dir generated/photo
positional:
  image                         Phone photo file

optional:
  --paper-size {a4,letter,legal}  Template paper size (default: a4)
  --output-dir DIR                Output directory (default: generated/<stem>)

Outputs <stem>_rectified.png at the computed effective DPI (typically 100–250).

Trace a rectified image

Run SAM2 segmentation + vectorization on a rectified image:

trace-tool rectified.png --dpi 150

Pack tool DXFs into a layout

layout-tools tool1.dxf tool2.dxf --gap 3 --max-units 5

Generate the Fusion 360 config

prepare-bin generated/combined_layout.dxf --tool-height 17

Fusion 360 integration

pic-to-bin ships in two flavors for Fusion 360 — a toolbar add-in (recommended) and a classic script. One install command sets up both:

pic-to-bin-fusion install

This copies the add-in to …/API/AddIns/pic_to_bin/ and the script to …/API/Scripts/pic_to_bin/, sharing the build code (_bin_builder.py) between them.

Add-in (recommended) — toolbar button

  1. Open Fusion 360.
  2. Press Shift+S → Add-Ins tab.
  3. Select pic_to_bin → Run (toggle Run on Startup to keep the button available every session).
  4. In a Design workspace, the Solid > Create panel now contains a Gridfinity Pic-to-Bin button.
  5. Click the button. The script auto-loads <project>/generated/bin_config.json if it exists; otherwise a file dialog opens defaulting to your Desktop.
  6. Bin gets built, exported as STL + STEP, and a viewport screenshot is saved alongside bin_config.json.

Script form (alternate)

If you prefer the classic Scripts dialog:

  1. Press Shift+S → Scripts tab.
  2. Select pic_to_bin → Run.

The behavior is identical to the add-in button.

What gets built

The bin is generated in a fresh document with these timeline groups for easy navigation:

  • Bin Body — outer rectangular block. Appearance: ABS (White).
  • Stacking Lip (if enabled) — solid block + corner fillets + base-profile mating cutout + 0.6 mm top recess.
  • Deck — recessed surface around the pocket.
  • Tool Pockets — one cut per tool.
  • Finger Slots — one cut per tool, same floor as the pocket.
  • Base Pads — gridfinity baseplate-mating geometry, one Join extrude for all wide pads, one for the narrow posts, plus the two chamfers.

Reinstalling and reload

Re-running pic-to-bin-fusion install overwrites both folders. The script and add-in entry points reload _bin_builder.py from disk on every invocation, so most code changes land on the next button click without restarting Fusion. Only changes to the entry-point files themselves (pic_to_bin_script/pic_to_bin.py or pic_to_bin_addin/pic_to_bin.py) require a Stop/Run on the add-in or a Fusion restart.

Uninstall

pic-to-bin-fusion uninstall

Removes both the script and the add-in.


Troubleshooting

Problem Likely cause Fix
MarkerDetectionError: No markers detected Template not visible or too blurry Ensure all markers are in frame; hold camera steadier
MarkerDetectionError: Only N markers (need ≥3) Markers obscured or overexposed Improve lighting; don't cover markers with tool
ScaleInconsistencyError: H/V scales differ >5% Template not printed at 100% Reprint with fit-to-page disabled
WARNING: Low effective DPI (<100) Camera too far away Hold phone closer; use higher resolution mode
Tools don't fit in grid Tools too large for --max-units Increase --max-units
Fusion freezes building pockets Stale cached _bin_builder after editing The reload is already wired in — just click the button again. If still stuck, restart Fusion.
Pocket fits too loose Default --tolerance 0 produces 2 mm physical clearance + ≥2 mm at each tip Lower with --tolerance -0.5 and/or --axial-tolerance 1.0
Pocket fits too tight at the tool's tips only SAM2 under-detected the tapered ends Increase --axial-tolerance (default 'auto', 2 mm floor)
Pocket fits too tight everywhere Trace itself is short (shadow halo, parallax, mask erosion) First try --tolerance 1 (= 3 mm physical). If still tight, check --phone-height matches your shooting distance

Common photo issues

  • Markers partially cut off: Keep all 8 markers visible. At 3 minimum the pipeline will run but accuracy drops.
  • Blurry markers: Tap to focus on the template before shooting; avoid camera shake.
  • Shadows on markers: Use diffuse or overhead lighting, not a side lamp.
  • HEIC images (iPhone): Supported natively — the pipeline converts automatically via pillow-heif.

Running tests

python -m pytest tests/ -v

License

MIT — see LICENSE.md.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

gridfinity_pic_to_bin-0.1.0.tar.gz (303.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

gridfinity_pic_to_bin-0.1.0-py3-none-any.whl (295.7 kB view details)

Uploaded Python 3

File details

Details for the file gridfinity_pic_to_bin-0.1.0.tar.gz.

File metadata

  • Download URL: gridfinity_pic_to_bin-0.1.0.tar.gz
  • Upload date:
  • Size: 303.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for gridfinity_pic_to_bin-0.1.0.tar.gz
Algorithm Hash digest
SHA256 988b7e2fb3dd3def5e4be32635d877a014734285ce92fac8ad814d918292fcff
MD5 5df192c0dc0932992472b0ec9374116d
BLAKE2b-256 6658dc28a33b35dc177b6de75a86c76777826c4366771e6dd09bba9063fbc0f0

See more details on using hashes here.

Provenance

The following attestation bundles were made for gridfinity_pic_to_bin-0.1.0.tar.gz:

Publisher: publish.yml on justinhardin/gridfinity-pic-to-bin

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file gridfinity_pic_to_bin-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for gridfinity_pic_to_bin-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5e8c636b61decfe5008b52f525f58e5d7e00264b64b141a31b9d718208a3214e
MD5 3a8198f1b50d1aef2c7b185b163a5a9e
BLAKE2b-256 9920fd06d6af248ba5a7ad9619964b180b53db64d1f51037f0d835019a9387e6

See more details on using hashes here.

Provenance

The following attestation bundles were made for gridfinity_pic_to_bin-0.1.0-py3-none-any.whl:

Publisher: publish.yml on justinhardin/gridfinity-pic-to-bin

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 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