Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

BUG: Resample Data (Image Geometry) sets the output length unit to Micrometer

未关闭 适合新手
#1,844 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 4 天内回复

还没有人认领这个 Issue。

评估

难度
2/5
预计耗时
1-3 小时
新手友好度
78/100
Issue 类型
缺陷
描述清晰度
描述清楚
活跃度
活跃
技术栈
cpp
领域
backend, data

调研方向

阅读 src/simplnx/Utilities/ImageProcessing/ImageGeometryResample.cpp,重点查看创建输出几何体的 PreflightImageGeometryResample(),以及 CreateImageGeometryAction 构造函数声明,以确认其默认单位。在 src/Plugins/SimplnxCore/test/ResampleImageGeomTest.cpp 中添加或使用提供的回归用例,并运行指定的 CTest 用例。当原位输出和新几何体输出都保留输入单位时,即完成;检查对 Read Image Stack 所述的影响。

由索引模型根据 Issue 内容生成。

描述

bug Filter

Problem

Resample Data (Image Geometry) sets the length unit of the resampled Image Geometry to Micrometer, whatever the input geometry's unit is. A Millimeter input becomes a Micrometer output, but the origin and spacing values stay in the input's units. So the output's physical size is wrong by the ratio between the two units.

  • Expected: the resampled geometry has the input geometry's length unit, both when it is saved as a new geometry and when it replaces the input.
  • Actual: the resampled geometry is always Micrometer.
  • Commit: develop at 2eb6b878f6ff408d1454754d4c0e63edd676d7e0.

Preflight shows the problem: the Resampled Image Geometry Info value reports the input's unit, but the geometry that execute creates is Micrometer.

Steps to Reproduce

  1. Create an Image Geometry with dimensions 2 x 2 x 2, origin (0, 0, 0), spacing (1, 1, 1) and length unit Millimeter. Give it a Cell Attribute Matrix with one int32 array.
  2. Run Resample Data (Image Geometry) with Resampling Mode set to Spacing and New Spacing (0.5, 0.5, 0.5). Run it once with Perform In Place off and once with it on.
  3. Look at the unit of the resampled geometry. It is Micrometer in both runs.

Cause

PreflightImageGeometryResample() builds the output geometry with CreateImageGeometryAction and does not pass a unit, so the action uses its default, Micrometer:

https://github.com/BlueQuartzSoftware/simplnx/blob/2eb6b878f6ff408d1454754d4c0e63edd676d7e0/src/simplnx/Utilities/ImageProcessing/ImageGeometryResample.cpp#L314-L315

  resultOutputActions.value().appendAction(std::make_unique<CreateImageGeometryAction>(
      destImagePath, geometryDimensions, srcOrigin, CreateImageGeometryAction::OriginType{resolvedValues.Spacing[0], resolvedValues.Spacing[1], resolvedValues.Spacing[2]}, cellDataName));

The default comes from the constructor declaration:

https://github.com/BlueQuartzSoftware/simplnx/blob/2eb6b878f6ff408d1454754d4c0e63edd676d7e0/src/simplnx/Filter/Actions/CreateImageGeometryAction.hpp#L31-L32

The preflight value a few lines later uses the input's unit, so the two disagree:

https://github.com/BlueQuartzSoftware/simplnx/blob/2eb6b878f6ff408d1454754d4c0e63edd676d7e0/src/simplnx/Utilities/ImageProcessing/ImageGeometryResample.cpp#L330

In place, the action builds a temporary geometry with the same Micrometer default, and that geometry then replaces the input. The test below shows the same result for both modes.

Verification Unit Test

Add to src/Plugins/SimplnxCore/test/ResampleImageGeomTest.cpp:

