fix(convex-hull): Pick's-theorem hull area so SOLIDITY <= 1#357
fix(convex-hull): Pick's-theorem hull area so SOLIDITY <= 1#357darkclad wants to merge 1 commit into
Conversation
Justification — golden value changes for
|
| Golden | Old | New | Why |
|---|---|---|---|
CONVEX_HULL_AREA |
20.0 | 27.0 | Pick's-theorem pixel-count hull area on the fixture. External oracle scikit-imageconvex_area = 28 (≈4% high; the two hulls differ by one boundary lattice point). |
SOLIDITY |
1.3 | 0.9629629629629629 | = AREA_PIXELS_COUNT / CONVEX_HULL_AREA = 26 / 27 = 0.962962…. scikit-image gives 26/28 = 0.929. Now ≤ 1. |
Why this is not fudging
- Internal consistency: the new
SOLIDITYis exactlyAREA_PIXELS_COUNT (26) / CONVEX_HULL_AREA (27); both the numerator (26, unchanged golden) and the new denominator are in the same table. - Nothing else moved: the fix only changes
s_hull.CIRCULARITY(which usess_roiand the
perimeter, not the hull) is unchanged, as are all other shape goldens. Only the 2 hull-derived
keys changed. - Sign of correctness: the old value 1.3 was provably wrong (solidity can never exceed 1); the new
value is ≤ 1 and within ~4% of scikit-image's independentconvex_area/solidity. - Values are byte-identical to the oracle-validated
main-feature-validation(copied, not invented);
only the shared table-merge refactor was dropped (I keptmain's two-table structure and edited the
two numbers in place).
Regression guard
tests/python/test_feature_bugs.py::test_solidity_le_one asserts SOLIDITY <= 1 + 1e-6 on the
canonical ROI through the production featurize() path — the hard correctness invariant that the old
code violated (1.3).
CI
Full suite green on this branch: C++ runAllTests 683/683; pytest tests/python/ 49 passed, 1 skipped.
ConvexHullFeature computed the hull area with the bare shoelace polygon area, which runs through pixel centres and under-counts the rasterised pixel coverage. The ROI area is a pixel count, so SOLIDITY = roi_area / hull_area could exceed 1 (1.3 on the canonical ROI) - impossible. Use the Pick's-theorem pixel-count-equivalent hull area (shoelace + boundary_points/2 + 1, boundary_points = sum of gcd(|dx|,|dy|) over edges), matching scikit-image convex_area, plus a hull>0 guard. SOLIDITY is now <= 1 in both the trivial and out-of-core paths. Refresh the vetted goldens in test_shape_morphology_2d.h (CONVEX_HULL_AREA 20->27, SOLIDITY 1.3->0.96296 = 26/27; CIRCULARITY and all other shape goldens unchanged) and add tests/python/test_feature_bugs.py::test_solidity_le_one.
88e14df to
df9459b
Compare
ConvexHullFeature computed the hull area with the bare shoelace polygon area, which runs through pixel centres and under-counts the rasterised pixel coverage. The ROI area is a pixel count, so SOLIDITY = roi_area / hull_area could exceed 1 (1.3 on the canonical ROI) - impossible.
Use the Pick's-theorem pixel-count-equivalent hull area (shoelace + boundary_points/2 + 1, boundary_points = sum of gcd(|dx|,|dy|) over edges), matching scikit-image convex_area, plus a hull>0 guard. SOLIDITY is now <= 1 in both the trivial and out-of-core paths.
Refresh the vetted goldens in test_shape_morphology_2d.h (CONVEX_HULL_AREA 20->27, SOLIDITY 1.3->0.96296 = 26/27; CIRCULARITY and all other shape goldens unchanged) and add tests/python/test_feature_bugs.py::test_solidity_le_one.