Skip to content

ImageAlign: Use imageTransformations - #1905

Open
JakubFara wants to merge 7 commits into
developfrom
bugfix/ImageAlign_use_imageItransformations
Open

ImageAlign: Use imageTransformations#1905
JakubFara wants to merge 7 commits into
developfrom
bugfix/ImageAlign_use_imageItransformations

Conversation

@JakubFara

@JakubFara JakubFara commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

Purpose

  • Updated ImageAlign to use ImgTransformation metadata from incoming frames.
  • Reinitializes alignment when source or target image transformations change.
  • Computes intrinsics, distortion, rotation, and translation from the transformationsinstead of EEPROM calibration data.

Summary by CodeRabbit

  • Bug Fixes
    • Improved image alignment by automatically recalculating alignment/rectification parameters whenever input transformations change.
    • Enhanced distortion correction and alignment accuracy by deriving depth-to-alignment transform from the latest transformation data.
    • Improved output consistency by using the most recent available alignment reference frame for rectification and by basing output metadata on the depth input.

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

ImageAlign now derives calibration and rectification parameters from depth and align-to frame transformations, caches the latest align-to frame, refreshes state when transformations change, and removes calibration-handler refresh logic.

Changes

ImageAlign transformation flow

Layer / File(s) Summary
Transformation-based calibration extraction
src/pipeline/node/ImageAlign.cpp
Rectification distortion, rotation, and translation are computed from ImgTransformation values; calibration-handler initialization is removed and vecToCvMat accepts flat vectors.
Transformation tracking and reinitialization
src/pipeline/node/ImageAlign.cpp
ImageAlign::run() caches the latest align-to frame, tracks depth and align-to transformations, invalidates cached setup when they change, and assigns output metadata from the depth input.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

  • luxonis/depthai-core#1904: Both changes replace calibration-handler-based rectification inputs with frame transformation data and simplify vecToCvMat.

Suggested reviewers: aljazkonec1, asahtik, matictonin

Poem

A rabbit aligns frames in a row,
Letting transformations show where to go.
Old calibration rests, matrices dance,
Changed frames get a fresh chance.
Hop, warp, and rectify in tune!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: ImageAlign now uses image transformations instead of calibration data.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch bugfix/ImageAlign_use_imageItransformations

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@JakubFara JakubFara changed the title Use imageTransformations ImageAlign: Use imageTransformations Jul 21, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/pipeline/node/ImageAlign.cpp (1)

249-259: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Prevent Undefined Behavior when distortion coefficients are empty.

If alignDistortionCoefficients is empty, std::vector<float>(0, 0.0f) is passed to vecToCvMat, which creates an empty cv::Mat(1, 0). Because OpenCV does not allocate a data buffer for 0 total elements, cvMat.data will be nullptr. The vecToCvMat helper then calls memcpy with this nullptr, which is Undefined Behavior in C/C++ and can cause the pipeline to crash.

Since OpenCV accepts a 14-element vector of zeros to represent no distortion (and the code already does this to pad depthDistortionCoefficients), you can safely hardcode the size to 14 to avoid the crash.

🛡️ Proposed fix
         const auto alignDistortionCoefficients = alignToTransformation.getDistortionCoefficients();
         const auto depthToAlignRotation = depthSourceTransformation.getRotationMatrixTo(alignToTransformation);
         const auto depthToAlignTranslationArray = depthSourceTransformation.getTranslationVectorTo(alignToTransformation, false, LengthUnit::MILLIMETER);
         const std::vector<float> depthToAlignTranslation(depthToAlignTranslationArray.begin(), depthToAlignTranslationArray.end());
 
         auto cv_M1 = arrayToCvMat(3, 3, CV_32FC1, depthSourceIntrinsics);
         auto cv_M2 = arrayToCvMat(3, 3, CV_32FC1, alignSourceIntrinsics);
 
         auto cv_d1 = vecToCvMat(1, depthDistortionCoefficients.size(), CV_32FC1, depthDistortionCoefficients);
-        auto cv_dNone = vecToCvMat(
-            1, alignDistortionCoefficients.size(), CV_32FC1, std::vector<float>(alignDistortionCoefficients.size(), 0.0f));  // No distortion for aligned frame
+        auto cv_dNone = vecToCvMat(1, 14, CV_32FC1, std::vector<float>(14, 0.0f));  // No distortion for aligned frame
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pipeline/node/ImageAlign.cpp` around lines 249 - 259, Update the cv_dNone
construction near alignDistortionCoefficients to always create a 14-element zero
vector instead of using alignDistortionCoefficients.size(). Preserve its role as
the no-distortion matrix and avoid passing an empty vector to vecToCvMat.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/pipeline/node/ImageAlign.cpp`:
- Around line 357-360: Update the inputAlignTo handling in ImageAlign to
repeatedly call tryGet<ImgFrame>() until no pending messages remain, retaining
each retrieved frame so inputAlignToImg ends with the latest one. Preserve the
existing behavior when the queue is empty.

