Automatic page splitting

This commit is contained in:
sebastien committed 2026-11-03 22:08:36 +01:00
1 parent d4404e4c27
commit 78f3e4b2f0
13 files changed
+1959 -40

No files matched your search

+241
View File
@@ -0,0 +1,241 @@
# Experimental automatic page splitting
## Python GUI
The “Séparer et réordonner les pages” step now offers **Manuellement** and
**Automatiquement**. Automatic processing runs in the background using the
standard splitter, publishes PDFs in `Copies`, and preserves source scans in
`Copies Originales`. It retains source-page order. The parallel-copy setting
appears only for automatic processing. Existing single-copy and marked-copy
selection work in both modes.
Choose Manuellement afterward to review the saved proposals against the
preserved original. The editor displays independent overlapping output crops
and crosses out removed blank pages. Advancing accepts the displayed decision;
the existing keep/discard shortcuts override it. Moving a splitter resumes
manual splitting on that page. Reviewing automatic proposals preserves their
source-page order; the original manual workflow retains its booklet ordering.
Proposals are reused only while both source and output fingerprints still match.
Each automatic run saves its inputs, report/gallery, and previous outputs under
`.copienator/runs/page-split-*`. All PDFs are analysed before publication, and
PDFs and provenance are published together with rollback on installation errors.
An entirely blank copy keeps its preserved source and receives a manual-review
flag instead of an invalid empty output PDF.
The equivalent CLI command is:
```sh
python -m copienator page-split EVALUATION --automatic --workers 4
```
Omit `--automatic` for the interactive editor. The standalone review command
below remains available for experiments without installing results into `Copies`.
Run from the repository root, on original scans rather than already split copies:
```sh
python -m copienator.auto_page_split 'Interro07/Copies Originales' tmp/split-review --workers 4
```
The output directory must not already exist. Input PDFs are never overwritten.
This command is deliberately separate from the GUI and from the interactive
`page-split` command. It does not reorder booklets or use secondary splitters.
Outputs follow source-page order, left then right. They must not replace the
current processed evaluation without review and the appropriate later ordering.
## Outputs
- `index.html`: source-page previews, proposed boundaries, blank decisions,
uncertainty reasons, and links to exported PDFs.
- `pdfs/`: clipped PDFs retaining source scan data, without rasterizing output.
- `report.json`: decisions, original file hashes, original rotations/CropBoxes,
source page numbers, displayed clip coordinates, and output page numbers.
- `review/`: JPEG previews. Green marks the left output, purple the right/whole
output, orange the detected centre groups; red shading marks a blank removal.
A wholly blank copy has no output PDF, but still has report entries. An interrupted
run may leave partial outputs; use a new output directory for a subsequent run.
## Decisions
Displayed physical dimensions distinguish A3 landscape spreads from A4 sheets,
with a 5% tolerance. A4 landscape sheets are also retained whole. Unexpected
sizes and portrait A3 pages are retained whole and flagged. PDF rotation is
respected; handwriting orientation is not inferred.
The standard splitter renders a 75 dpi overview, accepts clearly written pages,
and analyses a central 10% strip at the requested 200 dpi for overflow ownership.
Sparse logical pages use `ink_detection.detect_page_content` at full resolution.
Ambiguous ownership, overflow reaching the strip edge, and unexpected geometry
use the internal full-page fallback. Coloured-ruling cleanup prevents grid
fragments from linking text across the fold.
That shared entry point runs normal rognage with its default artifact filtering.
On confirmed ruled paper it exposes the existing large-blank refinement's retained
content, including an empty result. Ordinary cropping deliberately falls back to
the original mask when refinement is empty; the new entry point does not. Normal
cropping behaviour and defaults remain unchanged. The same coherent-stroke filter
checks seedless pages for plausible pencil writing. On plain paper, the existing
adaptive foreground extractor recovers letter-sized pencil components; faint
page-spanning scanner borders do not qualify. It does not retain a page
merely because unrelated faint pixels survive. There is no separate weak-pixel
veto or splitter-specific hole-removal algorithm.
Small initial stroke groups near the midpoint are followed towards supported
writing inside either page. Connected faint strokes can recover beyond the
cropper's local 2 mm radius, while page-wide ruling networks are rejected. The
ownership search allows larger horizontal gaps between strong pen regions,
penalises vertical gaps, and stops at a page anchor rather than joining entire
lines across both pages. Pale thin ruling is filtered before word grouping.
An isolated group with no page anchor is treated as a fold artifact. Comparable
support from both pages still produces an explicit review flag. Output rectangles
cover the actual terminal strokes plus 2 mm padding, not the expanded search
area. Each side's boundary remains independent. The regression suite and reviewed
real examples are documented in `cropping-test/page-splitting/README.md`.
Blank decisions use logical-page evidence after subtracting actual strokes
attributed to the opposite side. The report includes the crop analysis and the
content-refinement result for each output. A spread artifact that is absent from
the logical page's credible content cannot by itself veto blank removal.
## Limitations and interpretation
The report's flags are heuristic reasons, not calibrated confidence scores.
Repeated-hole detection and ruling suppression can be ambiguous around unusual
handwriting. Extremely faint isolated writing can escape detection. Horizontal
grouping can miss disconnected parts of long formulae or merge adjacent blocks.
Ambiguous cases intentionally duplicate content rather than choosing an owner.
Full-height rectangular overlap can include neighbouring text at other heights.
Blank removal is intentionally conservative. Do not interpret a retained page
as proof it contains student work. In particular, residual scan marks can keep
otherwise blank pages. Interro07's saved page-origin mappings provide a useful
comparison with earlier processing, but are not independent handwritten ground
truth and do not validate overflow attribution.
## Verification
```sh
python -m unittest tests.test_auto_page_split tests.test_ink_detection tests.test_crop_blank_margins tests.test_page_splitter_reverse tests.test_page_splitter_secondary -q
```
Tests cover both overflow directions at once, disconnected letters, ambiguous
ownership, opposite-side blank attribution, weak scan noise, pencil-only writing,
blank grids with binding holes, faint grid notes and fraction bars, A4/unknown
sizes, all four PDF rotations with CropBox
offsets, rendered export fidelity, input preservation, existing-output refusal,
and wholly blank copies.
## Updated full Interro07 batch (2026-11-03)
The current batch is `tmp/auto-page-split-interro07-support-20261103/`.
All 47 original PDFs were processed: 214 scanned pages, with 206 A3 spreads
and 8 A4 sheets. The output contains **347 logical pages**, removing **73 blank
halves**. All 345 pages kept by the earlier workflow remain kept. The two
additional retained halves contain exercise headings (Copie08 source 6/left and
Copie11 source 4/left), consistent with the reviewed content policy.
Exactly seven keep/remove decisions change from the preceding 66-removal batch,
matching the seven reviewed difficult blank fixtures. Their source halves were
visually checked; the two heading exports were rendered with Poppler and checked.
Original hashes, output page counts and displayed dimensions were verified.
`comparison.json` records the comparisons. The 26 source-page overlap review
flags remain; blank detection results do not validate all overflow attribution.
## Shared rognage trial (2026-11-02)
The current results are in `tmp/auto-page-split-interro07-shared-rognage/`.
Blank detection now uses the shared crop content analysis on each logical page.
The splitter-specific weak-pixel veto and hole cleanup have been removed.
Normal cropping still uses its original empty-refinement fallback.
Against Interro07's saved page-origin mappings, the updated detector removes
66 of the 75 previously omitted halves (88%), compared with 5 in the initial
prototype. All 345 previously retained pages are preserved. Nine previously
omitted halves remain kept, including two very pale pages retained by the
pencil-writing recovery check. These are conservative keep decisions; no
previously retained page was removed. The output has 354 logical pages.
All proposed removals were reviewed in source-page contact sheets. The final
PDF page counts, dimensions, and source hashes are checked, with results in
`comparison.json`. The 44 regression tests pass, covering normal crop behaviour,
blank ruled sheets with holes, faint writing, scanner borders, large faint
diagrams, overlap geometry, and rotation. This validates blank detection against
the existing Interro07 workflow; it is not an exhaustive annotation of handwriting
or overflow ownership. Centre-binding artifacts can still cause false overlap
proposals. No GUI integration or change to the existing processed PDFs was made.
## Initial Interro07 trial (2026-11-02; superseded)
The final trial is in `tmp/auto-page-split-interro07-final/` (ignored by Git).
It processed all 47 original PDFs: 214 scanned pages, comprising 206 A3 spreads
and 8 A4 sheets. Original-file hashes were verified unchanged. The exported
PDFs contain 415 logical pages. There are 47 extended spreads, including 21 with
both boundaries extended, and 69 source pages flagged for review. These counts
describe proposals, not validated correct overflow detections.
Comparison with the saved `Interro07/.copienator/page_origins/` mappings:
| Decision | Logical pages |
| --- | ---: |
| Previously retained, still retained | 345 |
| Previously retained, now removed | 0 |
| Previously omitted, now removed | 5 |
| Previously omitted, retained as uncertain | 58 |
| Previously omitted, classified as content | 12 |
All five proposed removals were visually inspected and appear blank. Selected
overflow previews and Poppler-rendered exports were also inspected. The coloured
ruling cleanup fixed a false 88.65 mm left extension on Copie36, source page 4:
the final 4.45 mm extension follows the equation at the centre. Binding artifacts
still generate false extensions elsewhere. No independent exhaustive annotation
of overflow ownership was made; preserving previously retained pages does not
prove that every stroke is correctly assigned or unclipped.
The 38 focused and existing regression tests pass, including pixel comparisons
of exported pages with rotated, offset-CropBox sources. The prototype is **not
ready for unattended GUI integration**. The next priorities are better blank-page
recall without erasing faint work, and better separation of binding artifacts
from centre handwriting. `comparison.json` lists the 70 keep/remove disagreements
for targeted follow-up. Neither the GUI nor the existing processed copies changed.
## Standard coarse-to-fine analysis
The former fast mode is now the only command-line analysis path. It renders a
75 dpi overview and only a central 10% strip at the requested 200 dpi. A positive
content gate accepts obvious writing; sparse or ambiguous pages still use full
resolution content detection. Ambiguous ownership or overflow reaching the strip
boundary uses the complete reference analysis. Unexpected geometry keeps the
reference path. Exported scan data remains at its original resolution.
```sh
python -m copienator.auto_page_split 'Interro07/Copies Originales' tmp/fast-review \
--workers 4
```
The full Interro07 run in `tmp/auto-page-split-interro07-fast-final-20261103/`
takes 37.87 s including exports/previews, retains 347 pages and removes 73 blank
halves. All 420 keep/remove decisions agree with a fresh reference analysis.
Seven output boundaries differ: five by one pixel, and two inspected differences
in ruling/padding without observed loss of writing. This mode is not pixel-identical
to the reference. There is no analysis-mode selector; full-spread analysis remains an internal fallback.
See `cropping-test/page-splitting/experiments/FAST_ANALYSIS.md` for matched timing
comparisons, rejected low-resolution variants, quality checks and limitations.
## Interro06 blank-detection follow-up
The reviewed Interro06 suite originally passed 15/19 with fast analysis. All four
failures were unwritten halves retained for isolated ink marks. Compact solid
spots smaller than 2 mm no longer qualify as glyphs by themselves; their convex
hull must be filled, so small x-shaped glyphs remain eligible. A short almost
collinear smear within 15 mm of the top/bottom edge also needs neighbouring
writing support. The smear rule has additional area, size and density limits.
Both filters affect blank classification only; normal margin cropping is unchanged.
The four targets now pass, along with all 19 Interro06 cases, all 15 Interro07
blank cases and the writing-preservation controls. Inputs and reviewed expectations
are unchanged. The exact marks and initial measurements are saved under
`cropping-test/interro06/blank-investigation/`.