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 viaimportlib.metadata, so the version is declared only inpyproject.toml. Removes the hand-maintained duplicates insrc/amfora/__init__.pythat could drift out of sync.Inclusion orientation is now multivariate-ready.
analyze_single_sherd(and thereforefull_analysis) now emits circular orientation metrics computed from the sherd-corrected axial grain angles, alongside the retained legacycontour_inclusion_orientation_mean/_std:contour_inclusion_orientation_strength— resultant length (0 = random, 1 = perfectly aligned)contour_inclusion_orientation_concentration— von Mises concentration estimatecontour_inclusion_orientation_uniformity,contour_inclusion_orientation_bimodalitycontour_inclusion_orientation_dominant_deg— dominant direction (real axial degrees)contour_inclusion_orientation_alignment— signedmean(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. Plainmean/stdof 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 amforainstead 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 sameKworks 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_cm2toanalyze_single_sherdresults. Density and area-percentage metrics now divide by this instead ofsherd_area_cm2, so they reflect the area the detectors actually searched.
Synthetic image generator#
New
amfora.testingmodule exposing the calibrated synthetic-sherd generator (previously inline inexamples/pro_gen_images.ipynb). Adds apaste_noise_stdparameter so the same image can exercise either theK · MADor thepaste_pop_floorbranch of the pop gate.
Packaging#
Migrated to modern
src/amforalayout withpyproject.toml(hatchling backend).setup.pyandrequirements.txtremoved.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 pushedmax < minon cream / white channels, which OpenCV 4.10+ rejects. Cap raised to 255 withmax > minenforced.Cross-channel
_drop_nestedover-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.erodeborderValue 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 passborderType=BORDER_CONSTANT, borderValue=0explicitly.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.