Skip to content

2dseq transposition appears to be applied twice: RECO_transposition records what reconstruction already did #153

Description

@gdevenyi

Schema2dseq gained _apply_transposition, which transposes the XY axes of
every frame whose RECO_transposition / VisuCoreTransposition flag is set.

I believe the reconstruction has already applied that transposition when it
wrote the 2dseq, so applying it on read transposes the image. Two independent
lines of evidence, neither of which relies on any converter's output.

1. It contradicts the geometry parameters in the same file

Any flagged non-square reconstruction shows this. One I have to hand, PV6.0.1,
3D:

VisuCoreSize    [178, 200, 100]
VisuCoreExtent  [16.02, 18.00, 9.00]

The field of view divides by the matrix, in VisuCoreSize order, into isotropic
0.090 mm voxels — which is what the acquisition was. Pair that same extent with
the transposed array (200, 178, 100) and the voxels come out 0.080 x 0.101 mm.

So VisuCoreExtent describes the untransposed array, and by construction so do
VisuCorePosition and VisuCoreOrientation. Transposing data alone puts it at
odds with the whole geometry block a consumer uses to build an affine — and the
affine is unchanged by this code, so the image and its geometry now disagree.

2. Two acquisitions of the same object stop agreeing

I have an orientation phantom study containing pairs that differ only in
readout direction — the variable that flips this flag. Same phantom, same
session, same slice orientation, same voxel size, identical direction cosines.
Two images of the same object in the same plane must hold the same array.

Correlating each pair as-is, and with one member's in-plane axes swapped:

pair as-is one transposed
PV6.0.1 coronal 2D flag left alone +0.951 +0.283
0.4, flag applied +0.283 +0.951
PV6.0.1 axial 3D flag left alone +0.992 +0.532
0.4, flag applied +0.532 +0.992
PV5.1 axial 3D flag left alone +0.928 +0.426
0.4, flag applied +0.426 +0.928

The pairs already agree when the flag is left alone. Applying it is what makes
two images of the same object disagree, and the prediction inverts exactly
between library versions.

Consistent with the ParaVision docs

ATB_SetRecoTranspositionFromLoops is documented as the method program
"calculating the values of the RECO_transposition array depending on the image
orientation" — the sequence telling the reconstruction what to do, which the
reconstruction then does. The parameter reads as a record, not an instruction.

Scope

The flag is set on 1,142 of 1,561 reconstructions (73%) in the corpus I test
against, spanning PV5.1, 6.0.1, 7.0.0 and PV360 — so this changes the pixel data
of most datasets, silently.

What I have not established

  • Only PV5.1 and PV6.0.1 are covered by the pair experiment. Not 7.0.0 or
    PV360 — and the flag's source differs (RECO_transposition for 1,052 of those
    reconstructions, VisuCoreTransposition for 90), so they need not behave alike.
  • All three pairs are axis-aligned; oblique acquisitions are untested.
  • The phantom study's redistributability is unestablished, so I can't attach it.
    The geometry argument in (1) needs no data from me — it reproduces on any
    flagged non-square reconstruction you have.

Happy to be wrong about this if there's a dataset where the transposition is
genuinely pending on read; that would be very useful to see.

See also #(the shape issue), which is a separate defect in the same code path.

🤖 Generated with Claude Code

https://claude.ai/code/session_019P9Qp72Xymjic1eT9sMB5Q

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions