Chapter 13Rev. 1.0.0

Choosing the next view and where to spend the photons

Some measurements constrain the quantity we care about more than others. We use local uncertainty to compare feasible views and examine how exposure can be allocated to the task.

A registration can fit its first X-ray closely while leaving the object free to move along a poorly observed direction. Another image might resolve that uncertainty. Taking almost the same view again mostly provides more photons along directions already measured. Moving the C-arm incurs its own costs, and the angle with the prettiest derivative image may be physically inaccessible. We need to predict which feasible measurement will reduce uncertainty in the task we care about.

We will choose one additional view of the known attenuation volume used in Chapter 11, generate that view’s observation and fit the updated pose. The worked example completes the entire sequence. Across eight prescribed Poisson noise pairs, its selected view reduces mean squared target error by 71% against a nearly repeated 5° view at the same exposure. Every base and final fit reaches the numerical stopping tolerance and passes independent geometric and reserved-view checks. The complete recipe supplies the admitted CT-derived input and connects the canonical dpt.examples.acquisition_design selector to observation generation and registration.

The forward model and pose convention come from Chapter 11. Chapter 12 supplies the harder extension in which the unknown is a volume. We will keep track of the information available before each decision, because a policy that has already seen tomorrow’s X-ray tends to perform suspiciously well.

13.1 Define the task and the information available

Suppose the current data are Y0\mathcal{Y}_0 and the next acquisition is described by aa: its source and detector geometry together with calibrated exposure settings. A decision rule can use the known volume, Y0\mathcal{Y}_0, the current pose estimate and a declared uncertainty model. It may render hypothetical measurements at candidate acquisitions. It cannot use their future measured pixel values.

For registration, the quantity of interest need not be an equally weighted combination of translation and rotation. A small rotation produces a larger displacement at a distant surgical target than near the rotation centre. We therefore supply object-frame target points and score their predicted world-coordinate variance. These points describe the task using anatomy already available to the policy. Withheld reference transformations are used later to measure error.

A fixed design chooses the entire sequence before seeing any new measurements. A sequential design chooses the next acquisition, receives its observation, updates the estimate and chooses again. The executable example implements one decision in the latter sequence. Its supplied current precision must describe uncertainty at that decision, including previous measurements exactly once. Adding their information again would reward the policy for counting its homework twice.

Figure 13.1 separates these inputs from the withheld evaluation reference. The same separation belongs in the file layout: the design case contains calibrated candidate predictions and the current state, while the later evaluation record supplies the selected measured image and independent reference.

Known registration volumeAttenuation and object-frame task targets
Current observationsY0\mathcal Y_0Images already acquired
Current pose and uncertaintyG^WO, Λ0\widehat{\mathbf G}_{WO},\ \boldsymbol\Lambda_0One declared local chart
Candidate acquisitionsCalibrated geometry, exposure, budget and assessed feasibility
Compute hypothetical predictionsλa, JL,a, Ia\boldsymbol\lambda_a,\ \mathbf J_{L,a},\ \mathbf I_aCompute each against the same current state
Score permitted candidates and record the choicea=argminaAΦ(a)a^\star=\operatorname*{argmin}_{a\in\mathcal A}\Phi(a)Predicted target-position variance
Decision recorded
Acquire the selected viewya\mathbf y_{a^\star}Its measured pixels now become available.
Update registrationUse the additional observation for the next decision.
Evaluate against an independent referenceUse withheld reference poses to measure achieved target error.Evaluation only · no input to candidate scoring
Figure 13.1What an acquisition policy is allowed to knowThe policy scores candidate views from the known volume and current estimate, then acquires the chosen view. Keeping future observations and reference poses out of scoring makes the later error an independent test of the decision.

13.2 Choose a task-specific design objective

Keep the pose chart fixed while comparing candidates. At the current transform G^WO\widehat{\mathbf G}_{WO}, use dimensionless coordinates z\mathbf z with positive diagonal scale matrix S\mathbf S:

GWO(z)=G^WOexp ⁣((Sz)).\mathbf G_{WO}(\mathbf z)=\widehat{\mathbf G}_{WO}\exp\!\left((\mathbf S\mathbf z)^\wedge\right).
(13.1)

The first three entries of S\mathbf S set translation scales in millimetres, and the remaining entries set rotation scales in radians. All derivatives in this section are evaluated at z=0\mathbf z=\mathbf 0. Equation (13.1) is a local right update. A precision matrix expressed in another frame, at another chart centre or with different scales must be transformed before use.

For candidate aa, assume conditionally independent ideal counts Na,pPoisson(λa,p(z))N_{a,p}\sim\operatorname{Poisson}(\lambda_{a,p}(\mathbf z)). At positive means, the score contribution is (Na,p/λa,p1)zλa,p(N_{a,p}/\lambda_{a,p}-1)\nabla_{\mathbf z}\lambda_{a,p}. Its expectation is zero and its variance uses Var(Na,p)=λa,p\operatorname{Var}(N_{a,p})=\lambda_{a,p}. Independence removes cross-pixel score covariances, giving the expected Fisher information

Ia=p1λa,p(zλa,p)(zλa,p)T.\mathbf I_a=\sum_p\frac{1}{\lambda_{a,p}}\left(\nabla_{\mathbf z}\lambda_{a,p}\right)\left(\nabla_{\mathbf z}\lambda_{a,p}\right)^{\mathsf T}.
(13.2)

A large image derivative contributes little useful information if its noise is large or if it repeats an already well-observed parameter direction. For the primary model, let La,pL_{a,p} be the canonical optical depth and n0,a,pn_{0,a,p} the fixed open-beam expectation. Since λa,p=n0,a,pexp(La,p)\lambda_{a,p}=n_{0,a,p}\exp(-L_{a,p}), equation (13.2) becomes

Ia=JL,aTdiag(λa)JL,a=BaTBa,Ba=diag(λa)JL,a,\mathbf I_a=\mathbf J_{L,a}^{\mathsf T}\operatorname{diag}(\boldsymbol\lambda_a)\mathbf J_{L,a} =\mathbf B_a^{\mathsf T}\mathbf B_a, \qquad \mathbf B_a=\operatorname{diag}(\sqrt{\boldsymbol\lambda_a})\mathbf J_{L,a},
(13.3)

where JL,a\mathbf J_{L,a} has one row La,p/z\partial L_{a,p}/\partial\mathbf z per pixel. This form avoids dividing by a count prediction that may round to zero. A genuinely zero supplied beam contributes zero information: no image of the object arrives along that ray. Correlated read noise, energy integration and shared calibration errors require their own likelihood. Independent Poisson weighting does not become appropriate merely because an image came from an X-ray detector.

Let the current pose distribution be approximated locally by a Gaussian with positive-definite precision Λ0\boldsymbol\Lambda_0 in this same chart. Adding expected information gives

Ca(Λ0+Ia)1.\mathbf C_a\approx(\boldsymbol\Lambda_0+\mathbf I_a)^{-1}.
(13.4)

Equation (13.4) predicts local covariance using expected likelihood curvature. It is neither an exact posterior covariance for every possible future image nor a guarantee that the registration solver will find the intended pose. The current uncertainty can already include earlier acquisitions. A numerical damping matrix inserted into an optimiser is not automatically a defensible Λ0\boldsymbol\Lambda_0.

For an object-frame target xq\mathbf x_q, differentiating its world position under equation (13.1) gives

Hq=R^WO[I3[xq]×]S,Cq,aHqCaHqT.\mathbf H_q=\widehat{\mathbf R}_{WO}\begin{bmatrix}\mathbf I_3&-[\mathbf x_q]_\times\end{bmatrix}\mathbf S, \qquad \mathbf C_{q,a}\approx\mathbf H_q\mathbf C_a\mathbf H_q^{\mathsf T}.
(13.5)

Here [xq]×v=xq×v[\mathbf x_q]_\times\mathbf v=\mathbf x_q\times\mathbf v. The translation part of Hq\mathbf H_q moves every target alike, while its rotation part retains the distance and direction from the object origin. Averaging target-position variance gives the scalar criterion

Φ(a)=1Qq=1Qtr(Cq,a).\Phi(a)=\frac{1}{Q}\sum_{q=1}^{Q}\operatorname{tr}(\mathbf C_{q,a}).
(13.6)

Its units are square millimetres. This predicts spread, not squared error including unknown bias. Listing 13.1 computes the target derivatives and scores this criterion through Cholesky solves. The scorer requires strictly positive-definite current precision and reports an error when that assumption fails. It adds no identity matrix to supply missing precision.

Target-position variance in the scaled pose chartpython/dpt/examples/acquisition_design.pyL67–119
def target_jacobians(np: Any, pose: RigidTransform, targets: Any, scales: Any) -> Any:
    """Return d(world target)/dz in mm for T_WO exp((S z)^) at z=0."""
    rotation = np.asarray(pose.rotation, dtype=np.float64).reshape(3, 3)
    result = np.empty((len(targets), 3, 6), dtype=np.float64)
    for index, (x, y, z) in enumerate(targets):
        skew = np.asarray([[0.0, -z, y], [z, 0.0, -x], [-y, x, 0.0]])
        result[index, :, :3] = rotation
        result[index, :, 3:] = -rotation @ skew
    result *= scales[None, None, :]
    if not np.isfinite(result).all():
        raise NumericalError("target derivatives exceed FP64; check target coordinates and scales")
    return result


def target_variance(
    np: Any, precision: Any, target_jacobian: Any, maximum_condition: float
) -> tuple[float, Any, float]:
    """Mean target-position variance in mm², without forming an inverse to score."""
    if not np.isfinite(precision).all():
        raise NumericalError("pose precision is non-finite; discard this candidate score")
    values = np.linalg.eigvalsh(precision)
    if values[0] <= 0 or values[-1] / values[0] > maximum_condition:
        raise NumericalError(
            "pose precision must be positive definite and within maximum_precision_condition; "
            "check the stated uncertainty and parameter scales, without adding numerical jitter"
        )
    factor = np.linalg.cholesky(precision)
    right = target_jacobian.reshape(-1, 6).T
    whitened = np.linalg.solve(factor, right)
    if not np.isfinite(whitened).all():
        raise NumericalError(
            "target covariance solve exceeds FP64; check the precision and chart scales"
        )
    # hypot scales its sum of squares; individual products must not underflow
    # before they contribute to an otherwise representable total variance.
    normalisation = math.sqrt(len(target_jacobian))
    root_variance = math.hypot(*(float(value) / normalisation for value in whitened.flat))
    variance = root_variance * root_variance
    if not math.isfinite(variance) or variance <= 0:
        raise NumericalError(
            "positive target-position variance is outside FP64 range; check the stated "
            "uncertainty and physical units, or use a range-preserving score representation"
        )
    inverse_factor = np.linalg.solve(factor, np.eye(6))
    covariance = inverse_factor.T @ inverse_factor
    if not np.isfinite(covariance).all() or bool((np.diag(covariance) <= 0).any()):
        raise NumericalError(
            "local covariance is outside FP64 range; check the precision and chart scales "
            "before exporting this candidate"
        )
    return variance, covariance, float(values[-1] / values[0])

Nuisance parameters can substantially change the ranking. If η\boldsymbol\eta describes uncertain calibration and the joint precision is partitioned into pose and nuisance blocks, the marginal pose precision is the Schur complement ΛzzΛzηΛηη1Ληz\boldsymbol\Lambda_{zz}-\boldsymbol\Lambda_{z\eta}\boldsymbol\Lambda_{\eta\eta}^{-1}\boldsymbol\Lambda_{\eta z}, assuming the required positive definiteness. Holding nuisance parameters fixed instead uses the pose block directly and can understate uncertainty. Our example makes that restriction explicit: acquisition calibration and attenuation are fixed, and only pose is uncertain.

13.3 Separate candidate selection from continuous optimisation

For a finite eligible set A\mathcal A, the decision is simply a=argminaAΦ(a)a^\star=\operatorname{argmin}_{a\in\mathcal A}\Phi(a). Score every candidate against the same current precision, pose and targets. Do not update the current precision after scoring a hypothetical candidate, because that would make the answer depend on enumeration order. Exact score ties in the example prefer lower cost, then the candidate name.

Finite enumeration needs derivatives with respect to pose at each fixed geometry. The library already exports these. Continuous optimisation of source position or detector orientation is a different implementation task: differentiating Ia\mathbf I_a with respect to aa generally needs derivatives of both the mean and its pose Jacobian, including mixed pose–acquisition derivatives. The current projector supplies neither acquisition-geometry adjoints nor higher derivatives. Repeated calls to an existing first-order VJP do not establish either capability.

A criterion that includes a reconstruction solve adds another dependency. Differentiating a fixed number of solver iterations gives a derivative of that algorithm. Implicit differentiation instead uses an equation characterising the solution and requires appropriate local uniqueness, regularity and convergence. These quantities need not agree for an unfinished solve or at an active-set change. Holding the current estimate fixed does not differentiate its dependence on the acquisition. Record that approximation explicitly.

13.4 Restrict choices to feasible acquisitions

The candidate set should come from an imaging-system specification. Source and detector positions must respect working distance, angular travel and detector coverage. A reachable endpoint can still require a motion path that collides with equipment. Exposure settings may be discrete, and moving to a candidate may consume more time than taking its image. Geometry and movement costs therefore belong to each candidate record.

The example accepts candidates already assessed for feasibility and requires a description of that assessment. It checks the supplied ray geometry and a scalar acquisition budget, but it does not perform collision detection or certify a motion path. Figure 13.2 shows an illustrative endpoint constraint with excluded configurations marked separately. A high information score cannot disguise an unusable view.

A candidate’s open-beam array specifies the detector-incident expectation under that candidate’s calibrated source setting. If source motion changes distance or coverage, reusing the previous array without recalibration changes the assumed experiment. The JSON case binds every supplied array to its units, source hash and redistribution rights. For a cost expressed as expected detector photons, the code checks that the stated cost equals the open-beam sum in the absence of the object. This budget differs from the transmitted count sum.

The white C-arm model at an illustrative angle of +60 degrees. The source and detector are 353.72 and 348.28 millimetres from O. Coloured arcs trace detector positions classified by source clearance. Labels locate the source, detector, isocentre, rest-source point c, angle and the source-clearance disk of radius 176.86 millimetres.
  • Allowed detector endpoint
  • Source-clearance exclusion
  • Outside candidate domain

At +60°: source clearance 353.72 mm, detector configuration allowed.

s=Rsu,d=Rdu\mathbf s=R_s\mathbf u,\quad\mathbf d=-R_d\mathbf urelative to O, with u=cosαe0+sinαe1\mathbf u=\cos\alpha\,\mathbf e_0+\sin\alpha\,\mathbf e_1.

scRs/2,c=Rse0\|\mathbf s-\mathbf c\|\geq R_s/2,\quad\mathbf c=R_s\mathbf e_0Allowed: arccos(7/8)απ/2\arccos(7/8)\leq|\alpha|\leq\pi/2.

Model-world distances: Rs=353.72mmR_s=353.72\,\mathrm{mm},Rd=348.28mmR_d=348.28\,\mathrm{mm}. e0=(0,1,0), e1=(1,0,0)\mathbf e_0=(0,-1,0),\ \mathbf e_1=(1,0,0). The ±90° candidate domain and point-clearance disk are illustrative. They do not specify device travel or a collision-free path.

Use the angle slider to inspect the endpoint constraint. Camera orbiting changes only the view.
Figure 13.2Useful views within the feasible acquisition setColoured arcs separate C-arm detector positions by whether the corresponding source clears the disk. Admissible views must satisfy this geometric constraint before they can be compared for information.

13.5 Choose a second view for registration

The application case provides the known attenuation field, current pose and local precision, with targets defined in object coordinates. It supplies candidate geometries and calibrated beams, but no future radiographs. The evaluator uploads the field once, uses one CUDA stream for Warp and PyTorch, and constructs each candidate’s depth Jacobian through projection_pose_sensitivities.

The exported derivative uses physical millimetres and radians. Multiplying its columns by the supplied scales converts it to JL,a\mathbf J_{L,a} in equation (13.3). On the GPU, the FP64 path forms logλ=logn0L\log\lambda=\log n_0-L directly from retained optical depth; the FP32 path uses the canonical log-transmission output. FP64 exponential weighting preserves a wider range than deriving weights from stored FP32 counts. The P×6P\times6 weighted Jacobian then reduces to a 6×66\times6 information matrix through a CUDA matrix product. Only that matrix and a few scalar diagnostics return to the host.

Listing 13.2 shows the complete candidate calculation. One candidate needs the exported Jacobian and a weighted copy, together 96P96P bytes, plus optical-depth, beam and statistical scratch. PyTorch allocates intermediate tensors during this bounded offline calculation. max_candidate_pixels bounds the retained detector-sized work, and the stream completes before its temporary owners are released.

Computing the Fisher information for one candidate viewpython/dpt/examples/acquisition_design.pyL124–248
def candidate_information(
    *,
    np: Any,
    torch: Any,
    ctx: Any,
    grid: GridSpec,
    geometry: DetectorGeometry,
    attenuation: Any,
    pose: Any,
    beam_host: Any,
    scales: Any,
    samples_per_ray: int,
    precision: Literal["float32", "float64"] = "float32",
    integration: Literal["midpoint", "cell_gauss"] = "midpoint",
) -> tuple[Any, dict[str, Any]]:
    """Use canonical depth derivatives and an FP64 CUDA Fisher reduction.

    Preparation allocates one candidate's O(6P) Jacobian and weighted copy.
    Torch views alias Warp storage on the same CUDA stream. There is no
    per-pixel Python loop and no image/Jacobian download. This is an offline
    candidate evaluation, not a captured or profiled optimisation hot path.
    """
    wp, pixels = ctx.wp, geometry.pixels
    try:
        projection = prepare_projection(
            grid,
            geometry,
            ProjectionSpec(samples_per_ray, precision=precision, integration=integration),
            device=str(ctx.device),
            stream=ctx.stream,
        )
        transmission = (
            prepare_transmission(
                TransmissionSpec(beam="none"),
                max_pixels=pixels,
                device=str(ctx.device),
                stream=ctx.stream,
            )
            if precision == "float32"
            else None
        )
        with ctx.scope():
            beam = wp.array(beam_host.reshape(-1), dtype=wp.float32, device=ctx.device)
            depth = wp.empty(pixels, dtype=projection.dtype, device=ctx.device)
            log_transmission = wp.empty(
                pixels if precision == "float32" else 0, dtype=wp.float32, device=ctx.device
            )
            ones = wp.ones(pixels, dtype=projection.dtype, device=ctx.device)
            jacobian = wp.empty(6 * pixels, dtype=wp.float64, device=ctx.device)
        project_optical_depth(
            attenuation,
            pose,
            workspace=projection,
            out_L=depth,
            stream=ctx.stream,
        )
        if transmission is not None:
            transmit(
                depth,
                out_log_T=log_transmission,
                workspace=transmission,
                stream=ctx.stream,
            )
        projection_pose_sensitivities(
            attenuation,
            pose,
            ones,
            out_jacobian=jacobian,
            workspace=projection,
            stream=ctx.stream,
        )
        beam_tensor = wp.to_torch(beam)
        log_mean = beam_tensor.to(dtype=torch.float64).log_()
        if precision == "float64":
            log_mean.sub_(wp.to_torch(depth))
        else:
            log_mean.add_(wp.to_torch(log_transmission))
        illuminated = beam_tensor > 0
        # A zero supplied beam carries no information. Positive means outside
        # the normal FP64 range are rejected; no tail, floor or pixel is hidden.
        log_tiny = math.log(float(np.finfo(np.float64).tiny))
        if bool((illuminated & (log_mean < log_tiny)).any().item()):
            raise NumericalError(
                "a positive candidate count mean is below normal FP64 range; "
                "use a range-preserving design implementation before ranking this case"
            )
        root_mean = log_mean.mul_(0.5).exp_()
        depth_jacobian = wp.to_torch(jacobian).reshape(pixels, 6)
        weighted = depth_jacobian.clone()
        weighted.mul_(scales).mul_(root_mean[:, None])
        if not bool(torch.isfinite(weighted).all().item()):
            raise NumericalError("weighted pose derivatives exceed FP64; discard this candidate")
        if bool(((depth_jacobian != 0) & illuminated[:, None] & (weighted == 0)).any().item()):
            raise NumericalError(
                "a nonzero weighted derivative underflowed; discard this candidate"
            )
        magnitude = weighted.abs()
        minimum = math.sqrt(float(np.finfo(np.float64).tiny))
        maximum = math.sqrt(float(np.finfo(np.float64).max) / (6.0 * pixels))
        if bool((((magnitude > 0) & (magnitude < minimum)) | (magnitude > maximum)).any().item()):
            raise NumericalError(
                "candidate Fisher products exceed the declared FP64 accumulation range; "
                "rescale the pose chart or use a range-preserving reduction"
            )
        # Weighted depth derivatives give J_L^T diag(lambda) J_L directly.
        # Avoid a division by rounded, potentially zero count predictions.
        information = weighted.T @ weighted
        result = information.cpu().numpy().copy()
        if not np.isfinite(result).all():
            raise NumericalError("candidate information is non-finite; discard this score")
        diagnostics = {
            "pixels": pixels,
            "precision": precision,
            "integration": integration,
            "zero_beam_pixels": int((~illuminated).sum().item()),
            "omitted_positive_beam_pixels": 0,
            "jacobian_and_weighted_copy_bytes": 2 * 6 * pixels * 8,
            "fisher_reduction": "FP64 CUDA; only the 6 by 6 information matrix is downloaded",
        }
        return 0.5 * (result + result.T), diagnostics
    finally:
        # Warp owners and the host beam must survive every pending shared-stream operation.
        wp.synchronize_stream(ctx.stream)

Numerical range remains part of the method. A dark pixel with a supplied zero beam contributes exactly zero. For illuminated pixels, the example rejects means below the normal FP64 range and rejects weighted derivative products outside its declared accumulation range. It adds no count floor and omits no positive-beam tail to obtain a ranking. Such a rejection calls for a more capable numerical reduction or a better-scaled chart, followed by independent verification. The actual depth and depth Jacobian remain the discretised quantities produced by the canonical projector.

Listing 13.3 adds each candidate’s information to the same current precision, computes the target criterion and records threshold-defined local Fisher rank. Rank depends on the stated tolerance and parameter scaling. A view can reduce variance along an existing direction without increasing rank, so rank alone is not the selection rule.

Choosing the view with the lowest target variancepython/dpt/examples/acquisition_design.pyL377–418
                for candidate in eligible:
                    information, diagnostics = candidate_information(
                        np=np,
                        torch=torch,
                        ctx=ctx,
                        grid=grid,
                        geometry=candidate["geometry"],
                        attenuation=attenuation,
                        pose=pose_device,
                        beam_host=candidate["beam"],
                        scales=scales_device,
                        samples_per_ray=samples,
                        precision=cfg.get("precision", "float32"),
                        integration=cfg.get("integration", "midpoint"),
                    )
                    variance, covariance, condition = target_variance(
                        np, prior + information, target_derivatives, maximum_condition
                    )
                    eigenvalues = np.linalg.eigvalsh(information)
                    largest = float(eigenvalues[-1])
                    if eigenvalues[0] < -rank_tolerance * max(largest, np.finfo(np.float64).tiny):
                        raise NumericalError(
                            "candidate Fisher matrix is indefinite beyond rank tolerance"
                        )
                    rank = int(np.count_nonzero(eigenvalues > rank_tolerance * largest))
                    rows.append(
                        {
                            "name": candidate["name"],
                            "cost": candidate["cost"],
                            "mean_target_variance_mm2": variance,
                            "local_fisher_rank": rank,
                            "posterior_precision_condition": condition,
                            "diagnostics": diagnostics,
                        }
                    )
                    matrices.append(information)
                    covariances.append(covariance)
                # Exact score ties prefer the smaller stated cost, then the name.
                selected = min(
                    rows,
                    key=lambda row: (row["mean_target_variance_mm2"], row["cost"], row["name"]),
                )

The worked sequence begins with a 0° image at an open-beam expectation of 1,000 photons per pixel. Once that base fit has converged, the selector compares 5°, 30°, 60° and 90° at the same exposure. The base view’s Fisher matrix at its accepted pose supplies Λ0\boldsymbol\Lambda_0, so the first image enters the uncertainty calculation once, before each candidate’s information is added. The calculation uses the exact cell integration and FP64 arithmetic checked in Chapter 11 for both the current information and each candidate. The task points are the eight corners with object-frame coordinates ±40 mm; the later geometric evaluation uses those very same points.

In the first noise replicate, the selector chooses 60°, with predicted mean target variance 0.001325 mm². Moving farther to 90° gives a larger value, 0.001946 mm². Angular separation alone therefore does not explain this ranking: the criterion measures how each view constrains these targets through the supplied anatomy at the current pose. After recording the choice, the driver draws its count image and refits the pose. Figure 13.3 compares that prediction with the realised errors across all eight pairs.

The first view choice

Predicted target variance (mm²) against Candidate view (degrees). Other candidates and Selected view.Predicted target variance (mm²)00.0020.0045306090Candidate view (degrees)Other candidates: 5°, 0.0041141Other candidates: 30°, 0.0018848Selected view: 60°, 0.001325Other candidates: 90°, 0.0019457
  • Other candidates
  • Selected view

All eight recovery outcomes

RMS target error (mm) against Prescribed noise replicate. Near-parallel 5° and Selected view.RMS target error (mm)00.050.101234567Prescribed noise replicateNear-parallel 5°: 0, 0.078296Near-parallel 5°: 1, 0.028378Near-parallel 5°: 2, 0.091441Near-parallel 5°: 3, 0.035864Near-parallel 5°: 4, 0.093749Near-parallel 5°: 5, 0.07674Near-parallel 5°: 6, 0.074781Near-parallel 5°: 7, 0.024429Selected view: 0, 0.021129Selected view: 1, 0.036844Selected view: 2, 0.019681Selected view: 3, 0.033086Selected view: 4, 0.05486Selected view: 5, 0.040635Selected view: 6, 0.037695Selected view: 7, 0.036188
  • Near-parallel 5°
  • Selected view

The selected view reduces mean squared target error by 71% relative to the near-parallel view. 2 of the 8 pairs have higher error after selection: the criterion predicts an average over possible count images, while each pair receives one noise realisation. This controlled example demonstrates the average benefit; it does not promise to beat every well-chosen fixed view.

Recorded result and acceptance criteria
QuantityResultCriterion
Completed solves25 / 25 stationary, geometrically accurate and reserved-view checks passedEvery prescribed solve passes
Selected mean squared target error0.0013347 mm²≤ 75% of near-parallel baseline
Near-parallel mean squared target error0.0046812 mm²Same exposure and solver
Selected / baseline0.2851≤ 0.75
Paired descriptive 95% upper bound-0.0005937 mm²Below zero
Reproduction and recorded data
Figure 13.3Choose a view, acquire its counts, check the recoveryEqual-exposure comparison on the same eight object-frame targets. The future count image is generated only after each decision is recorded.

The 5° baseline deliberately spends its second exposure on almost the same view. It makes the value of measuring a different direction visible in a small complete example. This result does not establish superiority over a well-chosen fixed orthogonal view. When the first image admits distant plausible poses, a Gaussian around one estimate can also miss those alternatives. An independently specified pose ensemble or expected information gain over a multimodal posterior would address that different approximation.

13.6 Design views for reconstruction

An attenuation volume replaces the six pose coordinates with perhaps millions of unknown coefficients. The design question still needs a task: variance of a regional average, visibility of a specified feature or reconstruction error under a declared prior ensemble. Summing uncertainty equally over all voxels can spend acquisitions on parts of the field that do not matter to that task.

A local approximation has a precision operator of the form

HaH0+JaTWaJa,\mathbf H_a\approx\mathbf H_0+\mathbf J_a^{\mathsf T}\mathbf W_a\mathbf J_a,
(13.7)

where H0\mathbf H_0 describes current local precision and Wa\mathbf W_a follows the candidate’s measurement model. A dense volume covariance would require quadratic storage. Instead, an implementation could apply precision to vectors and solve for the covariance action needed by a small set of task functionals. For a linear task q(μ)=cTμq(\boldsymbol\mu)=\mathbf c^{\mathsf T}\boldsymbol\mu, the local variance is cTHa1c\mathbf c^{\mathsf T}\mathbf H_a^{-1}\mathbf c, and a linear solve can obtain it without constructing the inverse.

Equation (13.7) describes an extension, not a capability exercised by the registration example. A matrix-free implementation needs compatible Jacobian-vector and transpose products, a declared regulariser Hessian, and independently checked solver tolerances. The available volume VJP provides the transpose action but does not by itself provide the entire design calculation. Nonnegativity constraints and changes of active set further affect a local Gaussian approximation.

Burger and colleagues develop sequential Bayesian projection design with Gaussian priors and additive Gaussian noise, including criteria based on posterior covariance and information. Their numerical study concerns two-dimensional parallel-beam tomography. It gives a concrete precedent for updating projection choices as data arrive, but the three-dimensional Poisson pose calculation here has its own likelihood and geometry. [38]

Compare reconstruction policies at the same measurement budget and include the time spent deciding which view to take. An expensive design search can be appropriate for a costly acquisition. It can also become a remarkably elaborate method of avoiding the next reconstruction. Spectral-channel choices add the calibrated response and material-identifiability conditions developed in §12.6. They cannot be ranked from geometric coverage alone.

13.7 Allocate exposure and state the budget correctly

Under a fixed spectrum and linear independent-count model, suppose a relative exposure ee scales the expected counts as λa,p(e)=eλa,p(1)\lambda_{a,p}(e)=e\lambda_{a,p}(1). The depth Jacobian stays fixed, so

Ia(e)=eIa(1).\mathbf I_a(e)=e\mathbf I_a(1).
(13.8)

Information grows linearly in this model, but the resulting target variance generally does not, because it depends on the inverse of the sum of prior and measurement information. Detector saturation, spectral changes or exposure-dependent processing invalidate the simple scaling. Each requires a forward and noise model that follows the actual control setting.

The example permits several candidate records with the same geometry and different calibrated beam/cost pairs. This evaluates discrete exposure alternatives for one next view. A multi-view allocation would instead choose exposures jointly under a total budget and per-view bounds, and would need to retain the dependence of its criterion on every allocation. Movement time can be included only when the cost is defined consistently with the current system state.

Expected detector photons, tube-current–time product in mAs and acquisition time in seconds are different budgets. None is absorbed dose. A dose-constrained extension must define whose absorbed energy per unit mass is being constrained and use a separately validated deposition model that accounts for spectrum, geometry and material. The number of Monte Carlo histories used to estimate a prediction is a computational setting, not the exposure given to a subject.

The worked comparison holds expected open-beam photons fixed and changes the second angle. It therefore demonstrates an angular decision at equal exposure. An exposure-allocation curve would need several controlled photon populations and must retain that axis label, even if “dose reduction” would fit rather nicely in the abstract.

13.8 Complete and check the acquisition sequence

Run the Chapter 11 recipe through to summary.json. After the orthogonal registration, the driver performs eight base fits and sixteen paired refits. Within each pair, selection and the 5° baseline share the same first image, so their comparison holds that image’s noise fixed. The driver records the selected angle before generating its observation. If both policies request the same future view, they receive the same observation; different acquisitions use separately keyed random streams.

Fit the first image, choose a view, generate its observation and refit the shared poseexperiments/worked-applications/run.pyL406–455
            for replicate in range(replicates):
                beam = protocol["acquisition"]["base_and_candidate_open_beam_per_pixel"]
                base_id = _observation(
                    record, public, means, protocol, 0.0, beam, 2, replicate, seed
                )
                base = _fit(
                    known_root,
                    output,
                    public,
                    protocol,
                    f"base-{replicate:02d}",
                    [base_id],
                    RigidTransform(),
                    device,
                )
                accepted = rigid(base["pose_object_to_world"])
                decision_path = output / f"decision-{replicate:02d}"
                selection = rank_design(
                    known_root,
                    output,
                    public,
                    protocol,
                    {
                        "angles": protocol["acquisition"]["candidate_angles_degrees"],
                    },
                    accepted,
                    decision_path,
                    device,
                )
                # Selection is on disk before either future count image exists.
                record.write_json(f"decision-{replicate:02d}-binding.json", selection)
                pair = {"replicate": replicate, "base": base, "selection": selection}
                for policy, angle in (
                    ("selected", selection["selected_angle"]),
                    ("near_parallel", protocol["acquisition"]["fixed_view_degrees"]),
                ):
                    future_id = _observation(
                        record, public, means, protocol, angle, beam, 3, replicate, seed
                    )
                    pair[policy] = _fit(
                        known_root,
                        output,
                        public,
                        protocol,
                        f"{policy}-{replicate:02d}",
                        [base_id, future_id],
                        accepted,
                        device,
                    )
                results.append(pair)

The frozen configuration fixes the eight noise replicates, exposure, candidate set, probe locations and success criteria. The input anatomy is intentionally known for this instructional exercise. Evaluation transforms and the reserved 45° and 135° view means are kept out of fitting and ranking. After all fits have finished, the evaluator measures target error and checks predictions in both reserved views.

Every one of the 25 solves, including the initial Chapter 11 registration, reaches the unchanged scaled-gradient threshold of 0.001 and passes its independent checks. The selected policy’s mean squared target error is 0.001335 mm², compared with 0.004681 mm² for the near-parallel baseline: a ratio of 0.2851, below the declared 0.75 requirement. The paired mean difference is −0.003347 mm², with a descriptive 95% t-interval upper endpoint of −0.000594 mm². This interval summarises eight prescribed noise pairs on one anatomy; it is not an estimate of clinical benefit across patients.

In two of the eight pairs, the selected view produces a larger target error than the 5° baseline. The Fisher criterion predicts variance averaged over possible future count images, while each refit receives one new noisy image alongside the shared base image. A view with lower predicted variance can therefore give the worse result in an individual pair. The mean improvement includes both reversals, without requiring every noisy observation to be unusually obliging.

To extend the experiment, change one declared setting at a time and write a new record. Add an orthogonal fixed baseline to ask a harder comparison question, or restrict the candidate angles to study accessibility. A new anatomy, calibration error or a poor initial pose can change the ranking and its reliability. Keep those results separate from the supplied worked example, with every attempted outcome retained.

What the earlier policy comparison could not establish

The earlier study below tested selected, fixed and random policies across two CT-derived phantoms. Its 96 base and policy fits used assigned attenuation and simulated observations. All pass the geometric criterion, but none meets the unchanged stationarity threshold. The registration replay in Chapter 11 identified precision loss and midpoint integration artefacts that can produce these premature stops. Until the downstream solver completes, a policy comparison mixes the view’s information with the behaviour of an unfinished optimisation.

Figure 13.4 retains those original outcomes. The paired noise intervals do not establish a consistent advantage over the fixed policy. This is why the main exercise now completes every solve and uses a clearly stated near-parallel baseline. It does not relabel the historical results as successful optimisation.

Predicted local variance before acquisition

First prescribed replicate. Selection minimises predicted variance at eight fixed object-frame corners, using the nonstationary first-view pose. Evaluation uses 125 separate mathematical probes.

Case 0: current mean target variance 0.00944 mm²
Additional anglePredicted variance / mm²Choice
-90°0.00225
-60°0.00191
-30°0.00244
30°0.00197
60°0.00171Selected
90°0.00199
Case 1: current mean target variance 0.00892 mm²
Additional anglePredicted variance / mm²Choice
-90°0.00193
-60°0.00166Selected
-30°0.00248
30°0.00203
60°0.00176
90°0.00189

Measured error after registration

Selection chose +60° for case 0 and −60° for case 1, while the fixed policy used +90°. Plots show achieved errors, not predicted variances.

Case 0: broad candidate set

Final 125-probe RMS displacement / mm against Paired noise replicate. Selected, Fixed and Random.Final 125-probe RMS displacement / mm00.0250.050.0750.102467Paired noise replicateSelected: 0, 0.018386Selected: 1, 0.056675Selected: 2, 0.04352Selected: 3, 0.043672Selected: 4, 0.041713Selected: 5, 0.034655Selected: 6, 0.027179Selected: 7, 0.06167Fixed: 0, 0.059036Fixed: 1, 0.028088Fixed: 2, 0.058639Fixed: 3, 0.018923Fixed: 4, 0.03859Fixed: 5, 0.06169Fixed: 6, 0.029091Fixed: 7, 0.072768Random: 0, 0.018386Random: 1, 0.056675Random: 2, 0.083377Random: 3, 0.048095Random: 4, 0.05199Random: 5, 0.034655Random: 6, 0.029091Random: 7, 0.06167
  • Selected
  • Fixed
  • Random

Case 1: broad candidate set

Final 125-probe RMS displacement / mm against Paired noise replicate. Selected, Fixed and Random.Final 125-probe RMS displacement / mm00.0250.050.0750.102467Paired noise replicateSelected: 0, 0.038459Selected: 1, 0.025056Selected: 2, 0.024805Selected: 3, 0.040002Selected: 4, 0.033682Selected: 5, 0.031601Selected: 6, 0.054694Selected: 7, 0.039027Fixed: 0, 0.040198Fixed: 1, 0.033154Fixed: 2, 0.043988Fixed: 3, 0.06629Fixed: 4, 0.03312Fixed: 5, 0.037433Fixed: 6, 0.038275Fixed: 7, 0.038403Random: 0, 0.037561Random: 1, 0.041892Random: 2, 0.053203Random: 3, 0.040002Random: 4, 0.033682Random: 5, 0.031601Random: 6, 0.037572Random: 7, 0.039027
  • Selected
  • Fixed
  • Random

Matching angles share observations within each replicate, so markers may overlap. Both plots use the same probes and scale. Lower predicted variance did not consistently reduce achieved error.

Selected minus comparison: paired probe-RMS differences in millimetres
CaseComparisonPairsMean differenceDescriptive 95% interval
0fixed8/8-0.00492-0.02012 to 0.01056
0random8/8-0.00706-0.01702 to -0.00055
1fixed8/8-0.00544-0.01414 to 0.00295
1random8/8-0.00340-0.01264 to 0.00450

Negative differences favour selection. Percentile bootstrap intervals describe paired noise within each phantom, not population performance across CTs. Both selected-versus-fixed intervals include zero.

Before and after: all policy means and reserved-view errors
CasePolicyFitsMean probe RMS / mmMean reserved-view standardised RMS
0Before additional view80.103340.03676
0selected80.040930.01521
0fixed80.045850.01800
0random80.047990.01644
1Before additional view80.078160.02643
1selected80.035920.01242
1fixed80.041360.01358
1random80.039320.01427

Reserved-view RMS compares prediction with the independent generating mean on two excluded views, scaled pixelwise by the generating Poisson SD. The table averages per-fit RMS values, not noisy-observation residuals.

Every additional view costs 16,384,000 expected detector-incident photons. Including the initial view gives 32,768,000. This is a photon-population budget, not absorbed dose. All 64 base and policy fits passed the geometric gates and ended with line_search_failed. None met the gradient threshold of 0.001.

All outcomes, paired replicates and 24 decisions · Sources, rights and display rules. TCIA CT-ORG cases 0 and 1, with assigned monochromatic attenuation and simulated radiographs.

Figure 13.4Selecting a view, then testing the decisionThe Fisher criterion selects a second view before acquisition, and eight paired replicates per phantom compare its realised pose error with fixed and random choices. Lower predicted variance does not consistently give lower achieved error.

Figure 13.5 shows the earlier restricted-angle comparison at fixed exposure. Under the constrained candidate set, selection produces a higher mean geometric error for case 0. The recorded evidence does not separate local covariance approximation, candidate restrictions and unfinished fitting sufficiently to assign that increase to one cause. Treat it as a diagnostic example to rerun after the numerical checks pass, rather than evidence that the selector improves this restricted case.

Measured error after registration

Selection chose +30° in both cases, while the fixed policy used +15°. Plots show achieved errors, not predicted variances.

Case 0: constrained candidate set

Final 125-probe RMS displacement / mm against Paired noise replicate. Selected, Fixed and Random.Final 125-probe RMS displacement / mm00.0250.050.0750.10123Paired noise replicateSelected: 0, 0.046075Selected: 1, 0.041888Selected: 2, 0.038542Selected: 3, 0.080312Fixed: 0, 0.032857Fixed: 1, 0.063439Fixed: 2, 0.039007Fixed: 3, 0.041284Random: 0, 0.046765Random: 1, 0.052131Random: 2, 0.039007Random: 3, 0.080312
  • Selected
  • Fixed
  • Random

Case 1: constrained candidate set

Final 125-probe RMS displacement / mm against Paired noise replicate. Selected, Fixed and Random.Final 125-probe RMS displacement / mm00.0250.050.0750.10123Paired noise replicateSelected: 0, 0.064458Selected: 1, 0.0236Selected: 2, 0.057368Selected: 3, 0.03273Fixed: 0, 0.048699Fixed: 1, 0.041185Fixed: 2, 0.074458Fixed: 3, 0.021835Random: 0, 0.048699Random: 1, 0.041185Random: 2, 0.057368Random: 3, 0.021835
  • Selected
  • Fixed
  • Random

Matching angles share observations within each replicate, so markers may overlap. Both plots use the same probes and scale. Lower predicted variance did not consistently reduce achieved error.

Selected minus comparison: paired probe-RMS differences in millimetres
CaseComparisonPairsMean differenceDescriptive 95% interval
0fixed4/40.00756-0.01286 to 0.02915
0random4/4-0.00285-0.00780 to -0.00017
1fixed4/4-0.00201-0.01734 to 0.01333
1random4/40.00227-0.01046 to 0.01333

Negative differences favour selection. Percentile bootstrap intervals describe paired noise within each phantom, not population performance across CTs. In case 0 the selected policy has a higher mean error than the fixed view.

Before and after: all policy means and reserved-view errors
CasePolicyFitsMean probe RMS / mmMean reserved-view standardised RMS
0Before additional view40.083240.02975
0selected40.051700.01768
0fixed40.044150.01689
0random40.054550.01763
1Before additional view40.088490.03495
1selected40.044540.01539
1fixed40.046540.01841
1random40.042270.01699

Reserved-view RMS compares prediction with the independent generating mean on two excluded views, scaled pixelwise by the generating Poisson SD. The table averages per-fit RMS values, not noisy-observation residuals.

Every additional view costs 16,384,000 expected detector-incident photons. Including the initial view gives 32,768,000. This is a photon-population budget, not absorbed dose. All 32 base and policy fits passed the geometric gates and ended with line_search_failed. None met the gradient threshold of 0.001.

All outcomes, paired replicates and 24 decisions · Sources, rights and display rules. TCIA CT-ORG cases 0 and 1, with assigned monochromatic attenuation and simulated radiographs.

Figure 13.5Equal photon budgets, constrained view choicesWith candidate angles limited to −15°, +15° and +30°, four paired replicates per phantom compare selected, fixed and random views at one photon budget. In case 0, selection has higher mean pose error than the fixed policy.

13.9 A closing word

Volume I ends with a calculation that can help choose its next measurement. We began with photon survival through a slab. Reaching this decision has required a working renderer and derivatives that can guide an inverse calculation. The complete examples now recover unknown parameters from simulated observations and check the returned solutions against independent references. It is quite a lot of machinery for choosing another X-ray, but we can now account for what the machinery does.

That gives us a practical starting point for a problem of our own. Changing the unknown from a pose to a material field has already shown how much of the forward calculation can survive a very different inverse problem. Its physical assumptions remain visible, so we can decide what a new application actually requires us to change. A more elaborate representation can then be a deliberate modelling choice, with a calculation we understand beneath it.

Volume II is planned to cover neural representations and learned methods, and Volume III to develop volume reconstruction further. Those subjects have a place to begin in the forward model we have built here. Thank you for working through the physics and code with me. I hope that, when you next encounter a difficult imaging problem, a working calculation feels within reach.

References

  1. Burger, M, Hauptmann, A, Helin, T, Hyvönen, N and Puska, J-P (2021). Sequentially optimized projections in x-ray imaging. Inverse Problems, 37(7), 075006. https://doi.org/10.1088/1361-6420/ac01a4