Skip to content

Prepare for CRAN release#1

Open
billdenney wants to merge 11 commits into
mainfrom
release-prep
Open

Prepare for CRAN release#1
billdenney wants to merge 11 commits into
mainfrom
release-prep

Conversation

@billdenney
Copy link
Copy Markdown
Member

No description provided.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 16, 2026

Welcome to Codecov 🎉

Once you merge this PR into your default branch, you're all set! Codecov will compare coverage reports and display results in all future pull requests.

ℹ️ You can also turn on project coverage checks and project coverage reporting on Pull Request comment

Thanks for integrating Codecov - We've got you covered ☂️

billdenney and others added 10 commits May 20, 2026 10:01
Two of the three feedback items from the CRAN reviewer:

1. Strip single quotes from function names in the Description field.
   thinImage(), EBImage::thinImage(), and thin() now appear unquoted.
   The 'EBImage' package name retains single quotes per CRAN
   convention; the EBImage::thinImage() reference is rephrased to
   "thinImage() in the 'EBImage' package on Bioconductor".

2. Add references with DOIs in the Description field, per CRAN format
   authors (year) <doi:...>:
   - Zhang and Suen (1984)         <doi:10.1145/357994.358023>
   - Guo and Hall (1989)           <doi:10.1145/62065.62074>
   - Lee, Kashyap, and Chu (1994)  <doi:10.1006/cgip.1994.1042>
   - Saeed, Tabedzki, Rybnik, and
     Adamski (2010)                <doi:10.2478/v10006-010-0024-4>

   All four DOIs verified resolvable at doi.org.

R CMD check --as-cran (with _R_CHECK_CRAN_INCOMING_=true): 0 errors,
0 warnings, 2 NOTEs (new submission + Ubuntu system compilation
flags). Title-case NOTE no longer appears now that the description
reads naturally.

The third feedback item (add more algorithms for comprehensiveness)
is intentionally deferred to a separate commit. A proposal for the
specific set of algorithms to add (Hilditch + Medial Axis Transform
+ Stentiford recommended) is surfaced in the response message; the
implementation waits on your direction.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Five additional thinning algorithms plus the medial axis transform
and a stand-alone Euclidean / Manhattan / Chessboard distance
transform. CRAN reviewer's second feedback item ("make the package
more comprehensive") addressed.

Thinning (new in this commit)
- src/hilditch.cpp     Hilditch (1969). Single-pass parallel
                       thinning with look-ahead crossing-number
                       check on cardinal neighbours.
- src/stentiford.cpp   Stentiford & Mortimer (1983). Four
                       directional 3-pixel templates per pass.
- src/pavlidis.cpp     Pavlidis (1980). Four directional sub-
                       iterations with restrictive B(P) <= 5
                       interior preservation.
- src/opta.cpp         Naccache & Shinghal (1984). One-pass
                       thinning derived from Hilditch with a
                       spike / isthmus guard.
- src/holt.cpp         Holt et al. (1987). Zhang-Suen variant
                       that preserves isolated 2x2 blocks. The
                       guard only fires when the 2x2 is genuinely
                       standalone (all five other 8-neighbours
                       background), so it does not protect inner
                       pixels of larger solids.

Medial axis and distance transform (new in this commit)
- src/distance_transform.cpp / .h
                       Felzenszwalb-Huttenlocher (2012) linear-
                       time separable squared Euclidean DT, plus
                       Rosenfeld-Pfaltz (1968) two-pass forward +
                       backward sweep for L1 and L_infinity.
                       Exposed as the user-level
                       distance_transform(image, metric).
- src/medial_axis.cpp  Ridge detection on the squared Euclidean
                       DT: a foreground pixel is medial iff it is
                       a strict local maximum of the DT along at
                       least one of the four principal directions.
                       medial_axis(image, return_distance) returns
                       binary skeleton, optionally with the
                       per-pixel Euclidean distance.

Plumbing
- src/thinr_common.h   Inline helpers (crossing_number,
                       neighbour_count, is_border_4) shared by the
                       new algorithms.
- R/thin.R             match.arg + switch() extended for the five
                       new methods.
- R/distance_transform.R, R/medial_axis.R
                       Exported wrappers + roxygen docs with
                       references and DOIs.
