mosaicraft
A Python photomosaic generator that runs every step of the pipeline in a perceptual colour space, and makes every cell of the output a distinct photograph.
The whole image is a mosaic of Vermeer's Girl with a Pearl Earring; zoom into any square and it's a different animal photograph.
mosaicraft rebuilds a target image as a grid of smaller tile photographs. Unlike most photomosaic libraries — which match mean colour in RGB/HSV and reuse the same tile dozens of times — mosaicraft runs Oklab for perceptual colour matching, MKL optimal transport for per-tile colour transfer, and Hungarian 1:1 assignment so every cell is a distinct photograph. Laplacian pyramid blending is also available (set --preset ultra when you want the cell seams smoothed away at the cost of some tile sharpness).
pip install mosaicraft
mosaicraft generate photo.jpg --tiles ./tiles --output mosaic.jpg
The tile pool
A sample from the curated animal close-up pool (5,000 photographs, CC BY 2.0 / Open Images V7). Hungarian 1:1 assignment picks exactly one cell for each photograph.
Installation
pip install mosaicraft # PyPI
pip install "mosaicraft[faiss]" # with FAISS for huge tile pools
Requires Python 3.10+, NumPy ≥ 1.23, OpenCV ≥ 4.6, SciPy ≥ 1.10, scikit-image ≥ 0.20. No GPU required.
Quick start
mosaicraft generate photo.jpg --tiles ./tiles --output mosaic.jpg -n 5000
from mosaicraft import MosaicGenerator
MosaicGenerator(tile_dir="./tiles").generate("photo.jpg", "mosaic.jpg", target_tiles=5000)
Why Oklab / Why MKL
Why Oklab? CIELAB was calibrated on small colour differences; it underestimates perceptual distance for the large jumps a photomosaic routinely makes. Oklab (Björn Ottosson, 2020) was rebuilt on modern colour-difference data and is noticeably more uniform on the saturated regions a photomosaic spends most of its compute budget matching. Dropping it into the cost function is free and visibly improves matches on saturated photos.
Why MKL optimal transport? Reinhard color transfer matches the first and second moments of the LAB distribution. MKL (Pitié et al., 2007) matches the full covariance, so the shape of the tile's color distribution is preserved as its statistics slide toward the target cell. Details survive; averages don't win.
Reproducing the figures
The zoom-detail and tile-pool images above are regenerated by python scripts/generate_readme_figures.py after running scripts/download_demo_assets.py (one-time, ~450 MB). The tile pool comes from the Open Images V7 dataset (Google, 2022); to refresh it, run python scripts/curate_oiv7_animals.py (downloads ~180 MB of metadata into .cache/oiv7/, HEAD-validates every retained URL, and rejects rows whose Rotation flag is non-zero so sideways Flickr thumbnails do not enter the pool). The curator filters by exact-match License == https://creativecommons.org/licenses/by/2.0/ so the pool contains only CC BY 2.0 images — no CC BY-SA, no CC BY-NC, no public-domain mixing. Per-image Title, Author, Source (landing URL), and License are surfaced in docs/assets/ATTRIBUTION.md (auto-generated by scripts/generate_attribution.py per Creative Commons TASL practice) and the file is enforced in CI by scripts/verify_attribution.py.
Testing
pip install -e ".[dev]"
pytest # unit + pipeline + CLI tests
ruff check src tests # lint
bandit -r src -ll # security scan
Contributing
Bug reports, feature requests, and pull requests are welcome. See CONTRIBUTING.md for the development workflow. Security issues: see SECURITY.md.
Verification (sigstore)
Releases from v_next_ (released after 2026-05-16) include a sigstore keyless signature bundle
(.sigstore per artifact) attached to the GitHub Release.
Verify a PyPI install
pip download <pkg-name>==<version> --no-deps -d ./verify
python -m sigstore verify github \
--cert-identity 'https://github.com/hinanohart/mosaicraft/.github/workflows/release.yml@refs/tags/v<version>' \
--cert-oidc-issuer 'https://token.actions.githubusercontent.com' \
./verify/*.whl ./verify/*.tar.gz
The corresponding .sigstore bundles can be downloaded from the GitHub Release page.
Historic releases (pre-2026-05-16)
Earlier releases were published without sigstore bundles. Re-installing those versions provides no cryptographic provenance — pin to a current release if assurance matters.
License and image credits
MIT License for human use. See LICENSE.
AI/ML training opt-out: this repository is opted out of AI/ML training, fine-tuning, and embedding generation — see ai.txt. Training use requires separately negotiated written permission.
Image credits:
- Target painting — Johannes Vermeer, Girl with a Pearl Earring (c. 1665), public domain, via Wikimedia Commons.
- Tile pool — 5,000 animal close-up photographs from the Open Images V7 dataset, restricted to images licensed under CC BY 2.0 (no share-alike, no non-commercial, no public-domain mixing). Curated by
scripts/curate_oiv7_animals.pyfrom a hand-picked list of 80 leaf classes in the Open Images Animal subtree (Cat, Dog, Fox, Owl, Tiger, etc.), with HEAD-probe URL validation to drop dead Flickr links and a Rotation-flag filter so the un-rotated Flickr thumbnails arrive upright. Each photograph is attributed to its photographer indocs/assets/ATTRIBUTION.md(auto-generated fromanimal_tiles_index.json, ~3,500 distinct Flickr accounts, with title + source URL per Creative Commons TASL practice) as required by CC BY 2.0. Photographers may withdraw their original uploads — theMANIFEST.jsonSHA256 check reports any URL that subsequently 404s.
References
mosaicraft stands on the following classic and modern work:
- Björn Ottosson, A perceptual color space for image processing (2020, blog). Oklab.
- Pitié, F. et al., The linear Monge-Kantorovitch linear colour mapping for example-based colour transfer (IET-CVMP 2007). MKL.
- Reinhard, E. et al., Color transfer between images (IEEE CGA 2001).
- Zhang, R. et al., The Unreasonable Effectiveness of Deep Features as a Perceptual Metric (CVPR 2018). LPIPS.
- Wang, Z. et al., Image quality assessment: from error visibility to structural similarity (IEEE TIP 2004). SSIM.
- Tesfaldet, M. et al., Convolutional Photomosaic Generation via Multi-Scale Perceptual Losses (ECCVW 2018). Multi-scale perceptual loss for photomosaic quality assessment.
- Burt, P. & Adelson, E., A multiresolution spline with application to image mosaics (ACM ToG 1983). Laplacian pyramid blending.
- Kuhn, H. W., The Hungarian method for the assignment problem (Naval Research Logistics 1955).
Metadata
Release files for mosaicraft 0.4.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| mosaicraft-0.4.2.tar.gz | 53.1 kB | With provenance | Details for mosaicraft-0.4.2.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| mosaicraft-0.4.2-py3-none-any.whl | Python 3 | none | any | Details for mosaicraft-0.4.2-py3-none-any.whl |
Total release size: 93.0 kB
Release files / mosaicraft-0.4.2.tar.gz
| Download URL | mosaicraft-0.4.2.tar.gz |
|---|---|
| Size | 53.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
63b02e4c611a697878a9a63670a3f332947b50ede6128094a660501b8aab1948
|
|
BLAKE2b-256 checksum How to use checksums |
74d1ce103801b6e147e92c37ba13c7e5a578fc0e6a0e74fe05ecff65d50e6c53
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 19, 2026.
Transparency logRelease files / mosaicraft-0.4.2-py3-none-any.whl
| Download URL | mosaicraft-0.4.2-py3-none-any.whl |
|---|---|
| Size | 39.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a7796e3da6bd71cfd6aed8cbfca18ac94118863cccd52da9e2fdb43764964815
|
|
BLAKE2b-256 checksum How to use checksums |
bb22fd2320ebad7b73d4f5ac44b8595cfdd44df805568934155820d58d165a75
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 19, 2026.
Transparency logSecurity for mosaicraft 0.4.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for mosaicraft-0.4.2.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 19, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.