Changelog#

All notable changes to AMFOrA are documented here. The format roughly follows Keep a Changelog, and versions follow semantic versioning.

v1.0.3 — 2026-08-24#

  • Single source of truth for the version. amfora.__version__ is now read from the installed package metadata via importlib.metadata, so the version is declared only in pyproject.toml. Removes the hand-maintained duplicates in src/amfora/__init__.py that could drift out of sync.

  • Inclusion orientation is now multivariate-ready. analyze_single_sherd (and therefore full_analysis) now emits circular orientation metrics computed from the sherd-corrected axial grain angles, alongside the retained legacy contour_inclusion_orientation_mean / _std:

    • contour_inclusion_orientation_strength — resultant length (0 = random, 1 = perfectly aligned)

    • contour_inclusion_orientation_concentration — von Mises concentration estimate

    • contour_inclusion_orientation_uniformity, contour_inclusion_orientation_bimodality

    • contour_inclusion_orientation_dominant_deg — dominant direction (real axial degrees)

    • contour_inclusion_orientation_alignment — signed mean(cos 2θ): +1 = grains parallel to the sherd surface, 0 = random, −1 = perpendicular

  • The circular metrics call the pre-existing analyze_orientation_for_pca() on the doubled angles, so the axial (−90°, 90°] range maps onto the full circle and a random fabric correctly yields strength ≈ 0. Plain mean/std of circular degrees were not valid for PCA/LDA/clustering; these fix that and should have been exported in earlier releases.

  • No breaking changes: existing columns are unchanged; the new columns are additive.

v1.0.1 — 2026-06-01#

  • Documentation: README, docs/index.md, and docs/installation.md now lead with pip install amfora instead of cloning the GitHub repo. The from-source path is still documented for development use.

  • Citation: README citation now links to the PyPI project page.

v1.0.0 — 2026-05-31#

First release. Package renamed from the original AMFOrA_public working name to amfora for PyPI publication.

Detection pipeline#

  • Replaced the local-ring inclusion pop gate with a paste-anchored MAD-scaled version. The threshold per channel is max(K · MAD, floor), where MAD is the per-channel Median Absolute Deviation of paste pixels. The same K works across paste types because MAD tracks the paste’s own noise floor.

  • Added watershed cluster recovery for dark connected components too big for the size cap.

  • Added a multigrain split pass that re-splits lumpy accepted contours into individual grain sub-contours via distance-transform watershed seeded by local-maxima.

  • Added an edge-band gate to both detectors (4 % of shorter image dimension by default). Covers CLAHE tile-boundary leakage and unmasked-overhang artifacts.

  • Added effective_detection_area_cm2 to analyze_single_sherd results. Density and area-percentage metrics now divide by this instead of sherd_area_cm2, so they reflect the area the detectors actually searched.

Synthetic image generator#

  • New amfora.testing module exposing the calibrated synthetic-sherd generator (previously inline in examples/pro_gen_images.ipynb). Adds a paste_noise_std parameter so the same image can exercise either the K · MAD or the paste_pop_floor branch of the pop gate.

Packaging#

  • Migrated to modern src/amfora layout with pyproject.toml (hatchling backend). setup.py and requirements.txt removed.

  • Python 3.10+ required.

  • All previously-undeclared dependencies (seaborn, scikit-learn, plotly) added to the install requirements.

  • Optional extras: [test], [dev], [docs].

Tests and CI#

  • Added tests/ with 17 pytest tests covering imports, paste reference / MAD, false-positive rejection, recall on synthetic ground truth, and analysis result shape.

  • Added .github/workflows/test.yml (pytest on Py 3.10/3.11/3.12 + macOS Py 3.12, coverage upload).

  • Added .github/workflows/lint.yml (ruff check + format).

Bugs fixed during test-suite buildout#

  • OpenCV 4.10+ blob param validation crash on bright pastes. The hardcoded min(200, max_thresh) cap pushed max < min on cream / white channels, which OpenCV 4.10+ rejects. Cap raised to 255 with max > min enforced.

  • Cross-channel _drop_nested over-firing. The per-channel-pool dedup used centroid-in-polygon, which dropped adjacent features when one’s centroid fell inside another’s outline. Replaced with bbox-IoU + asymmetric containment, which correctly distinguishes same-feature duplicates from adjacent features.

  • cv2.erode borderValue default. The edge-band erosion was a silent no-op on all-foreground masks (pre-masked / synthetic inputs) because OpenCV’s default border handling preserved image-edge pixels. Both call sites now pass borderType=BORDER_CONSTANT, borderValue=0 explicitly.

  • Docstring escape-sequence deprecation warnings under Python 3.12. Stripped \* and \_ backslash escapes from docstrings.

Documentation#

  • Repo-root files: README.md, CONTRIBUTING.md, CODE_OF_CONDUCT.md (Contributor Covenant 2.1), generative-AI disclosure.

  • Jupyter Book under docs/ rewritten to reflect the current API; auto-published via .github/workflows/docs.yml.

  • API reference auto-generated from NumPy-style docstrings via Sphinx autodoc.


Prior history#

The pre-1.0 work was developed under the names AMACFA+ and AMFOrA_public. That history is preserved in the git log; see github.com/aleciaco/AMFOrA_public/commits/main.