---

Outside diff comments:
In `@src/pipeline/node/ImageAlign.cpp`:
- Around line 249-259: Update the cv_dNone construction near
alignDistortionCoefficients to always create a 14-element zero vector instead of
using alignDistortionCoefficients.size(). Preserve its role as the no-distortion
matrix and avoid passing an empty vector to vecToCvMat.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 61a3f0db-d087-43c0-a25a-2195d24d3df7

📥 Commits

Reviewing files that changed from the base of the PR and between 202304f and 0865443.

📒 Files selected for processing (1)
  • src/pipeline/node/ImageAlign.cpp
📜 Review details
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-03-24T22:39:04.364Z
Learnt from: MaticTonin
Repo: luxonis/depthai-core PR: 1732
File: src/pipeline/Pipeline.cpp:705-705
Timestamp: 2026-03-24T22:39:04.364Z
Learning: Do not flag the `!= ""` part of the auto-calibration condition as redundant when it appears in `PipelineImpl::build()` (or closely related pipeline build logic). If the code uses `utility::getEnvAs<std::string>(..., default)` with a default such as `"ON_START"`, the explicit empty-string guard may still be intentional to treat an explicitly empty env var as “OFF/disabled” (or to avoid special-casing elsewhere). Only consider removing `!= ""` if the codebase has an explicit, enforceable guarantee that `DEPTHAI_AUTOCALIBRATION` can never be set to an empty string (e.g., via validated parsing/CI checks); otherwise, keep the guard.

Applied to files:

  • src/pipeline/node/ImageAlign.cpp

Comment thread src/pipeline/node/ImageAlign.cpp
@JakubFara
JakubFara force-pushed the bugfix/ImageAlign_use_imageItransformations branch from afcf501 to 0772265 Compare July 22, 2026 08:28

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/pipeline/node/ImageAlign.cpp`:
- Around line 353-357: Update the transformation-change branch in ImageAlign so
it also resets allocated, frameSize, outFrameSize, and previousShiftFactor
alongside initialized and calibrationSet. Before reinitialization, re-derive any
auto-selected output dimensions from the new transformation rather than
retaining values from the previous transform.
- Around line 359-362: Update the frame-selection logic in ImageAlign so
inputAlignToImgFrame is refreshed from the currently selected inputAlignToImg on
every frame, moving that copy outside the !initialized block while keeping
alignToTransformation initialization there. This ensures
alignedImg->setMetadata(inputAlignToImgFrame) uses current timestamp and
sequence metadata.
- Around line 343-350: Guard the result of inputAlignTo.getAll<ImgFrame>() in
the align-to image selection logic before accessing back(). Only read and assign
the last message when the collection is non-empty, then preserve the existing
inputAlignTo.get<ImgFrame>() fallback when no valid image was selected.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 8ab485a0-2cb1-48b2-83f5-d28e10d3b120

📥 Commits

Reviewing files that changed from the base of the PR and between 0865443 and 0772265.

📒 Files selected for processing (1)
  • src/pipeline/node/ImageAlign.cpp
📜 Review details
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-03-24T22:39:04.364Z
Learnt from: MaticTonin
Repo: luxonis/depthai-core PR: 1732
File: src/pipeline/Pipeline.cpp:705-705
Timestamp: 2026-03-24T22:39:04.364Z
Learning: Do not flag the `!= ""` part of the auto-calibration condition as redundant when it appears in `PipelineImpl::build()` (or closely related pipeline build logic). If the code uses `utility::getEnvAs<std::string>(..., default)` with a default such as `"ON_START"`, the explicit empty-string guard may still be intentional to treat an explicitly empty env var as “OFF/disabled” (or to avoid special-casing elsewhere). Only consider removing `!= ""` if the codebase has an explicit, enforceable guarantee that `DEPTHAI_AUTOCALIBRATION` can never be set to an empty string (e.g., via validated parsing/CI checks); otherwise, keep the guard.

Applied to files:

  • src/pipeline/node/ImageAlign.cpp

Comment thread src/pipeline/node/ImageAlign.cpp Outdated
Comment thread src/pipeline/node/ImageAlign.cpp
Comment thread src/pipeline/node/ImageAlign.cpp
@JakubFara
JakubFara force-pushed the bugfix/ImageAlign_use_imageItransformations branch from 25d51e6 to e1f8f10 Compare July 22, 2026 13:17

@MaticTonin MaticTonin left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

No issues from my side.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/pipeline/node/ImageAlign.cpp`:
- Around line 560-569: Update the stride and plane-offset initialization in the
aligned image setup to use the row stride defined by the ImgFrame contract, not
aggregate frame bytes-per-pixel for planar NV12 and YUV420p formats. Preserve
the existing chroma-plane layout, ensuring p2Offset starts at width × height and
YUV420p p3Offset follows the half-resolution chroma plane; use the local
frameTypeToBpp mapping or equivalent per-row value.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d525a022-c136-489a-9774-7e306fb75b83

📥 Commits

Reviewing files that changed from the base of the PR and between 25970e0 and c3b865e.

📒 Files selected for processing (1)
  • src/pipeline/node/ImageAlign.cpp
📜 Review details
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-03-24T22:39:04.364Z
Learnt from: MaticTonin
Repo: luxonis/depthai-core PR: 1732
File: src/pipeline/Pipeline.cpp:705-705
Timestamp: 2026-03-24T22:39:04.364Z
Learning: Do not flag the `!= ""` part of the auto-calibration condition as redundant when it appears in `PipelineImpl::build()` (or closely related pipeline build logic). If the code uses `utility::getEnvAs<std::string>(..., default)` with a default such as `"ON_START"`, the explicit empty-string guard may still be intentional to treat an explicitly empty env var as “OFF/disabled” (or to avoid special-casing elsewhere). Only consider removing `!= ""` if the codebase has an explicit, enforceable guarantee that `DEPTHAI_AUTOCALIBRATION` can never be set to an empty string (e.g., via validated parsing/CI checks); otherwise, keep the guard.

Applied to files:

  • src/pipeline/node/ImageAlign.cpp
🔇 Additional comments (5)
src/pipeline/node/ImageAlign.cpp (5)

69-73: LGTM!


187-188: LGTM!


235-247: LGTM!


331-392: LGTM!


439-439: LGTM!

Comment thread src/pipeline/node/ImageAlign.cpp
@aljazkonec1 aljazkonec1 added the testable PR is ready to be tested - run vanilla tests label Jul 24, 2026
@aljazkonec1

aljazkonec1 commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator
  • Device side implementations were not updated
  • image_align_node_test was failing
  • Expanded image_align_node_test to test runtime changes to ImgTransformations
  • setting the metadata from input frame or from alignToFrame was both wrong so I opted to manually set everything
  • The getAll function would block because it needs at least one input. Switched to tryGet so that inputAlignTo doesnt need to be at the same frequency as input to continue processing

@JakubFara please go over my changes here and on device (RVC2 and RVC4) as I might have made some mistakes. Thanks

@JakubFara
JakubFara force-pushed the bugfix/ImageAlign_use_imageItransformations branch from 8bba2c3 to f020966 Compare July 24, 2026 09:42
@JakubFara

Copy link
Copy Markdown
Collaborator Author
  • Device side implementations were not updated

Thanks, I was not aware of device side

Expanded image_align_node_test to test runtime changes to ImgTransformations

Good point

setting the metadata from input frame or from alignToFrame was both wrong so I opted to manually set everything

What particularly was wrong?

The getAll function would block because it needs at least one input. Switched to tryGet so that inputAlignTo doesnt need to be at the same frequency as input to continue processing

Ok, I have found tryGetAll function which should do the thing.

Implementation of trySend does not fit to this PR.

I like to rebase branch ok develop not merge develop to branch since it keeps the branch clean.

I prefere just 1 person to do the changes in a PR.

@aljazkonec1

aljazkonec1 commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

What particularly was wrong?

offsets were set based on the input and not the alignTo frame offsets, Camera capabilities were copied from alignToFrame when in reality they should remain from the inputFrame, A lot of the metadata gets overwritten after that (size, type, timestamps, ImgTransformations ...) so I opted to just remove setMetadata and make it an explicit set

Implementation of trySend does not fit to this PR.

Yes but it was necessarry due to flaky-ness of test.

tryGetAll is OK with me

@JakubFara
JakubFara force-pushed the bugfix/ImageAlign_use_imageItransformations branch from f020966 to 720fbb3 Compare August 10, 2026 14:40
@JakubFara
JakubFara force-pushed the bugfix/ImageAlign_use_imageItransformations branch from 720fbb3 to 8ee2055 Compare August 11, 2026 14:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

testable PR is ready to be tested - run vanilla tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants