Skip to content

Several rays per detector cell (MultiRay) - #11

Open
nHackel wants to merge 5 commits into
mainfrom
nh/multiray
Open

nHackel wants to merge 5 commits into
mainfrom
nh/multiray

Conversation

@nHackel

@nHackel nHackel commented Nov 3, 2026

Copy link
Copy Markdown
Member

Ray-driven projectors trace one line per detector cell, through its center. When detector cells are large compared to the voxels, these lines miss voxels between them. The back projection then covers the image unevenly, and reconstructions show patterns from the sampling. This PR adds MultiRay, a geometry wrapper that traces several rays per cell and averages their line integrals.

g = MultiRay(circular_cone_beam(...), JitteredPoints(2, 2; seed=1); weights=GaussianWeights(0.4))
op = JosephProjector(image, g)

What's included

  • MultiRay(geometry, points; weights) for ConeBeam, ArcConeBeam and ParallelBeam.
    • The data keep their size. The projection of a cell is the weighted mean of its rays' line integrals; the back projection is the exact adjoint.
    • It works with Siddon and Joseph, on every device, with masks, subset and adapt.
  • Point strategies (positions in cell units, with the cell center at 0 and the edges at ±½):
    • RegularPoints(su, sv): the subcell centers.
    • JitteredPoints(su, sv; seed): each regular point moved randomly within its subcell (Cook 1986).
    • RandomPoints(n; seed).
    • Points(offsets).
  • Weighting strategies: UniformWeights, GaussianWeights(σu, σv). The weights are normalized per cell.
  • cell_ray(g, cu, cv, k): the ray that ends at any position on the detector, in cell units. On arc detectors the position is an angle about the source, so the rays sample the curved cell.
  • Random positions without a random number generator: the hash pcg4d (Jarzynski & Olano 2020) of cell, view, ray and seed. It's ported from the authors' MIT-licensed HLSL, with their notice in src/geometry/pcg4d.jl.
    • The positions are identical in the forward and back projection, on every device and across calls, so the operator is a fixed matrix.
    • Subsets keep the original view numbers, so their rows are those of the full operator.
  • 2D images: the projectors keep the rays in the image plane (offsets along u only). Without this, rays would leave the single voxel layer, and Joseph would interpolate it down.
  • Implementation: the number of rays per cell is a type parameter. The kernels are unchanged: a per-element function dispatches on the geometry and loops over the rays. A MultiRay has no ray(g, i), so projectors that trace only one ray per cell reject it instead of ignoring the extra rays.

nHackel and others added 5 commits November 3, 2026 21:46
cell_ray(g, cu, cv, k) gives the ray of view k that ends at position (cu, cv) on the detector, in
cell units (integers are cell centers, half-integers cell edges), for cone beams with flat and arc
detectors and parallel beams; ray(g, i) is the case of the cell center.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One page each for images, projection geometries, operators (with masks, launch configuration and
extensions), projectors and internals, instead of a single page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MultiRay wraps a detector geometry with a point strategy (RegularPoints, JitteredPoints,
RandomPoints, Points) and a weighting strategy (UniformWeights, GaussianWeights); Siddon and Joseph
average the line integrals of the rays of each cell with normalized weights, with the exact
adjoint. The number of rays per cell is a type parameter, so one ray per cell compiles to the plain
projector. Random positions come from the hash pcg4d of Jarzynski & Olano (ported under its MIT
license) of cell, view, ray and seed: the same in forward and back projection, on every device and
in subsets. For 2D images the projectors keep the rays in the image plane.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The types for the in-plane rule sat between the docstring and the struct, so the docstring
documented FullCell instead of MultiRay.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
How-to "Use Several Rays per Cell" (the sampling problem of one ray per cell on a 2D example,
positions on the detector, MultiRay with regular and jittered points) and explanation "Several
Rays per Cell" (model, point and weighting strategies, random positions from a hash, 2D images,
implementation), linked from the home page and Siddon's page; GPU timings in the benchmark README.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codecov

codecov Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.77419% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 96.62%. Comparing base (e068fa2) to head (7dff5f2).

Files with missing lines Patch % Lines
src/geometry/multiray.jl 95.55% 4 Missing ⚠️
src/operators/launch.jl 50.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #11      +/-   ##
==========================================
+ Coverage   96.30%   96.62%   +0.31%     
==========================================
  Files          19       22       +3     
  Lines         542      682     +140     
==========================================
+ Hits          522      659     +137     
- Misses         20       23       +3     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

This branch has not been deployed

No deployments
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