SharpMeow commited on
Commit
c5e217e
路
verified 路
1 Parent(s): fc41ae9

How-to guides with pictures; legend and title fixes

Browse files
Files changed (3) hide show
  1. .gitattributes +1 -0
  2. app.py +76 -26
  3. media/howto-slices.gif +3 -0
.gitattributes CHANGED
@@ -50,3 +50,4 @@ assets/PHerc0841-xz.webp filter=lfs diff=lfs merge=lfs -text
50
  assets/PHerc0846A-xz.webp filter=lfs diff=lfs merge=lfs -text
51
  assets/PHerc0846B-xz.webp filter=lfs diff=lfs merge=lfs -text
52
  media/example-result.png filter=lfs diff=lfs merge=lfs -text
 
 
50
  assets/PHerc0846A-xz.webp filter=lfs diff=lfs merge=lfs -text
51
  assets/PHerc0846B-xz.webp filter=lfs diff=lfs merge=lfs -text
52
  media/example-result.png filter=lfs diff=lfs merge=lfs -text
53
+ media/howto-slices.gif filter=lfs diff=lfs merge=lfs -text
app.py CHANGED
@@ -324,7 +324,7 @@ def make_field(volume: str, z: float, y: float, x: float, size: float = 256, mod
324
  with one_run(request):
325
  r = run_field(p, progress)
326
  c = p["centre_level0_zyx"]
327
- pic = L.compose(r["pictures"], f"{p['sample']} 路 {p['size_zyx'][0]}鲁 box at z {c[0]}, y {c[1]}, x {c[2]}")
328
  return pic, r["receipt"], r["zip"]
329
 
330
 
@@ -346,29 +346,74 @@ field. Each will be marked here with what it was tested on.
346
  """
347
 
348
  HOW_TO = """\
349
- ### 1. Make your first field (one minute)
 
 
 
350
 
351
- 1. Open **Make a field**. It starts on an example point in PHerc0139; other examples are in the list under the point.
352
- 2. Press **Make the field**. The Space reads about 450 MB of CT from the open data, then runs villa's model
353
- on the GPU for about half a minute.
354
- 3. Look at the three rows: the middle slice of your box along z, y and x. Each row shows the CT, then **cos**
355
- (bright and dark bands, one pair per papyrus layer), **grad_mag** (how sharply cos changes) and the
356
- **normal** as colour (red for x, green for y, blue for z: which way the sheet faces).
357
- 4. Read the check under the picture. The same box should agree with the open data's own field far better than
358
- the control, which is the published field read a few layers away.
359
 
360
- ### 2. Pick your own point
 
 
 
361
 
362
- 1. Open the scan in the [Vesuvius Challenge data browser](https://scrollprize.org/data_browser/) or in VC3D and note
363
- a point inside the papyrus, in full-resolution (level 0) voxels: z, then y, then x.
364
- 2. Choose the same scan here (the 14-digit volume id is in the scan's folder name) and type the point.
365
- 3. Choose 256 (about 2.4 mm a side at 9.4 um voxels) or 512 (four times the time, eight times the volume).
366
- 4. The line under the size says how much CT it reads, how many model tiles it runs and how much GPU time it asks.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
367
 
368
  Boxes are whole 256-voxel blocks of the scan, because villa writes the field in 64-voxel chunks of its quarter
369
- grid; that is also why a box's field matches the one villa makes for the whole scan.
 
370
 
371
- ### 3. Use the download
 
 
 
 
 
 
 
 
372
 
373
  ```bash
374
  unzip PHerc0139-*.zip -d box && cd box
@@ -376,17 +421,17 @@ python - <<'EOF'
376
  import numpy as np, json
377
  f = np.load("field.npz"); r = json.load(open("receipt.json"))
378
  print({k: f[k].shape for k in f}, r["boxes"])
 
379
  EOF
380
  ```
381
 
382
- `villa/` is villa's own output folder: point lasagna's fit at `villa/*.lasagna.json` as you would a published run.
383
- Its arrays have the whole scan's shape in level-0 coordinates, with only your box written.
384
-
385
- ### 4. Call it from Python or an agent
386
 
387
- See **Agents and API**: the same four calls as the page, from `gradio_client`, plain HTTP, or any MCP client.
 
 
388
 
389
- ### 5. Run it yourself, for big regions or whole scans
390
 
391
  The Space is for boxes. For a whole scan, run villa's lasagna on a GPU of your own or a cloud job:
392
 
@@ -400,11 +445,11 @@ python scripts/bootstrap_venv.py --venv .venv
400
  Measured on an NVIDIA L4 (25 Oct 2026): about 2 million voxels a second end to end, so about ten minutes per
401
  cubic centimetre at 9.4 um. It fits in 5.6 GB of GPU memory at its default tile, 2.3 GB at `--tile-size 128`.
402
 
403
- ### When something goes wrong
404
 
405
  | What you see | What to do |
406
  | --- | --- |
407
- | "ZeroGPU refused this run" | Your daily ZeroGPU time is used up. Sign in to Hugging Face for more, or come back tomorrow. |
408
  | "the field is empty" | The box is outside the scroll, where the masked CT is all zero. Move the point toward the papyrus. |
409
  | "the point is outside the scan" | The point is past the scan's level-0 shape; check you used level-0 voxels, not a coarser level. |
410
  | "not a volume in the open data" | Use the 14-digit volume id (list it with `list_scans`). |
@@ -454,6 +499,11 @@ CSS = """
454
  .lf-credit { text-align:center; font-size:13px; color: var(--body-text-color-subdued); padding:18px 0 6px; }
455
  .lf-credit a { color: var(--lf-accent) !important; padding:0 !important; margin:0 !important; }
456
  .lf-howto img { border-radius:10px; border:1px solid var(--border-color-primary); max-width:100%; }
 
 
 
 
 
457
  @media (max-width: 640px) {
458
  .lf-head h1 { font-size:24px; }
459
  .lf-head span { display:none; }
 
324
  with one_run(request):
325
  r = run_field(p, progress)
326
  c = p["centre_level0_zyx"]
327
+ pic = L.compose(r["pictures"], f"{p['sample']} 路 {p['size_zyx'][0]}-voxel box at z {c[0]}, y {c[1]}, x {c[2]}")
328
  return pic, r["receipt"], r["zip"]
329
 
330
 
 
346
  """
347
 
348
  HOW_TO = """\
349
+ <p class="lf-toc">Guides: <a href="#what">What a lasagna field is</a> 路 <a href="#first">Make your first field</a> 路
350
+ <a href="#read">Read the result</a> 路 <a href="#point">Pick your own point</a> 路 <a href="#download">Use the
351
+ download</a> 路 <a href="#agents">Call it from code or an agent</a> 路 <a href="#yourself">Run it yourself</a> 路
352
+ <a href="#wrong">When something goes wrong</a></p>
353
 
354
+ <h3 id="what">What a lasagna field is</h3>
 
 
 
 
 
 
 
355
 
356
+ A scroll's CT shows papyrus layers rolled and squashed together. villa's lasagna model turns the CT into a smooth
357
+ field that surface tools can follow: **cos** goes once from bright to dark and back per papyrus layer, so counting
358
+ bands counts layers; **grad_mag** says how sharply cos changes (how tightly the layers are packed); the **normal**
359
+ says which way the sheet faces at each point. villa's lasagna surface fit and the spiral fit read these channels.
360
 
361
+ ![The CT of one box of PHerc0139 next to villa's lasagna field, stepping through the box](/gradio_api/file=media/howto-slices.gif)
362
+
363
+ *PHerc0139 (not on any prize list), one box about 2.5 mm a side: the CT, cos and the normal as colour, stepping
364
+ through z. Model output: geometry, not a reading of any text.*
365
+
366
+ <h3 id="first">1. Make your first field (one minute)</h3>
367
+
368
+ 1. Open **Make a field**. It starts on an example point in PHerc0139; more examples are in the first list.
369
+ 2. Press **Make the field**. The Space reads about 450 MB of CT from the open data, then runs villa's model on the
370
+ GPU for about 20 seconds. The first run after the Space wakes up also loads the model (about a minute).
371
+ 3. The picture, the check and the download appear on the right.
372
+
373
+ ![Making a field on this page: press the button, wait about half a minute, read the check](/gradio_api/file=media/howto-make.gif)
374
+
375
+ <h3 id="read">2. Read the result</h3>
376
+
377
+ ![A result: three rows of slices, each row CT, cos, grad_mag and normal](/gradio_api/file=media/example-result.png)
378
+
379
+ - **Rows** are the middle slice of your box along z, y and x. **Columns** are the CT, cos, grad_mag and the
380
+ normal as colour (red for x, green for y, blue for z).
381
+ - **cos** should run along the papyrus in the CT, one bright and one dark band per layer. Where layers touch or
382
+ the CT is unclear, the bands bend or merge: that is where surface tracing is hard too.
383
+ - **The check** compares your field with the published one for the same box, and with a **control**: the same
384
+ published field read 48 voxels away. A correct run gives cos r = 1.0 and grad_mag r = 1.0 for the same box and
385
+ near 0 for the control.
386
+ - **Normals** are compared where the layer signal is strong; where it is weak the normal is barely defined. On the
387
+ open data's fields they can differ in parts of a box, because villa changed how lasagna estimates normals after
388
+ those fields were made (April 2026, by their run names). This Space runs the later code, the same as its ten
389
+ whole-scan fields; on PHerc0175A it matched that field on 99.9% of voxels, with a median normal angle of 0掳.
390
+
391
+ ![The check under a result](/gradio_api/file=media/howto-check.png)
392
+
393
+ <h3 id="point">3. Pick your own point</h3>
394
+
395
+ 1. Find a point inside the papyrus in the [Vesuvius Challenge data browser](https://scrollprize.org/data_browser/),
396
+ VC3D or neuroglancer, in full-resolution (level 0) voxels: z, then y, then x.
397
+ 2. Choose the same scan in **Scan**: type part of the scroll name or the 14-digit volume id to filter the list.
398
+ 3. Type the point. The line under the button says the box it will make, how much CT it reads, how many model
399
+ tiles it runs and how much GPU time it asks.
400
+ 4. Choose **256** (about 2.5 mm a side at 9.4 um) or **512** (eight times the volume, about a minute of GPU).
401
+
402
+ ![Choosing a scan, a point and a box size](/gradio_api/file=media/howto-point.png)
403
 
404
  Boxes are whole 256-voxel blocks of the scan, because villa writes the field in 64-voxel chunks of its quarter
405
+ grid and puts its tiles on one lattice over the whole scan: that is why a box's field is the whole-scan field
406
+ there. The box is the block nearest your point, so your point is inside it but not always at its centre.
407
 
408
+ <h3 id="download">4. Use the download</h3>
409
+
410
+ The zip holds three things:
411
+
412
+ | Item | What it is | Open it with |
413
+ | --- | --- | --- |
414
+ | `villa/` | villa's own output folder: `*.lasagna.json` and four OME-Zarr channels, in the scan's coordinates with only your box written | lasagna's fit, as you would a published run |
415
+ | `field.npz` | the box's four arrays (cos at half, the others at a quarter of the input level's grid) | numpy |
416
+ | `receipt.json` | the plan, villa commit, checkpoint hash, timings and the check | any JSON reader |
417
 
418
  ```bash
419
  unzip PHerc0139-*.zip -d box && cd box
 
421
  import numpy as np, json
422
  f = np.load("field.npz"); r = json.load(open("receipt.json"))
423
  print({k: f[k].shape for k in f}, r["boxes"])
424
+ nx, ny = (f["nx"] - 128) / 127, (f["ny"] - 128) / 127 # normals are stored as v x 127 + 128
425
  EOF
426
  ```
427
 
428
+ <h3 id="agents">5. Call it from code or an agent</h3>
 
 
 
429
 
430
+ The page is also an API and an MCP server. See **Agents and API** for the calls, a Python example and the MCP
431
+ address. An agent can list the scans, plan a box without running it, then make it, and read the check from the
432
+ receipt. Each field uses the caller's own ZeroGPU time.
433
 
434
+ <h3 id="yourself">6. Run it yourself, for big regions or whole scans</h3>
435
 
436
  The Space is for boxes. For a whole scan, run villa's lasagna on a GPU of your own or a cloud job:
437
 
 
445
  Measured on an NVIDIA L4 (25 Oct 2026): about 2 million voxels a second end to end, so about ten minutes per
446
  cubic centimetre at 9.4 um. It fits in 5.6 GB of GPU memory at its default tile, 2.3 GB at `--tile-size 128`.
447
 
448
+ <h3 id="wrong">When something goes wrong</h3>
449
 
450
  | What you see | What to do |
451
  | --- | --- |
452
+ | "ZeroGPU refused this run" | Your ZeroGPU time or runs are used up; visitors who are not signed in get very little. Sign in to Hugging Face for more, or come back tomorrow. |
453
  | "the field is empty" | The box is outside the scroll, where the masked CT is all zero. Move the point toward the papyrus. |
454
  | "the point is outside the scan" | The point is past the scan's level-0 shape; check you used level-0 voxels, not a coarser level. |
455
  | "not a volume in the open data" | Use the 14-digit volume id (list it with `list_scans`). |
 
499
  .lf-credit { text-align:center; font-size:13px; color: var(--body-text-color-subdued); padding:18px 0 6px; }
500
  .lf-credit a { color: var(--lf-accent) !important; padding:0 !important; margin:0 !important; }
501
  .lf-howto img { border-radius:10px; border:1px solid var(--border-color-primary); max-width:100%; }
502
+ .lf-howto { max-width: 920px; }
503
+ .lf-howto h3 { scroll-margin-top: 16px; margin-top: 1.6em !important; }
504
+ .lf-howto em { color: var(--body-text-color-subdued); font-size: 13.5px; }
505
+ .lf-toc { font-size: 14px; line-height: 1.9; padding: 10px 14px; border-radius: 10px;
506
+ background: var(--block-background-fill); border: 1px solid var(--border-color-primary); }
507
  @media (max-width: 640px) {
508
  .lf-head h1 { font-size:24px; }
509
  .lf-head span { display:none; }
media/howto-slices.gif ADDED

Git LFS Details

  • SHA256: 189fd5fa02638691e8816d11a24a9ce24e1db0b20030e9a00b1273c3811c84a7
  • Pointer size: 132 Bytes
  • Size of remote file: 2.51 MB