Skip to content

Unblock step 13 and write the cropped cine frames - #97

Open
avhekkink wants to merge 1 commit into
plugin/atrailstrainmotionfrom
plugin/atrialstrainmotion-fix-step-13-crop
Open

Unblock step 13 and write the cropped cine frames#97
avhekkink wants to merge 1 commit into
plugin/atrailstrainmotionfrom
plugin/atrialstrainmotion-fix-step-13-crop

Conversation

@avhekkink

@avhekkink avhekkink commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

All 20 steps of the pipeline now run successfully end to end on V-0004

Step 13 was blocked with an ITK error and produced nothing, so step 14 had no input. The crop itself was also never finished. The container's cropImages hardcodes the crop box to one case, so this fix crops on the host instead, using the codebase's own utilities and a padded bounding box of the LA.

Changes

  • CropImage repairs the NIfTI header before it loads the segmentation. Why? The cemrg/ccta container rebuilds the header from the image affine and leaves qform_code at 0, which ITK refuses. SegmentExtract already calls CemrgNiftiUtils::RepairNiftiQform on the output of the same container; CropImage did not. This is the failure the step reported.

  • CropImage writes the cropped frames. The crop loop and the afmotion cropImages call were commented out, so the step measured a bounding box, printed it to stdout and stopped. It now builds a mitk::Cuboid from the padded box and writes nifti/dcm-crop-<N>.nii through CemrgCommonUtils::CropImage, which MmcwView::CropinIMGS already uses to crop a cine series against one cube. Step 14 needs those files: the container writes <project>/nifti/dcm-crop- .nii into tracking/imgTimes.lst, and the host MIRTK register reads that list.

  • afmotion cropImages is not used, and should not be as-is. uac_pipeline.py hardcodes the crop box to a specific case from another dataset and ignores the box the plugin measures. Its CropNifti_v3.py also writes the affine shift with a guessed sign for each axis, correct only for one orientation. mitk::BoundingObjectCutter calls IndexToWorld on the region start instead, which holds for any direction matrix.

  • A HasLabel test guards the bounding box.
    itk::LabelStatisticsImageFilter::GetBoundingBox returns a default-constructed std::vector when the image does not hold the label, so the loop that follows read six elements past the end of an empty vector. This never fired only because the segmentation always found an atrium.

  • The padding measures the box, not the position of the box. Each index was scaled by 30% of its own value, so the padding depended on where the atrium sat in the volume rather than how large it was. The padding is now a proportion of the length of each axis, held inside the image.

  • CropImage reports its failures. It names a missing nifti/dcm-10.nii, replaces the working copy rather than silently keeping the old one, stops when the segmentation writes nothing, and names the frame it cannot read or crop. The box now reaches afib_log<date>.log through MITK_INFO; std::cout never did.

Impacted areas

Area Files
Atrial Strain Motion plugin AtrialStrainMotionView.cpp

Nothing shared changes. CemrgCommandLine, CemrgCommonUtils and CemrgNiftiUtils are used as they are, so no other plugin is affected.

The cropped frames land in nifti/, beside the frames the user supplies, because the container hardcodes that path.

Testing

Run in the GUI on V-0004, 21 frames of 512 x 512 x 269:

  • Step 13. No ITK dialogue. The log carries the repair, the atrium box 7 306 98 255 73 249 and the padded box 0 395 51 302 21 268. It wrote 21 frames in 113 seconds and left no scratch file.
  • Steps 14 to 20. All complete. MIRTK wrote tracking/tsffd.dof at 9,039,844 bytes. Every per-frame output holds different content, checked by md5sum, so no step repeated a result or wrote an empty one.

This is the first end-to-end run of all twenty steps.

Not tested:

  • Any dataset other than V-0004. Both demo datasets carry 21 frames of the same geometry.
  • A frame that is not signed short, or one on a different grid from dcm-10.nii.
  • Windows. The step runs Docker and writes files; neither is platform specific, but nobody has run it there.

Step 13 stopped with an ITK error and wrote no cropped frames. Step 14
reads nifti/dcm-crop-<N>.nii, so it had no input. Two defects composed.

Repair the qform before the load. The CCTA container rebuilds the NIfTI
header from the image affine and leaves qform_code at 0. SegmentExtract
already calls CemrgNiftiUtils::RepairNiftiQform on the same container's
output. CropImage did not.

Crop every frame through CemrgCommonUtils::CropImage. The crop loop and
the afmotion cropImages call were commented out, so the step measured a
bounding box and discarded it. The container hardcodes its crop box to
another dataset, so the crop runs on the host instead.
MmcwView::CropinIMGS crops a cine series with the same three functions.

Guard the bounding box. GetBoundingBox returns an empty list for a label
that the image does not hold, so the loop read six elements past the end
of it. A HasLabel test now stops the step first.

Pad the box by a share of the length of each axis, then hold it inside
the image. The padding scaled each index by a share of its own value, so
it depended on the position of the atrium in the volume.

Add the failure checks that SegmentExtract has: a named error for a
missing reference frame, a copy that can overwrite, and a test of the
segmentation result.

Verified on V-0004. Step 13 writes 21 frames of 396 x 252 x 248. The
origin of each frame equals the original origin plus M times the start
index. Steps 14 to 20 then complete.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tz4XNNv9HTzUaJmdM2nFZ7
@avhekkink
avhekkink requested a review from alonsoJASL September 3, 2026 12:46
@avhekkink
avhekkink marked this pull request as ready for review September 3, 2026 13:06
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