Mesh-Free Ink Search
Automatic surface volumes from the published surface predictions, checked against hand-traced segments, a label-free test for lines of writing, and what they found on two unread scrolls.
Summary
- Surface volumes without a mesh. A small tracker follows one papyrus sheet through the published
m7surface prediction and samples the CT along it. On known text, ink predicted on these surfaces matches ink predicted on the published hand-traced segments: r = 0.55 at 9 µm and r = 0.72 at 2.4 µm. - A label-free test for lines of writing, and where it fails. Lines are 6.55 mm apart (median, measured from the organisers' labels). A row-profile periodicity score tells text from its rotated copy on the published 2.4 µm predictions (AUC 0.92; 0.97 where labels confirm ink). In a pre-registered benchmark on 9 µm ink_9um outputs it is at chance (tile AUC 0.50; 0.57 on label-confirmed text), even where the model reads the text almost perfectly. At 9 µm the ink comes out as blobs and the line structure is too weak for a 20 mm tile.
- A simpler rule that does work. The separation rule from villa #1867 picked the correct depth direction for all 14 labelled segments (five scrolls) and for all 14 checkpoints on held-out PHerc0841. Neither it nor the text score ranks checkpoints (Spearman +0.01 and +0.00).
- Search of PHerc1203 and PHerc0846A. 33 fields grown and run through ink_9um; the best candidates were read at 2.4 µm and showed no letter strokes. The benchmark shows the 9 µm text score could not have flagged text there, so the negative rests on the 2.4 µm reads only.
- Orientation. In-plane rotations and flips barely change ink_9um (AUC 0.79 to 0.85 against labels); reversing the depth order does (0.49 to 0.65), as villa #1648 reports. Published segments run the scroll axis both ways (500 rows-down, 408 rows-up meshes), which is harmless for this model.
1 · MethodSurface volumes from the surface prediction
Only one of the 21 scrolls on the challenge's unread list (PHerc0800) has published segments. Eleven of them have the organisers' m7 surface prediction on the same grid as the scan. Inside a block a few millimetres across, sheets are close to parallel, so a height field is enough:
- the sheet normal comes from the structure tensor of the surface prediction around a seed;
- one sheet is tracked as a height field over surface-prediction peaks, growing best-first from the seed, tile by tile, with each tile's depth window re-centred on the height its neighbours predict;
- the CT is sampled along the local normal into a 31-layer (9.6 µm) or 65-layer (2.4 µm) surface volume, with the normal's sign chosen so the papyrus body lies on the same side as in published segments, and the scroll axis down the rows.
On an M1 Pro laptop a 1.5 cm field takes about 8 minutes to grow at 9.6 µm; ink inference runs on the Apple GPU.
Check 1: 9 µm, PHerc0139 w043 (known text)
Check 2: 2.4 µm, PHerc0841 w00 (known text, held out for ink_9um)
2 · OrientationWhat the ink models are sensitive to
Ink_9um (seed42 step-040000) on PHerc0841 w00, a 9.8 mm crop of the published 2.4 µm surface volume pooled 4×4×4 to the model's 9.6 µm grid, run on every in-plane rotation and flip, each prediction mapped back and scored against the organisers' labels inside the supervision mask.
| depth order | rot0 | rot0+flip | rot90 | rot90+flip | rot180 | rot180+flip | rot270 | rot270+flip |
|---|---|---|---|---|---|---|---|---|
| as-published | 0.816 | 0.803 | 0.785 | 0.845 | 0.832 | 0.842 | 0.801 | 0.845 |
| depth-reversed | 0.544 | 0.542 | 0.586 | 0.538 | 0.643 | 0.652 | 0.489 | 0.551 |
Averaging all 8 orientations gives AUC 0.849, the same as the 4 mirror variants that --tta-mirror already averages (0.849), and 0.033 above a single pass. The 2 µm model scored 0.988 to 0.990 in the four orientations run.
Across all published segments (908 meshes on 308 segments, scripts/experiments/audit_orientation.py), 500 meshes run the scroll axis down the rows and 408 up: all of Paris 4 and PHerc0172, half of PHerc1667. Given the table above this does not matter for ink_9um; it matters for pixel-level comparisons between renders.
3 · Text testA label-free score for lines of writing
In a published-layout render, lines of text are horizontal and repeat vertically, 6.55 mm apart (median of 73 measurements on 13 labelled segments; middle 80% 5.65–7.27 mm). The first version (v1, "peakness") compared spectral power in that band with its neighbours, vertical against horizontal. Unit tests showed both v1 and a red-noise variant (v2) are too noisy on a 20 mm tile, which holds only about three line periods. The primary score (v3) averages each row across the tile first (lines span the tile, so this suppresses noise), at tilts of −6° to +6°, and compares the fraction of row-profile power in the band with the same for columns.
Two guards reject geometry: the same score computed on the field's own hole and outline map (mask peak ≤ 1), and coverage ≥ 0.6 with holes ≤ 12% of the outline. The early calibration below (v1) looked convincing; the benchmark in section 5 shows it does not hold on 9 µm outputs.
| Map | Peakness |
|---|---|
| Known text, mesh-free surface (w043, 9 µm) | +1.79 |
| Known text, published segment (w043, 9 µm) | +1.60 |
| Published 2.4 µm predictions, 20 mm tiles, median (Paris 4, PHerc0139, PHerc0841) | +1.5 to +1.9 |
| PHerc0800 published segments (presumed blank) | −0.90 to +0.35 |
4 · SearchPHerc1203 and PHerc0846A
Both scrolls are unread and have 2.4 µm scans with a surface prediction. Neither has published segments; PHerc1203 has 22 raw auto-grown meshes (about 130 cm²), PHerc0846A has none. Seeds were placed automatically on surface-prediction sheets at several heights; each 1.5 cm field was grown at 9.6 µm, run through ink_9um (two checkpoints) and scored.
33 fields were scored with v1; 12 pass the guards and 3 of those reach a peakness of 1.0. Of the 5 fields in the known-text range, 0 pass the guards. Two of the rejected ones are below. Section 5 shows that at 9 µm these scores do not separate text from no text, so this ranking only chose where to look at 2.4 µm.
Earlier 2.4 µm reads of the best-looking patches (5 mm and 1 cm, 2 µm ResNet-152 model) also showed no strokes: on PHerc0846A the model fires over broad saturated regions (46% of a 1 cm field) with tile-shaped edges, which is over-response on that papyrus, not writing.
Negative within limits: 33 fields of 1.5 cm cover a few percent of each scroll's scanned band, and on scrolls the models did not train on even correct predictions are weak (villa #1867). This is evidence that these two scrolls do not show text to the current public models in the sampled areas, not that they carry none.
5 · BenchmarkDoes the text score work? A pre-registered test
Plan and thresholds were committed before the runs (PREREG.md, with every later change listed as a
dated deviation). Negatives come from the same surfaces: running ink_9um with the depth order reversed removes the
ink signal (AUC near 0.5) but keeps every crack, tear and fibre. Positives are the same maps in the direction the
labels confirm.
B1 used 14 labelled segments; 14 had a clear text direction (AUC gap ≥ 0.05 and best AUC ≥ 0.60). Line band 5.65–7.27 mm, measured from the labels.
| segment | AUC forward | AUC reverse | text direction |
|---|---|---|---|
| PHerc0009B_20250919125754-auto_grown_202509190 | 0.806 | 0.552 | forward |
| PHerc0139_20250108000005-w030_2025010818 | 0.936 | 0.530 | forward |
| PHerc0139_20250831000000-w040_2025083102 | 0.997 | 0.496 | forward |
| PHerc0139_20260108000000-w041_2026010816 | 1.000 | 0.530 | forward |
| PHerc0139_20260112000000-w043_2026011217 | 0.853 | 0.575 | forward |
| PHerc0139_20260115000000-w044_2026011522 | 0.978 | 0.546 | forward |
| PHerc0139_20260126000000-w045_2026012619 | 0.881 | 0.454 | forward |
| PHerc0139_20260302000000-w039_2026030210 | 0.999 | 0.450 | forward |
| PHerc0139_20260317000000-w035_2026031718 | 0.999 | 0.512 | forward |
| PHerc0500P2_20250825181859--1 | 0.745 | 0.533 | forward |
| PHerc0814_20260226000000-46527_2um_try2 | 0.893 | 0.443 | forward |
| PHerc0841_20260220213127-w00 | 0.753 | 0.499 | forward |
| PHerc0841_20260220214732-auto_grown_2026022014 | 0.721 | 0.579 | forward |
| PHerc0841_20260221022814-auto_grown_2026022017 | 0.751 | 0.601 | forward |
| score | P1 direction correct | P2 tile AUC | P4 held-out FPR | held-out TPR |
|---|---|---|---|---|
| v3 row-profile (primary) | 6/14 | 0.502 | 0.037 | 0.056 |
| v2 red-noise | 7/14 | 0.538 | 0.060 | 0.102 |
| v1 peakness | 9/14 | 0.565 | 0.060 | 0.148 |
| anisotropy | 13/14 | 0.674 | 0.032 | 0.153 |
| mean ink | 12/14 | 0.837 | 0.097 | 0.426 |
| fraction > 0.5 | 12/14 | 0.892 | 0.069 | 0.741 |
| separation (#1867) | 14/14 | 0.856 | 0.741 | 0.824 |
P3. Published 2.4 µm prediction tiles versus their 90°-rotated copies: AUC 0.916 over 1701 tiles; 0.973 over the 535 tiles where labels confirm ink.
P5. Synthetic Greek text added to wrong-direction maps, detection rate at the calibrated threshold (1.19) by added amplitude: 0: 5% · 0.02: 6% · 0.05: 8% · 0.1: 17% · 0.2: 27% · 0.4: 31%. Real text contrast in the text-direction maps (labelled ink minus supervised non-ink): median 0.281.
P6. Of 12 clean search fields on PHerc1203 and PHerc0846A, 0 pass the calibrated test after Benjamini–Hochberg at q = 0.10.
Exploratory, not pre-registered. Labels cover only 1–13% of each segment, so most "text-direction" tiles hold no text. Restricted to the 56 tiles where labels confirm ink, v3 still reaches only AUC 0.568 against all 216 wrong-direction tiles, and flags 5% of them at a 5% false-positive rate. Injection agrees: synthetic lines on top of real 9 µm output are detected only when they are stronger than real ink. The most line-like wrong-direction tiles are plain blob noise, not text from the next winding.
Reading the result. The score recognises lines in crisp maps (P3) but not in 9 µm outputs, where ink comes out as millimetre blobs. Any label-free text test on 9 µm maps needs more than three line periods per tile, or a sharper ink model. For choosing the depth direction, use the separation rule: it was right on every segment here.
6 · PilotCan the text score rank checkpoints without labels?
Villa #1867 found that in-distribution validation does not rank ink_9um checkpoints on a held-out scroll. If a label-free score did, it would help choose a checkpoint for an unread scroll. Test: all 14 ink_9um checkpoints, both depth directions, on the 9.366 µm volume of PHerc0841 w00 (40 × 45 mm), scored against the organisers' labels.
Across 14 checkpoints (forward direction, AUC 0.703 to 0.822), the rank correlation with label AUC is +0.00 for the text score and +0.01 for the separation rule from villa #1867. Picking the depth direction: text score right in 11 of 14 checkpoints, separation rule in 14 of 14.
| checkpoint | AUC (labels) | text score | separation |
|---|---|---|---|
| seed43/step-050000 | 0.822 | +0.48 | 0.277 |
| seed43/step-020000 | 0.779 | +0.36 | 0.264 |
| seed43/step-075000 | 0.773 | +0.51 | 0.299 |
| seed42/step-030000 | 0.771 | +0.97 | 0.236 |
| seed42/step-010000 | 0.767 | +0.71 | 0.201 |
| seed42/step-020000 | 0.766 | +0.16 | 0.251 |
| seed42/step-040000 | 0.762 | +0.07 | 0.263 |
| seed42/step-060000 | 0.759 | +0.23 | 0.290 |
| seed42/step-075000 | 0.748 | +0.16 | 0.297 |
| seed42/step-050000 | 0.747 | -0.07 | 0.284 |
| seed43/step-060000 | 0.740 | +0.39 | 0.280 |
| seed43/step-040000 | 0.718 | +0.64 | 0.280 |
| seed43/step-010000 | 0.717 | +0.41 | 0.202 |
| seed43/step-030000 | 0.703 | +0.98 | 0.259 |
7 · ReuseWhat is in the repository
Clone github.com/mletic/vesuvius-meshfree-ink, run make env once (pinned model environment and weights), then make benchmark and make report. The plan and every deviation are in PREREG.md; raw scores in results/.
uv run python -m vesuvius_sweep.grow PHerc0841 1984 3997 3553 --size 512 --hires --layers 65 # 2.4 µm surface volume, no mesh uv run python scripts/search/triage.py PHerc0846A --n-z 9 --spacing 550 --max 40 # seed, grow, ink, score, guard uv run python scripts/text_line_score.py INK.tif --um 2.4 --out heat.png # text score on any ink map uv run python scripts/experiments/orientation_sensitivity.py 9um # 8 orientations × 2 depth orders vs labels uv run python scripts/experiments/audit_orientation.py # scroll-axis direction of every mesh uv run python scripts/benchmark/ckpt_rank.py # checkpoint-ranking pilot