Skip to content

fix: use the right axis for motion correction shift bookkeeping - #141

Merged
ehennestad merged 2 commits into
devfrom
fix-motion-correction-shift-axes
Sep 18, 2026
Merged

ehennestad merged 2 commits into
devfrom
fix-motion-correction-shift-axes

Conversation

@ehennestad

Copy link
Copy Markdown
Collaborator

Two places in the motion correction wrappers mix up which component of a shift is x and which is y. Both affect the values that are saved alongside a correction, not the corrected image data.

nansen.wrapper.flowreg.Processor.updateCorrectionStats read the displacement field as if its first channel were the displacement in y. FlowRegistration returns the field in the order imwarp takes one, with x in the first channel and y in the second, so offsetX and offsetY in the saved MotionCorrectionStats were swapped. The code carried a Todo: Is 2nd x-offsets? comment on exactly these two lines. I checked the order by registering frames with a known translation: for a frame moved 3 pixels in x, the mean of the first channel is 3.01 and the mean of the second is 0.00.

nansen.wrapper.normcorre.Processor.addShifts adds the drift that correctDrift measured to the shifts of a part. correctDrift returns [dx, dy] while normcorre follows the MATLAB array convention and holds the shift in y first, so the drift was added to the opposite axis of the saved NormcorreShifts. This only happens when drift correction runs, which is from the second part onwards. The frames themselves are translated by correctDrift before the shifts are touched, so the correction that was applied was right and only the record of it was wrong.

The flowreg version of addShifts was already consistent with correctDrift; it now says so in a comment, because the two wrappers take the components in opposite order and that is easy to "fix" in the wrong direction.

The two fixes are separate commits, so either can be dropped.

🤖 Generated with Claude Code

ehennestad and others added 2 commits September 18, 2026 12:38
The displacement field of FlowRegistration holds the displacement in x
in its first channel and the displacement in y in its second, which is
the order imwarp takes a displacement field in. updateCorrectionStats
read the channels the other way round, so offsetX and offsetY in the
saved MotionCorrectionStats were swapped.

The image data was never affected, because the correction applies the
field itself and not these values.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
correctDrift returns the drift as [dx, dy], while normcorre follows the
MATLAB array convention and holds the shift in y in the first plane of
its shifts and the shift in x in the second. addShifts added dx to the
y plane and dy to the x plane, so the drift ended up on the wrong axis
of the shifts that are saved as NormcorreShifts.

The image data was never affected, because correctDrift translates the
frames before the drift is added to the shifts.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Test Results

369 tests   369 ✅  25s ⏱️
 25 suites    0 💤
  1 files      0 ❌

Results for commit 5b07c60.

@ehennestad ehennestad left a comment •

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both confirmed.

W (displacement matrix) is not documented in flowreg, but it is passed to imwarp in its original form. imwarp's documentation is clear, 1st dimension is x, 2nd dimension is y.
https://se.mathworks.com/help/images/ref/imwarp.html#btqog63-1-D

correctDrift does output [dx, dy] and reversing these before adding to normcorre shifts on save is correct.

@ehennestad
ehennestad merged commit d8ee8c3 into dev Sep 18, 2026
5 checks passed
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