TEST_CASE("SimplnxCore::ResampleImageGeom: Output keeps the input length unit", "[SimplnxCore][ResampleImageGeom]")
{
  UnitTest::LoadPlugins();
  const bool shouldRemoveOriginal = GENERATE(false, true);
  CAPTURE(shouldRemoveOriginal);

  DataStructure dataStructure;
  const DataPath srcGeomPath({"Geom"});
  const DataPath destGeomPath({"Geom Out"});
  auto* geomPtr = ImageGeom::Create(dataStructure, "Geom");
  REQUIRE(geomPtr != nullptr);
  geomPtr->setDimensions({2, 2, 2});
  geomPtr->setOrigin({0.0F, 0.0F, 0.0F});
  geomPtr->setSpacing({1.0F, 1.0F, 1.0F});
  geomPtr->setUnits(IGeometry::LengthUnit::Millimeter);
  auto* cellAmPtr = AttributeMatrix::Create(dataStructure, "Cell Data", {2, 2, 2}, geomPtr->getId());
  REQUIRE(cellAmPtr != nullptr);
  geomPtr->setCellData(*cellAmPtr);
  auto* dataPtr = Int32Array::Create(dataStructure, "Data", DataStoreUtilities::CreateDataStore<int32>(dataStructure, cellAmPtr->getDataPaths().front().createChildPath("Data"), cellAmPtr->getShape(), {1}),
                                     cellAmPtr->getId());
  REQUIRE(dataPtr != nullptr);
  dataPtr->fill(7);

  ResampleImageGeomFilter filter;
  Arguments args;
  args.insertOrAssign(ResampleImageGeomFilter::k_SelectedImageGeometryPath_Key, std::make_any<DataPath>(srcGeomPath));
  args.insertOrAssign(ResampleImageGeomFilter::k_CreatedImageGeometry_Key, std::make_any<DataPath>(destGeomPath));
  args.insertOrAssign(ResampleImageGeomFilter::k_RemoveOriginalGeometry_Key, std::make_any<bool>(shouldRemoveOriginal));
  args.insertOrAssign(ResampleImageGeomFilter::k_Spacing_Key, std::make_any<std::vector<float32>>(std::vector<float32>{0.5F, 0.5F, 0.5F}));
  auto preflightResult = filter.preflight(dataStructure, args);
  SIMPLNX_RESULT_REQUIRE_VALID(preflightResult.outputActions);
  auto executeResult = filter.execute(dataStructure, args);
  SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result);

  // In place, the resampled geometry replaces the input at its path. Otherwise it is created at the new path.
  const DataPath outputGeomPath = shouldRemoveOriginal ? srcGeomPath : destGeomPath;
  const auto* outputGeomPtr = dataStructure.getDataAs<ImageGeom>(outputGeomPath);
  REQUIRE(outputGeomPtr != nullptr);
  CHECK(outputGeomPtr->getSpacing() == FloatVec3{0.5F, 0.5F, 0.5F});
  CHECK(outputGeomPtr->getUnits() == IGeometry::LengthUnit::Millimeter);
}

Run only this test:

ctest -R "ResampleImageGeom: Output keeps the input length unit" --output-on-failure

Output at 2eb6b87 (simplnx-Rel, macOS arm64). In IGeometry::LengthUnit, 6 is Micrometer and 7 is Millimeter:

ResampleImageGeomTest.cpp:725: FAILED:
  CHECK( outputGeomPtr->getUnits() == IGeometry::LengthUnit::Millimeter )
with expansion:
  6 == 7
with message:
  shouldRemoveOriginal := false

ResampleImageGeomTest.cpp:725: FAILED:
  CHECK( outputGeomPtr->getUnits() == IGeometry::LengthUnit::Millimeter )
with expansion:
  6 == 7
with message:
  shouldRemoveOriginal := true

test cases:  1 |  0 passed | 1 failed
assertions: 17 | 15 passed | 2 failed

Proposed Fix

In PreflightImageGeometryResample() (src/simplnx/Utilities/ImageProcessing/ImageGeometryResample.cpp), pass the input geometry's unit to the action:

   resultOutputActions.value().appendAction(std::make_unique<CreateImageGeometryAction>(
-      destImagePath, geometryDimensions, srcOrigin, CreateImageGeometryAction::OriginType{resolvedValues.Spacing[0], resolvedValues.Spacing[1], resolvedValues.Spacing[2]}, cellDataName));
+      destImagePath, geometryDimensions, srcOrigin, CreateImageGeometryAction::OriginType{resolvedValues.Spacing[0], resolvedValues.Spacing[1], resolvedValues.Spacing[2]}, cellDataName,
+      srcImageGeom.getUnits()));

Read Image Stack also calls PreflightImageGeometryResample() when it resamples, so the change reaches that filter too. Check that its own unit handling still gives the unit it intends.

Notes

  • Found while reviewing #1838, which fixes the unit of orientation-space and pole-figure geometries. #1784 is a separate unit problem: deep copies of geometries drop the unit.
  • The effect on Read Image Stack comes from reading the code; it was not tested.
主要语言
C++
星标
18
派生
15
平均合并
5 天 1 小时
30 天内合并 PR
22

环境准备

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

BlueQuartzSoftware/simplnx 的其他 Issue

查看 BlueQuartzSoftware/simplnx 的全部 Issue

相似的 Issue

更多 C++ Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。