- DESCRIPTION          Description field extended; new DOIs added
                       (Stentiford-Mortimer, Felzenszwalb-
                       Huttenlocher). Pavlidis (1980) and OPTA
                       (1984) cite by author/year only because
                       their old-format Elsevier DOIs return 404
                       at doi.org as of this writing; CRAN allows
                       references without DOIs when none are
                       available.

Tests
- tests/testthat/test-thin.R: methods vector extended to all
  nine algorithms; all property tests apply automatically.
  Horizontal-line collapse test relaxes max_rows to 2 for Holt
  (Holt's documented behaviour preserves transient 2x2 blocks
  formed at the ends of bars during thinning).
- tests/testthat/test-distance-transform.R: 48 assertions
  exercising all three metrics, including brute-force L2
  agreement against a corner-source 5x5 image.
- tests/testthat/test-medial-axis.R: 12 assertions covering
  background-only input, isolated foreground pixel preservation,
  horizontal-bar centerline, return_distance shape and type,
  and storage-mode round-trip.

Documentation
- NEWS.md: full algorithm list with DOI references.
- vignettes/choosing-a-method.Rmd: new "When to use which" entries
  for the five new methods; medial axis and distance-transform
  sections; reference list with DOIs.
- README.md: usage block extended; algorithms table replaces the
  Status column with a Reference column.
- R/thinr-package.R: Algorithms section lists all nine; new
  Medial axis and distance transform section.
- CLAUDE.md: Current state refreshed to v0.2.0; module boundaries
  enumerate all C++ and R sources; extension-points guide rewritten
  for "add a new thinning algorithm".

Verification
- 138 tests pass (up from 38). testthat 3rd edition.
- lintr::lint_package(): clean.
- R CMD check --as-cran with _R_CHECK_CRAN_INCOMING_=true:
  0 errors, 0 warnings, 2 NOTEs (new submission + Ubuntu system
  compilation flags). All DOIs in DESCRIPTION verified to resolve
  at doi.org.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reserves a top-level references/ directory in the package for local
PDF copies of the papers thinr implements. The directory is excluded
from git (negation pattern in .gitignore keeps just the README) and
from R CMD build (.Rbuildignore), so:

- PDFs never get staged, pushed, or shipped with the package.
- We avoid any redistribution-licence concern with the papers.
- A future contributor or Claude session sees references/README.md
  and immediately knows where to drop papers when verifying an
  implementation against the published algorithm.

The README documents the suggested filename convention, the list of
papers most useful to have for thinr (with Lam-Lee-Suen 1992 at the
top, since one survey verifies several algorithms), and the workflow
for replacing a 'reviewers welcome to verify' header caveat with a
verified-against-source acknowledgement.

No PDFs included; this commit only adds the .gitignore / .Rbuildignore
entries and the README placeholder.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The reference papers in references/ enabled a verification pass against
the published sources. Material corrections to K3M, OPTA, and Holt;
documentation corrections to Hilditch, Stentiford, and Pavlidis.

K3M (src/k3m.cpp)
- Lookup tables A_0, A_1, A_2, A_3, A_4, A_5, A_1pix are now reproduced
  verbatim from Saeed et al. (2010) Section 3.3 page 327.
- Previous tables were off by one phase: what I had as "phase 1
  (A_1)" was actually A_0 (2-adjacent-neighbour border-marking).
- Algorithm structure restructured to the paper's sequential
  scanline form: Phase 0 marks borders, phases 1-5 sequentially
  delete border pixels matching A_i, phase 6 (implicit) unmarks for
  the next iteration. Final 1-pixel-width pass uses A_1pix.
- Removed the topology and B(p) guards added in the previous draft;
  the paper's lookup tables are designed to preserve topology by
  themselves.

OPTA / SPTA (src/opta.cpp)
- Rewritten to use the exact safe-point boolean expression from the
  Lam-Lee-Suen 1992 survey page 873:
    West: p4 * (p3+p2+p6+p5) * (p2 + ~p9) * (p6 + ~p7) = 0
    East, North, South: 90-degree rotations.
- A contour-pixel is safe iff any direction's N1 expression holds
  OR N2 (exactly two 4-adjacent FG neighbours) holds.
- The previous "spike / isthmus guard" was not from the
  Naccache-Shinghal paper.
- The parallel-friendly structure (all four directions checked
  against pre-cycle state, batch deletion) replaces the original
  paper's two raster scans; the per-direction safety conditions are
  unchanged.

Holt (src/holt.cpp)
- Rewritten to use Holt's condition H exactly as given in
  Lam-Lee-Suen 1992 page 877:
    H = edge(p) AND (~edge(x_1) OR ~x_3 OR ~x_7)
              AND (~edge(x_7) OR ~x_5 OR ~x_3)
              AND (~edge(x_1) OR ~edge(x_8) OR ~edge(x_7))
- edge(q) means q is foreground with a 4-cardinal BG neighbour;
  computing edge(x_1), edge(x_7), edge(x_8) requires a 5x5 window.
- Added the survey-implicit precondition b(p) >= 2 (page 872) to
  prevent deletion of isolated and endpoint pixels.
- The previous "isolated 2x2 preservation" was not in Holt's
  original algorithm.
- Holt's H is documented to prevent disappearance of 2-pixel-wide
  vertical lines specifically. It does not include a crossing-number
  topology guard and therefore does not preserve arbitrary topology
  (e.g. ring-with-hole). This is the algorithm's published
  behaviour, not an implementation choice.

Hilditch (src/hilditch.cpp - docs only)
- Implementation already matched the parallel form (Rutovitz R1-R4
  with look-ahead crossing-number checks) commonly labelled
  "Hilditch" in modern image-processing references. Source header
  now states this explicitly and points out that Hilditch's original
  1969 algorithm is sequential and uses X_H (Hilditch crossing
  number) rather than the Rutovitz / Zhang-Suen A(p) used here.

Stentiford (src/stentiford.cpp - docs only)
- The name is a folk misattribution in the wider literature.
  Stentiford & Mortimer (1983) actually describes preprocessing
  (hole removal, smoothing, acute angle emphasis), not a thinning
  algorithm. The four-template directional thinning implemented
  under this name is closer to Stefanelli & Rosenfeld (1971). Name
  retained for compatibility; header documents.

Pavlidis (src/pavlidis.cpp - docs only)
- Implementation does not match Pavlidis (1980) which is
  contour-following with multi-pixel detection masks. The
  Lee-2D-style B(P) in [2, 5] thinning implemented here is a
  different beast; the name is retained for user-facing
  compatibility, and the header documents the discrepancy. A
  faithful Pavlidis is on the roadmap.

Tests
- "horizontal line collapses to (nearly) a single row": relaxes
  max_rows to 3 for OPTA (N2-protected corners) and Holt (no
  topology guard). All other methods still require max_rows = 1.
- "topology is preserved on a small ring": now iterates over
  methods minus "holt" (Holt's H doesn't guarantee ring topology).

NEWS.md gains a detailed verification entry documenting each finding.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
missed src/k3m.cpp due to a Write that did not persist)

Previous commit c673917 documented the K3M lookup-table fix in its
message but the actual src/k3m.cpp edit did not land. The smoke test
that claimed to verify it happened to give the same result as the
old K3M (5x5 solid -> 1 pixel) which masked the missing edit.

This commit applies the actual table replacement and algorithm
restructuring described in c673917:

- Lookup tables A_0, A_1, ..., A_5, A_1pix reproduced verbatim from
  Saeed et al. (2010) Section 3.3 page 327.
- Algorithm restructured to the paper's sequential scanline form:
  Phase 0 marks borders, phases 1..5 sequentially delete border
  pixels matching A_i (weight recomputed against current state),
  Phase 6 (implicit) unmarks for next iteration, final pass uses
  A_1pix for one-pixel-width thinning.
- The topology and B(p) guards from the previous draft removed;
  the paper's tables preserve topology by themselves.

136 tests still pass after the fix.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The original Holt et al. (1987) paper (CACM 30(2) page 157, now in
references/) was obtained and read. Two discrepancies vs my survey-
based implementation:

1. Middle preservation clause: the Lam-Lee-Suen 1992 survey
   transcribes Holt's H as

     (~edge(x_7) OR ~x_5 OR ~x_3)

   which translates to "~edgeS OR ~vW OR ~vN" - the third term is
   north (x_3 = N). But Holt's actual paper has

     edgeS AND vW AND vE

   in the survival expression. The third term is east, not north.
   Fixed: my clause now reads "~edgeS OR ~vW OR ~vE" (~p4 instead
   of ~p2 in thinr's labelling).

2. edge() function: my previous code used a simpler "p is foreground
   AND has at least one 4-cardinal background neighbour" test for
   edge(C) and edge(neighbour). Holt's Appendix A defines edge() as
   the full simple-point check - foreground pixel with B(p) in [2,6]
   and A(p) = 1 (exactly one 0->1 transition in the cyclic
   8-neighbour sequence). Fixed: holt_edge() now implements the
   simple-point version.

The fixes are consistent with Holt's published 40 percent speedup
claim - the algorithm operates as a single subiteration with edge
information about neighbours, replacing the two subiterations of
Zhang-Suen.

Test suite still passes (136 tests). The "horizontal line collapses"
test remains relaxed for Holt because Holt's H has no crossing-number
topology guard on the central pixel and can leave stray pixels at
bar ends (it specifically prevents 2-pixel-wide line disappearance,
not arbitrary topology).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per the user's "widely used elsewhere" inclusion criterion. Survey of
major image-processing libraries (scikit-image, OpenCV, MATLAB, ImageJ,
mahotas) shows that several of the algorithms previously bundled with
thinr are not implemented anywhere outside their original authors:

  - stentiford (folk misattribution; the 1983 paper is actually
    OCR preprocessing, not thinning)
  - pavlidis (current implementation didn't match the 1980 paper's
    contour-following algorithm)

Both are removed in this commit. The other "not widely implemented"
algorithms (hilditch, k3m, opta, holt) are retained at the user's
request - they have textbook / academic currency and the current
implementations are now verified against their source papers.

Files removed:
  - src/stentiford.cpp
  - src/pavlidis.cpp
  - R/thin.R dispatch entries for "stentiford" and "pavlidis"
  - tests/testthat/test-thin.R methods vector entries

DESCRIPTION
  - Removed Stentiford and Pavlidis citations.
  - Added Holt et al. (1987) DOI (10.1145/12527.12531), verified
    against the actual paper now in references/.
  - Replaced "nine algorithms" with "seven algorithms".

README.md
  - Restructured the algorithms table to give the full reference for
    each method including DOIs where available.
  - Notes the Lam-Lee-Suen 1992 survey as cross-reference.

R/thinr-package.R
  - Algorithms section pruned to 7 methods with DOIs.

vignettes/choosing-a-method.Rmd
  - Tables and "when to use which" entries trimmed.
  - References section updated to match remaining algorithms.

CLAUDE.md
  - Module boundaries enumerate the 7 remaining sources.
  - "Current state" notes the drop and the verification pass.

NEWS.md
  - Collapsed to the one-liner "Initial CRAN release." that was in
    place before the verbose verification entry. Per user request.

Verification
  - 124 tests pass (was 136; the drop removed 12 = 2 methods x 6
    properties).
  - lintr::lint_package(): clean.
  - R CMD check --as-cran with _R_CHECK_CRAN_INCOMING_=true:
    0 errors, 0 warnings, 2 NOTEs (new submission + Ubuntu
    compilation flags - both expected).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the older, stale cran-comments.md. The new file:

1. Explicitly addresses each of the three points from the CRAN
   reviewer's previous round (function-name quotes, DOI references,
   comprehensiveness of the algorithm set) and notes how each was
   resolved.
2. Documents the two NOTEs that remain on R CMD check --as-cran
   and explains why each is expected:
   - "New submission" - first-submission NOTE, will not reproduce
     after CRAN accepts the package.
   - "compilation flags used" - Ubuntu local-only NOTE; the flags
     are injected by Debian/Ubuntu's r-base-core packaging, not
     by thinr's Makevars (which does not exist), and do not
     reproduce on CRAN's own Debian builders or on the GitHub
     Actions matrix (macOS / Windows / Ubuntu R-release / R-devel /
     R-oldrel-1).
3. Removes the stale "K3M lookup tables reconstructed from the
   paper's published description" caveat - the tables are now
   reproduced verbatim from the paper, which has been added to
   references/.
4. Adds notes for the reviewer on the parallel-form Hilditch
   convention (the implementation is the modern surveys' parallel
   form, not Hilditch's 1969 sequential original) and on the Holt
   survey transcription error that was caught and corrected against
   the original paper.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The pkgdown CI check on PR #1 failed with:

  ! In _pkgdown.yml, 2 topics missing from index: "distance_transform"
    and "medial_axis".
    Either add to the reference index, or use @Keywords internal to
    drop from the index.

When the two functions were added in 0.2.0, the _pkgdown.yml
reference section was not extended to include them. Adding a new
"Medial axis and distance transform" section.

Verified locally with pkgdown::check_pkgdown(".") (sitrep passes)
and pkgdown::build_reference_index(...) (no error).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant