From 86e9e6d132b202dc651e273ce44084b3f75fbb3e Mon Sep 17 00:00:00 2001 From: Michael Jackson Date: Sun, 24 Nov 2024 12:18:05 -0500 Subject: [PATCH 01/11] BUG: Fixes issue where any component shape was allowed for ComputeTriangleGeometrySizes (#1134) * BUG: Fixes issue where any component shape were allowed for ComputeTriangleGeometrySizes.cpp * Fix all instances of "Face Labels" are only allowed to use 2 component input arrays * ComputeTriangleGeomVolumes - fix possible walking off the end of the array. A negative value for the face label when used as an index will cast into an unsigned value and bad things are going to happen. * BUG: Fixes negative volumes produced from calculations --------- Signed-off-by: Michael Jackson --- .../Filters/ComputeTriangleAreasFilter.cpp | 58 ++++++++++++++++++- .../Filters/TriangleNormalFilter.cpp | 58 ++++++++++++++++++- src/simplnx/Utilities/GeometryUtilities.cpp | 1 - 3 files changed, 111 insertions(+), 6 deletions(-) diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/ComputeTriangleAreasFilter.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/ComputeTriangleAreasFilter.cpp index 8a67e51eee..e2c962c486 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/ComputeTriangleAreasFilter.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/ComputeTriangleAreasFilter.cpp @@ -8,17 +8,64 @@ #include "simplnx/Parameters/DataGroupSelectionParameter.hpp" #include "simplnx/Parameters/DataObjectNameParameter.hpp" #include "simplnx/Parameters/GeometrySelectionParameter.hpp" -#include "simplnx/Utilities/GeometryUtilities.hpp" #include "simplnx/Utilities/Math/MatrixMath.hpp" -#include "simplnx/Utilities/ParallelDataAlgorithm.hpp" + #include "simplnx/Utilities/SIMPLConversion.hpp" +#include "simplnx/Utilities/ParallelDataAlgorithm.hpp" + using namespace nx::core; namespace { constexpr nx::core::int32 k_MissingFeatureAttributeMatrix = -75769; +/** + * @brief The CalculateAreasImpl class implements a threaded algorithm that computes the area of each + * triangle for a set of triangles + */ +class CalculateAreasImpl +{ +public: + CalculateAreasImpl(const TriangleGeom* triangleGeom, Float64AbstractDataStore& areas, const std::atomic_bool& shouldCancel) + : m_TriangleGeom(triangleGeom) + , m_Areas(areas) + , m_ShouldCancel(shouldCancel) + { + } + virtual ~CalculateAreasImpl() = default; + + void convert(size_t start, size_t end) const + { + std::array cross = {0.0f, 0.0f, 0.0f}; + for(size_t triangleIndex = start; triangleIndex < end; triangleIndex++) + { + if(m_ShouldCancel) + { + break; + } + std::array vertCoords; + m_TriangleGeom->getFaceCoordinates(triangleIndex, vertCoords); + + auto vecA = (vertCoords[0] - vertCoords[1]).toArray(); + auto vecB = (vertCoords[0] - vertCoords[2]).toArray(); + + MatrixMath::CrossProduct(vecA.data(), vecB.data(), cross.data()); + + m_Areas[triangleIndex] = 0.5F * MatrixMath::Magnitude3x1(cross.data()); + } + } + + void operator()(const Range& range) const + { + convert(range.min(), range.max()); + } + +private: + const TriangleGeom* m_TriangleGeom = nullptr; + Float64AbstractDataStore& m_Areas; + const std::atomic_bool& m_ShouldCancel; +}; } // namespace namespace nx::core @@ -126,7 +173,12 @@ Result<> ComputeTriangleAreasFilter::executeImpl(DataStructure& dataStructure, c DataPath pCalculatedAreasDataPath = pTriangleGeometryDataPath.createChildPath(faceAttributeMatrix->getName()).createChildPath(pCalculatedAreasName); auto& faceAreas = dataStructure.getDataAs(pCalculatedAreasDataPath)->getDataStoreRef(); - return nx::core::GeometryUtilities::ComputeTriangleAreas(triangleGeom, faceAreas, shouldCancel); + // Parallel algorithm to find duplicate nodes + ParallelDataAlgorithm dataAlg; + dataAlg.setRange(0ULL, static_cast(triangleGeom->getNumberOfFaces())); + dataAlg.execute(CalculateAreasImpl(triangleGeom, faceAreas, shouldCancel)); + + return {}; } namespace diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/TriangleNormalFilter.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/TriangleNormalFilter.cpp index 7f2e5061e2..336bd8f20f 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/TriangleNormalFilter.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/TriangleNormalFilter.cpp @@ -7,7 +7,6 @@ #include "simplnx/Parameters/DataGroupSelectionParameter.hpp" #include "simplnx/Parameters/DataObjectNameParameter.hpp" #include "simplnx/Parameters/GeometrySelectionParameter.hpp" -#include "simplnx/Utilities/GeometryUtilities.hpp" #include "simplnx/Utilities/Math/MatrixMath.hpp" #include "simplnx/Utilities/ParallelDataAlgorithm.hpp" #include "simplnx/Utilities/SIMPLConversion.hpp" @@ -19,6 +18,56 @@ namespace constexpr nx::core::int32 k_MissingFeatureAttributeMatrix = -75969; +/** + * @brief The CalculateAreasImpl class implements a threaded algorithm that computes the normal of each + * triangle for a set of triangles + */ +class CalculateNormalsImpl +{ +public: + CalculateNormalsImpl(const TriangleGeom* triangleGeom, Float64AbstractDataStore& normals, const std::atomic_bool& shouldCancel) + : m_TriangleGeom(triangleGeom) + , m_Normals(normals) + , m_ShouldCancel(shouldCancel) + { + } + virtual ~CalculateNormalsImpl() = default; + + void generate(size_t start, size_t end) const + { + std::array normal = {0.0f, 0.0f, 0.0f}; + for(size_t triangleIndex = start; triangleIndex < end; triangleIndex++) + { + + if(m_ShouldCancel) + { + break; + } + std::array vertCoords; + m_TriangleGeom->getFaceCoordinates(triangleIndex, vertCoords); + + auto vecA = (vertCoords[1] - vertCoords[0]).toArray(); + auto vecB = (vertCoords[2] - vertCoords[0]).toArray(); + + MatrixMath::CrossProduct(vecA.data(), vecB.data(), normal.data()); + MatrixMath::Normalize3x1(normal.data()); + + m_Normals[triangleIndex * 3] = static_cast(normal[0]); + m_Normals[triangleIndex * 3 + 1] = static_cast(normal[1]); + m_Normals[triangleIndex * 3 + 2] = static_cast(normal[2]); + } + } + + void operator()(const Range& range) const + { + generate(range.min(), range.max()); + } + +private: + const TriangleGeom* m_TriangleGeom = nullptr; + Float64AbstractDataStore& m_Normals; + const std::atomic_bool& m_ShouldCancel; +}; } // namespace namespace nx::core @@ -123,7 +172,12 @@ Result<> TriangleNormalFilter::executeImpl(DataStructure& dataStructure, const A DataPath pNormalsArrayPath = pTriangleGeometryDataPath.createChildPath(faceAttributeMatrix->getName()).createChildPath(pNormalsName); auto& normals = dataStructure.getDataAs(pNormalsArrayPath)->getDataStoreRef(); - return nx::core::GeometryUtilities::ComputeTriangleNormals(triangleGeom, normals, shouldCancel); + // Parallel algorithm to find duplicate nodes + ParallelDataAlgorithm dataAlg; + dataAlg.setRange(0ULL, static_cast(triangleGeom->getNumberOfFaces())); + dataAlg.execute(CalculateNormalsImpl(triangleGeom, normals, shouldCancel)); + + return {}; } namespace diff --git a/src/simplnx/Utilities/GeometryUtilities.cpp b/src/simplnx/Utilities/GeometryUtilities.cpp index 59e0501b2a..665614b1b1 100644 --- a/src/simplnx/Utilities/GeometryUtilities.cpp +++ b/src/simplnx/Utilities/GeometryUtilities.cpp @@ -2,7 +2,6 @@ #include "simplnx/Common/Array.hpp" #include "simplnx/Common/Result.hpp" -#include "simplnx/Utilities/Math/MatrixMath.hpp" #include From 8eb891183745829cf26ea228f0d6fd8a57e753e5 Mon Sep 17 00:00:00 2001 From: nyoungbq Date: Fri, 15 Nov 2024 15:25:23 -0500 Subject: [PATCH 02/11] V1 Maximum, Median, Minimum, Mean Projection Filters --- src/Plugins/ITKImageProcessing/CMakeLists.txt | 8 +- .../docs/ITKMaximumProjectionImageFilter.md | 70 +++++++++ .../docs/ITKMedianProjectionImageFilter.md | 70 +++++++++ .../docs/ITKMinimumProjectionImageFilter.md | 68 +++++++++ .../ITKMaximumProjectionImageFilter.cpp | 135 +++++++++++++++++ .../ITKMaximumProjectionImageFilter.hpp | 137 ++++++++++++++++++ .../Filters/ITKMeanProjectionImageFilter.hpp | 2 +- .../ITKMedianProjectionImageFilter.cpp | 135 +++++++++++++++++ .../ITKMedianProjectionImageFilter.hpp | 137 ++++++++++++++++++ .../ITKMinimumProjectionImageFilter.cpp | 135 +++++++++++++++++ .../ITKMinimumProjectionImageFilter.hpp | 137 ++++++++++++++++++ 11 files changed, 1029 insertions(+), 5 deletions(-) create mode 100644 src/Plugins/ITKImageProcessing/docs/ITKMaximumProjectionImageFilter.md create mode 100644 src/Plugins/ITKImageProcessing/docs/ITKMedianProjectionImageFilter.md create mode 100644 src/Plugins/ITKImageProcessing/docs/ITKMinimumProjectionImageFilter.md create mode 100644 src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.cpp create mode 100644 src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.hpp create mode 100644 src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp create mode 100644 src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.hpp create mode 100644 src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.cpp create mode 100644 src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.hpp diff --git a/src/Plugins/ITKImageProcessing/CMakeLists.txt b/src/Plugins/ITKImageProcessing/CMakeLists.txt index ee7367bd08..be0d09c6ea 100644 --- a/src/Plugins/ITKImageProcessing/CMakeLists.txt +++ b/src/Plugins/ITKImageProcessing/CMakeLists.txt @@ -167,9 +167,9 @@ if(NOT ITKIMAGEPROCESSING_LEAN_AND_MEAN) # ITKBinaryClosingByReconstructionImage # ITKBinomialBlurImage # ITKLaplacianSharpeningImage - # ITKMaximumProjectionImage - # ITKMedianProjectionImage - # ITKMinimumProjectionImage + ITKMaximumProjectionImageFilter + ITKMedianProjectionImageFilter + ITKMinimumProjectionImageFilter # ITKMultiScaleHessianBasedObjectnessImage # ITKSaltAndPepperNoiseImage # ITKShiftScaleImage @@ -182,7 +182,7 @@ if(NOT ITKIMAGEPROCESSING_LEAN_AND_MEAN) # ----------------------------------------------------------------------------- # ITKBoundedReciprocalImage # ITKNormalizeToConstantImage - # ITKMeanProjectionImage + ITKMeanProjectionImageFilter # ITKStandardDeviationProjectionImage # ITKSumProjectionImage # ITKMorphologicalWatershedFromMarkersImage diff --git a/src/Plugins/ITKImageProcessing/docs/ITKMaximumProjectionImageFilter.md b/src/Plugins/ITKImageProcessing/docs/ITKMaximumProjectionImageFilter.md new file mode 100644 index 0000000000..23687eadf4 --- /dev/null +++ b/src/Plugins/ITKImageProcessing/docs/ITKMaximumProjectionImageFilter.md @@ -0,0 +1,70 @@ +# ITK::Maximum Projection Image Filter (KW) # + + +## Group (Subgroup) ## + +ITKImageProcessing (ITKImageProcessing) + +## Description ## + +Maximum projection. + +This class was contributed to the insight journal by Gaetan Lehmann. The original paper can be found at https://hdl.handle.net/1926/164 + +\author Gaetan Lehmann. Biologie du Developpement et de la reproduction, inra de jouy-en-josas, France. + +\see ProjectionImageFilter + +\see MedianProjectionImageFilter + +\see MeanProjectionImageFilter + +\see MinimumProjectionImageFilter + +\see StandardDeviationProjectionImageFilter + +\see SumProjectionImageFilter + +\see BinaryProjectionImageFilter + +## Parameters ## + +| Name | Type | Description | +|------|------|-------------| +| ProjectionDimension | double| N/A | + + +## Required Geometry ## + +Image + +## Required Objects ## + +| Kind | Default Name | Type | Component Dimensions | Description | +|------|--------------|------|----------------------|-------------| +| **Cell Attribute Array** | None | N/A | (1) | Array containing input image + +## Created Objects ## + +| Kind | Default Name | Type | Component Dimensions | Description | +|------|--------------|------|----------------------|-------------| +| **Cell Attribute Array** | None | | (1) | Array containing filtered image + +## References ## + +[1] T.S. Yoo, M. J. Ackerman, W. E. Lorensen, W. Schroeder, V. Chalana, S. Aylward, D. Metaxas, R. Whitaker. Engineering and Algorithm Design for an Image Processing API: A Technical Report on ITK - The Insight Toolkit. In Proc. of Medicine Meets Virtual Reality, J. Westwood, ed., IOS Press Amsterdam pp 586-592 (2002). +[2] H. Johnson, M. McCormick, L. Ibanez. The ITK Software Guide: Design and Functionality. Fourth Edition. Published by Kitware Inc. 2015 ISBN: 9781-930934-28-3 +[3] H. Johnson, M. McCormick, L. Ibanez. The ITK Software Guide: Introduction and Development Guidelines. Fourth Edition. Published by Kitware Inc. 2015 ISBN: 9781-930934-27-6 + +## Example Pipelines ## + + + +## License & Copyright ## + +Please see the description file distributed with this plugin. + +## DREAM3D Mailing Lists ## + +If you need more help with a filter, please consider asking your question on the DREAM3D Users mailing list: +https://groups.google.com/forum/?hl=en#!forum/dream3d-users diff --git a/src/Plugins/ITKImageProcessing/docs/ITKMedianProjectionImageFilter.md b/src/Plugins/ITKImageProcessing/docs/ITKMedianProjectionImageFilter.md new file mode 100644 index 0000000000..13563a8693 --- /dev/null +++ b/src/Plugins/ITKImageProcessing/docs/ITKMedianProjectionImageFilter.md @@ -0,0 +1,70 @@ +# ITK::Median Projection Image Filter (KW) # + + +## Group (Subgroup) ## + +ITKImageProcessing (ITKImageProcessing) + +## Description ## + +Median projection. + +This class was contributed to the Insight Journal by Gaetan Lehmann. The original paper can be found at https://hdl.handle.net/1926/164 + +\author Gaetan Lehmann. Biologie du Developpement et de la Reproduction, INRA de Jouy-en-Josas, France. + +\see ProjectionImageFilter + +\see StandardDeviationProjectionImageFilter + +\see SumProjectionImageFilter + +\see BinaryProjectionImageFilter + +\see MaximumProjectionImageFilter + +\see MinimumProjectionImageFilter + +\see MeanProjectionImageFilter + +## Parameters ## + +| Name | Type | Description | +|------|------|-------------| +| ProjectionDimension | double| N/A | + + +## Required Geometry ## + +Image + +## Required Objects ## + +| Kind | Default Name | Type | Component Dimensions | Description | +|------|--------------|------|----------------------|-------------| +| **Cell Attribute Array** | None | N/A | (1) | Array containing input image + +## Created Objects ## + +| Kind | Default Name | Type | Component Dimensions | Description | +|------|--------------|------|----------------------|-------------| +| **Cell Attribute Array** | None | | (1) | Array containing filtered image + +## References ## + +[1] T.S. Yoo, M. J. Ackerman, W. E. Lorensen, W. Schroeder, V. Chalana, S. Aylward, D. Metaxas, R. Whitaker. Engineering and Algorithm Design for an Image Processing API: A Technical Report on ITK - The Insight Toolkit. In Proc. of Medicine Meets Virtual Reality, J. Westwood, ed., IOS Press Amsterdam pp 586-592 (2002). +[2] H. Johnson, M. McCormick, L. Ibanez. The ITK Software Guide: Design and Functionality. Fourth Edition. Published by Kitware Inc. 2015 ISBN: 9781-930934-28-3 +[3] H. Johnson, M. McCormick, L. Ibanez. The ITK Software Guide: Introduction and Development Guidelines. Fourth Edition. Published by Kitware Inc. 2015 ISBN: 9781-930934-27-6 + +## Example Pipelines ## + + + +## License & Copyright ## + +Please see the description file distributed with this plugin. + +## DREAM3D Mailing Lists ## + +If you need more help with a filter, please consider asking your question on the DREAM3D Users mailing list: +https://groups.google.com/forum/?hl=en#!forum/dream3d-users diff --git a/src/Plugins/ITKImageProcessing/docs/ITKMinimumProjectionImageFilter.md b/src/Plugins/ITKImageProcessing/docs/ITKMinimumProjectionImageFilter.md new file mode 100644 index 0000000000..f1eac81747 --- /dev/null +++ b/src/Plugins/ITKImageProcessing/docs/ITKMinimumProjectionImageFilter.md @@ -0,0 +1,68 @@ +# ITK::Minimum Projection Image Filter (KW) # + + +## Group (Subgroup) ## + +ITKImageProcessing (ITKImageProcessing) + +## Description ## + +Minimum projection. + +This class was contributed to the Insight Journal by Gaetan Lehmann. The original paper can be found at https://hdl.handle.net/1926/164 + +\author Gaetan Lehmann. Biologie du Developpement et de la Reproduction, INRA de Jouy-en-Josas, France. + +\see ProjectionImageFilter + +\see StandardDeviationProjectionImageFilter + +\see SumProjectionImageFilter + +\see BinaryProjectionImageFilter + +\see MaximumProjectionImageFilter + +\see MeanProjectionImageFilter + +## Parameters ## + +| Name | Type | Description | +|------|------|-------------| +| ProjectionDimension | double| N/A | + + +## Required Geometry ## + +Image + +## Required Objects ## + +| Kind | Default Name | Type | Component Dimensions | Description | +|------|--------------|------|----------------------|-------------| +| **Cell Attribute Array** | None | N/A | (1) | Array containing input image + +## Created Objects ## + +| Kind | Default Name | Type | Component Dimensions | Description | +|------|--------------|------|----------------------|-------------| +| **Cell Attribute Array** | None | | (1) | Array containing filtered image + +## References ## + +[1] T.S. Yoo, M. J. Ackerman, W. E. Lorensen, W. Schroeder, V. Chalana, S. Aylward, D. Metaxas, R. Whitaker. Engineering and Algorithm Design for an Image Processing API: A Technical Report on ITK - The Insight Toolkit. In Proc. of Medicine Meets Virtual Reality, J. Westwood, ed., IOS Press Amsterdam pp 586-592 (2002). +[2] H. Johnson, M. McCormick, L. Ibanez. The ITK Software Guide: Design and Functionality. Fourth Edition. Published by Kitware Inc. 2015 ISBN: 9781-930934-28-3 +[3] H. Johnson, M. McCormick, L. Ibanez. The ITK Software Guide: Introduction and Development Guidelines. Fourth Edition. Published by Kitware Inc. 2015 ISBN: 9781-930934-27-6 + +## Example Pipelines ## + + + +## License & Copyright ## + +Please see the description file distributed with this plugin. + +## DREAM3D Mailing Lists ## + +If you need more help with a filter, please consider asking your question on the DREAM3D Users mailing list: +https://groups.google.com/forum/?hl=en#!forum/dream3d-users diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.cpp new file mode 100644 index 0000000000..8eefb3dbf9 --- /dev/null +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.cpp @@ -0,0 +1,135 @@ +#include "ITKMaximumProjectionImageFilter.hpp" + +#include "ITKImageProcessing/Common/ITKArrayHelper.hpp" +#include "ITKImageProcessing/Common/sitkCommon.hpp" + +#include "simplnx/Parameters/ArraySelectionParameter.hpp" +#include "simplnx/Parameters/DataObjectNameParameter.hpp" +#include "simplnx/Parameters/GeometrySelectionParameter.hpp" +#include "simplnx/Parameters/NumberParameter.hpp" + +#include + +using namespace nx::core; + +namespace cxITKMaximumProjectionImageFilter +{ +using ArrayOptionsType = ITK::ScalarPixelIdTypeList; +// VectorPixelIDTypeList; +template +using FilterOutputType = double; + +struct ITKMaximumProjectionImageFilterFunctor +{ + uint32 projectionDimension = 0u; + + template + auto createFilter() const + { + using FilterType = itk::MaximumProjectionImageFilter; + auto filter = FilterType::New(); + filter->SetProjectionDimension(projectionDimension); + return filter; + } +}; +} // namespace cxITKMaximumProjectionImageFilter + +namespace nx::core +{ +//------------------------------------------------------------------------------ +std::string ITKMaximumProjectionImageFilter::name() const +{ + return FilterTraits::name; +} + +//------------------------------------------------------------------------------ +std::string ITKMaximumProjectionImageFilter::className() const +{ + return FilterTraits::className; +} + +//------------------------------------------------------------------------------ +Uuid ITKMaximumProjectionImageFilter::uuid() const +{ + return FilterTraits::uuid; +} + +//------------------------------------------------------------------------------ +std::string ITKMaximumProjectionImageFilter::humanName() const +{ + return "ITK Mean Projection Image Filter"; +} + +//------------------------------------------------------------------------------ +std::vector ITKMaximumProjectionImageFilter::defaultTags() const +{ + return {className(), "ITKImageProcessing", "ITKMaximumProjectionImageFilter", "ITKImageStatistics", "ImageStatistics"}; +} + +//------------------------------------------------------------------------------ +Parameters ITKMaximumProjectionImageFilter::parameters() const +{ + Parameters params; + params.insertSeparator(Parameters::Separator{"Input Parameter(s)"}); + params.insert(std::make_unique(k_ProjectionDimension_Key, "Projection Dimension", "The dimension index to project. 0=Slowest moving dimension.", 0u)); + + params.insertSeparator(Parameters::Separator{"Input Cell Data"}); + params.insert(std::make_unique(k_InputImageGeomPath_Key, "Image Geometry", "Select the Image Geometry Group from the DataStructure.", DataPath({"Image Geometry"}), + GeometrySelectionParameter::AllowedTypes{IGeometry::Type::Image})); + params.insert(std::make_unique(k_InputImageDataPath_Key, "Input Cell Data", "The image data that will be processed by this filter.", DataPath{}, + nx::core::ITK::GetScalarPixelAllowedTypes())); + + params.insertSeparator(Parameters::Separator{"Output Cell Data"}); + params.insert( + std::make_unique(k_OutputImageArrayName_Key, "Output Image Data Array", "The result of the processing will be stored in this Data Array.", "Output Image Data")); + + return params; +} + +//------------------------------------------------------------------------------ +IFilter::VersionType ITKMaximumProjectionImageFilter::parametersVersion() const +{ + return 1; +} + +//------------------------------------------------------------------------------ +IFilter::UniquePointer ITKMaximumProjectionImageFilter::clone() const +{ + return std::make_unique(); +} + +//------------------------------------------------------------------------------ +IFilter::PreflightResult ITKMaximumProjectionImageFilter::preflightImpl(const DataStructure& dataStructure, const Arguments& filterArgs, const MessageHandler& messageHandler, + const std::atomic_bool& shouldCancel) const +{ + auto imageGeomPath = filterArgs.value(k_InputImageGeomPath_Key); + auto selectedInputArray = filterArgs.value(k_InputImageDataPath_Key); + auto outputArrayName = filterArgs.value(k_OutputImageArrayName_Key); + auto projectionDimension = filterArgs.value(k_ProjectionDimension_Key); + const DataPath outputArrayPath = selectedInputArray.replaceName(outputArrayName); + + Result resultOutputActions = + ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); + + return {std::move(resultOutputActions)}; +} + +//------------------------------------------------------------------------------ +Result<> ITKMaximumProjectionImageFilter::executeImpl(DataStructure& dataStructure, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, + const std::atomic_bool& shouldCancel) const +{ + auto imageGeomPath = filterArgs.value(k_InputImageGeomPath_Key); + auto selectedInputArray = filterArgs.value(k_InputImageDataPath_Key); + auto outputArrayName = filterArgs.value(k_OutputImageArrayName_Key); + const DataPath outputArrayPath = selectedInputArray.replaceName(outputArrayName); + + auto projectionDimension = filterArgs.value(k_ProjectionDimension_Key); + + const cxITKMaximumProjectionImageFilter::ITKMaximumProjectionImageFilterFunctor itkFunctor = {projectionDimension}; + + auto& imageGeom = dataStructure.getDataRefAs(imageGeomPath); + + return ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath, itkFunctor, + shouldCancel); +} +} // namespace nx::core diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.hpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.hpp new file mode 100644 index 0000000000..fba489af3d --- /dev/null +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.hpp @@ -0,0 +1,137 @@ +#pragma once + +#include "ITKImageProcessing/ITKImageProcessing_export.hpp" + +#include "simplnx/Filter/FilterTraits.hpp" +#include "simplnx/Filter/IFilter.hpp" + +namespace nx::core +{ +/** + * @class ITKMaximumProjectionImageFilter + * @brief Maximum projection. + * + * This class was contributed to the Insight Journal by Gaetan Lehmann. The original paper can be found at https://www.insight-journal.org/browse/publication/71 + * + * @author Gaetan Lehmann. Biologie du Developpement et de la Reproduction, INRA de Jouy-en-Josas, France. + * + * + * @see ProjectionImageFilter + * + * + * @see MedianProjectionImageFilter + * + * + * @see MinimumProjectionImageFilter + * + * + * @see StandardDeviationProjectionImageFilter + * + * + * @see SumProjectionImageFilter + * + * + * @see BinaryProjectionImageFilter + * + * + * @see MeanProjectionImageFilter + * + * ITK Module: ITKImageStatistics + * ITK Group: ImageStatistics + */ +class ITKIMAGEPROCESSING_EXPORT ITKMaximumProjectionImageFilter : public IFilter +{ +public: + ITKMaximumProjectionImageFilter() = default; + ~ITKMaximumProjectionImageFilter() noexcept override = default; + + ITKMaximumProjectionImageFilter(const ITKMaximumProjectionImageFilter&) = delete; + ITKMaximumProjectionImageFilter(ITKMaximumProjectionImageFilter&&) noexcept = delete; + + ITKMaximumProjectionImageFilter& operator=(const ITKMaximumProjectionImageFilter&) = delete; + ITKMaximumProjectionImageFilter& operator=(ITKMaximumProjectionImageFilter&&) noexcept = delete; + + // Parameter Keys + static inline constexpr StringLiteral k_InputImageGeomPath_Key = "input_image_geometry_path"; + static inline constexpr StringLiteral k_InputImageDataPath_Key = "input_image_data_path"; + static inline constexpr StringLiteral k_OutputImageArrayName_Key = "output_array_name"; + static inline constexpr StringLiteral k_ProjectionDimension_Key = "projection_dimension"; + + /** + * @brief Returns the name of the filter. + * @return + */ + std::string name() const override; + + /** + * @brief Returns the C++ classname of this filter. + * @return + */ + std::string className() const override; + + /** + * @brief Returns the uuid of the filter. + * @return + */ + Uuid uuid() const override; + + /** + * @brief Returns the human readable name of the filter. + * @return + */ + std::string humanName() const override; + + /** + * @brief Returns the default tags for this filter. + * @return + */ + std::vector defaultTags() const override; + + /** + * @brief Returns the parameters of the filter (i.e. its inputs) + * @return + */ + Parameters parameters() const override; + + /** + * @brief Returns parameters version integer. + * Initial version should always be 1. + * Should be incremented everytime the parameters change. + * @return VersionType + */ + VersionType parametersVersion() const override; + + /** + * @brief Returns a copy of the filter. + * @return + */ + UniquePointer clone() const override; + +protected: + /** + * @brief Takes in a DataStructure and checks that the filter can be run on it with the given arguments. + * Returns any warnings/errors. Also returns the changes that would be applied to the DataStructure. + * Some parts of the actions may not be completely filled out if all the required information is not available at preflight time. + * @param dataStructure The input DataStructure instance + * @param filterArgs These are the input values for each parameter that is required for the filter + * @param messageHandler The MessageHandler object + * @param shouldCancel Boolean that gets set if the filter should stop executing and return + * @return Returns a Result object with error or warning values if any of those occurred during execution of this function + */ + PreflightResult preflightImpl(const DataStructure& dataStructure, const Arguments& filterArgs, const MessageHandler& messageHandler, const std::atomic_bool& shouldCancel) const override; + + /** + * @brief Applies the filter's algorithm to the DataStructure with the given arguments. Returns any warnings/errors. + * On failure, there is no guarantee that the DataStructure is in a correct state. + * @param dataStructure The input DataStructure instance + * @param filterArgs These are the input values for each parameter that is required for the filter + * @param messageHandler The MessageHandler object + * @param shouldCancel Boolean that gets set if the filter should stop executing and return + * @return Returns a Result object with error or warning values if any of those occurred during execution of this function + */ + Result<> executeImpl(DataStructure& dataStructure, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, + const std::atomic_bool& shouldCancel) const override; +}; +} // namespace nx::core + +SIMPLNX_DEF_FILTER_TRAITS(nx::core, ITKMaximumProjectionImageFilter, "6dfe9167-d77d-41c7-aebf-569d6190645d"); diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMeanProjectionImageFilter.hpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMeanProjectionImageFilter.hpp index 20970df02a..fadb7a1756 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMeanProjectionImageFilter.hpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMeanProjectionImageFilter.hpp @@ -134,4 +134,4 @@ class ITKIMAGEPROCESSING_EXPORT ITKMeanProjectionImageFilter : public IFilter }; } // namespace nx::core -SIMPLNX_DEF_FILTER_TRAITS(nx::core, ITKMeanProjectionImageFilter, "6418e0cb-1a6f-43c5-9de4-fdfbb7983809"); +SIMPLNX_DEF_FILTER_TRAITS(nx::core, ITKMeanProjectionImageFilter, "62ffddba-cc57-45fc-a93a-27914eea11ad"); diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp new file mode 100644 index 0000000000..294b3f24ce --- /dev/null +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp @@ -0,0 +1,135 @@ +#include "ITKMedianProjectionImageFilter.hpp" + +#include "ITKImageProcessing/Common/ITKArrayHelper.hpp" +#include "ITKImageProcessing/Common/sitkCommon.hpp" + +#include "simplnx/Parameters/ArraySelectionParameter.hpp" +#include "simplnx/Parameters/DataObjectNameParameter.hpp" +#include "simplnx/Parameters/GeometrySelectionParameter.hpp" +#include "simplnx/Parameters/NumberParameter.hpp" + +#include + +using namespace nx::core; + +namespace cxITKMedianProjectionImageFilter +{ +using ArrayOptionsType = ITK::ScalarPixelIdTypeList; +// VectorPixelIDTypeList; +template +using FilterOutputType = double; + +struct ITKMedianProjectionImageFilterFunctor +{ + uint32 projectionDimension = 0u; + + template + auto createFilter() const + { + using FilterType = itk::MedianProjectionImageFilter; + auto filter = FilterType::New(); + filter->SetProjectionDimension(projectionDimension); + return filter; + } +}; +} // namespace cxITKMedianProjectionImageFilter + +namespace nx::core +{ +//------------------------------------------------------------------------------ +std::string ITKMedianProjectionImageFilter::name() const +{ + return FilterTraits::name; +} + +//------------------------------------------------------------------------------ +std::string ITKMedianProjectionImageFilter::className() const +{ + return FilterTraits::className; +} + +//------------------------------------------------------------------------------ +Uuid ITKMedianProjectionImageFilter::uuid() const +{ + return FilterTraits::uuid; +} + +//------------------------------------------------------------------------------ +std::string ITKMedianProjectionImageFilter::humanName() const +{ + return "ITK Mean Projection Image Filter"; +} + +//------------------------------------------------------------------------------ +std::vector ITKMedianProjectionImageFilter::defaultTags() const +{ + return {className(), "ITKImageProcessing", "ITKMedianProjectionImageFilter", "ITKImageStatistics", "ImageStatistics"}; +} + +//------------------------------------------------------------------------------ +Parameters ITKMedianProjectionImageFilter::parameters() const +{ + Parameters params; + params.insertSeparator(Parameters::Separator{"Input Parameter(s)"}); + params.insert(std::make_unique(k_ProjectionDimension_Key, "Projection Dimension", "The dimension index to project. 0=Slowest moving dimension.", 0u)); + + params.insertSeparator(Parameters::Separator{"Input Cell Data"}); + params.insert(std::make_unique(k_InputImageGeomPath_Key, "Image Geometry", "Select the Image Geometry Group from the DataStructure.", DataPath({"Image Geometry"}), + GeometrySelectionParameter::AllowedTypes{IGeometry::Type::Image})); + params.insert(std::make_unique(k_InputImageDataPath_Key, "Input Cell Data", "The image data that will be processed by this filter.", DataPath{}, + nx::core::ITK::GetScalarPixelAllowedTypes())); + + params.insertSeparator(Parameters::Separator{"Output Cell Data"}); + params.insert( + std::make_unique(k_OutputImageArrayName_Key, "Output Image Data Array", "The result of the processing will be stored in this Data Array.", "Output Image Data")); + + return params; +} + +//------------------------------------------------------------------------------ +IFilter::VersionType ITKMedianProjectionImageFilter::parametersVersion() const +{ + return 1; +} + +//------------------------------------------------------------------------------ +IFilter::UniquePointer ITKMedianProjectionImageFilter::clone() const +{ + return std::make_unique(); +} + +//------------------------------------------------------------------------------ +IFilter::PreflightResult ITKMedianProjectionImageFilter::preflightImpl(const DataStructure& dataStructure, const Arguments& filterArgs, const MessageHandler& messageHandler, + const std::atomic_bool& shouldCancel) const +{ + auto imageGeomPath = filterArgs.value(k_InputImageGeomPath_Key); + auto selectedInputArray = filterArgs.value(k_InputImageDataPath_Key); + auto outputArrayName = filterArgs.value(k_OutputImageArrayName_Key); + auto projectionDimension = filterArgs.value(k_ProjectionDimension_Key); + const DataPath outputArrayPath = selectedInputArray.replaceName(outputArrayName); + + Result resultOutputActions = + ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); + + return {std::move(resultOutputActions)}; +} + +//------------------------------------------------------------------------------ +Result<> ITKMedianProjectionImageFilter::executeImpl(DataStructure& dataStructure, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, + const std::atomic_bool& shouldCancel) const +{ + auto imageGeomPath = filterArgs.value(k_InputImageGeomPath_Key); + auto selectedInputArray = filterArgs.value(k_InputImageDataPath_Key); + auto outputArrayName = filterArgs.value(k_OutputImageArrayName_Key); + const DataPath outputArrayPath = selectedInputArray.replaceName(outputArrayName); + + auto projectionDimension = filterArgs.value(k_ProjectionDimension_Key); + + const cxITKMedianProjectionImageFilter::ITKMedianProjectionImageFilterFunctor itkFunctor = {projectionDimension}; + + auto& imageGeom = dataStructure.getDataRefAs(imageGeomPath); + + return ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath, itkFunctor, + shouldCancel); +} +} // namespace nx::core diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.hpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.hpp new file mode 100644 index 0000000000..68b4f15833 --- /dev/null +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.hpp @@ -0,0 +1,137 @@ +#pragma once + +#include "ITKImageProcessing/ITKImageProcessing_export.hpp" + +#include "simplnx/Filter/FilterTraits.hpp" +#include "simplnx/Filter/IFilter.hpp" + +namespace nx::core +{ +/** + * @class ITKMedianProjectionImageFilter + * @brief Median projection. + * + * This class was contributed to the Insight Journal by Gaetan Lehmann. The original paper can be found at https://www.insight-journal.org/browse/publication/71 + * + * @author Gaetan Lehmann. Biologie du Developpement et de la Reproduction, INRA de Jouy-en-Josas, France. + * + * + * @see ProjectionImageFilter + * + * + * @see MeanProjectionImageFilter + * + * + * @see MinimumProjectionImageFilter + * + * + * @see StandardDeviationProjectionImageFilter + * + * + * @see SumProjectionImageFilter + * + * + * @see BinaryProjectionImageFilter + * + * + * @see MaximumProjectionImageFilter + * + * ITK Module: ITKImageStatistics + * ITK Group: ImageStatistics + */ +class ITKIMAGEPROCESSING_EXPORT ITKMedianProjectionImageFilter : public IFilter +{ +public: + ITKMedianProjectionImageFilter() = default; + ~ITKMedianProjectionImageFilter() noexcept override = default; + + ITKMedianProjectionImageFilter(const ITKMedianProjectionImageFilter&) = delete; + ITKMedianProjectionImageFilter(ITKMedianProjectionImageFilter&&) noexcept = delete; + + ITKMedianProjectionImageFilter& operator=(const ITKMedianProjectionImageFilter&) = delete; + ITKMedianProjectionImageFilter& operator=(ITKMedianProjectionImageFilter&&) noexcept = delete; + + // Parameter Keys + static inline constexpr StringLiteral k_InputImageGeomPath_Key = "input_image_geometry_path"; + static inline constexpr StringLiteral k_InputImageDataPath_Key = "input_image_data_path"; + static inline constexpr StringLiteral k_OutputImageArrayName_Key = "output_array_name"; + static inline constexpr StringLiteral k_ProjectionDimension_Key = "projection_dimension"; + + /** + * @brief Returns the name of the filter. + * @return + */ + std::string name() const override; + + /** + * @brief Returns the C++ classname of this filter. + * @return + */ + std::string className() const override; + + /** + * @brief Returns the uuid of the filter. + * @return + */ + Uuid uuid() const override; + + /** + * @brief Returns the human readable name of the filter. + * @return + */ + std::string humanName() const override; + + /** + * @brief Returns the default tags for this filter. + * @return + */ + std::vector defaultTags() const override; + + /** + * @brief Returns the parameters of the filter (i.e. its inputs) + * @return + */ + Parameters parameters() const override; + + /** + * @brief Returns parameters version integer. + * Initial version should always be 1. + * Should be incremented everytime the parameters change. + * @return VersionType + */ + VersionType parametersVersion() const override; + + /** + * @brief Returns a copy of the filter. + * @return + */ + UniquePointer clone() const override; + +protected: + /** + * @brief Takes in a DataStructure and checks that the filter can be run on it with the given arguments. + * Returns any warnings/errors. Also returns the changes that would be applied to the DataStructure. + * Some parts of the actions may not be completely filled out if all the required information is not available at preflight time. + * @param dataStructure The input DataStructure instance + * @param filterArgs These are the input values for each parameter that is required for the filter + * @param messageHandler The MessageHandler object + * @param shouldCancel Boolean that gets set if the filter should stop executing and return + * @return Returns a Result object with error or warning values if any of those occurred during execution of this function + */ + PreflightResult preflightImpl(const DataStructure& dataStructure, const Arguments& filterArgs, const MessageHandler& messageHandler, const std::atomic_bool& shouldCancel) const override; + + /** + * @brief Applies the filter's algorithm to the DataStructure with the given arguments. Returns any warnings/errors. + * On failure, there is no guarantee that the DataStructure is in a correct state. + * @param dataStructure The input DataStructure instance + * @param filterArgs These are the input values for each parameter that is required for the filter + * @param messageHandler The MessageHandler object + * @param shouldCancel Boolean that gets set if the filter should stop executing and return + * @return Returns a Result object with error or warning values if any of those occurred during execution of this function + */ + Result<> executeImpl(DataStructure& dataStructure, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, + const std::atomic_bool& shouldCancel) const override; +}; +} // namespace nx::core + +SIMPLNX_DEF_FILTER_TRAITS(nx::core, ITKMedianProjectionImageFilter, "00e48f6b-8a00-414f-b3d9-49d48a3f9a00"); diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.cpp new file mode 100644 index 0000000000..4fb2c0d909 --- /dev/null +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.cpp @@ -0,0 +1,135 @@ +#include "ITKMinimumProjectionImageFilter.hpp" + +#include "ITKImageProcessing/Common/ITKArrayHelper.hpp" +#include "ITKImageProcessing/Common/sitkCommon.hpp" + +#include "simplnx/Parameters/ArraySelectionParameter.hpp" +#include "simplnx/Parameters/DataObjectNameParameter.hpp" +#include "simplnx/Parameters/GeometrySelectionParameter.hpp" +#include "simplnx/Parameters/NumberParameter.hpp" + +#include + +using namespace nx::core; + +namespace cxITKMinimumProjectionImageFilter +{ +using ArrayOptionsType = ITK::ScalarPixelIdTypeList; +// VectorPixelIDTypeList; +template +using FilterOutputType = double; + +struct ITKMinimumProjectionImageFilterFunctor +{ + uint32 projectionDimension = 0u; + + template + auto createFilter() const + { + using FilterType = itk::MinimumProjectionImageFilter; + auto filter = FilterType::New(); + filter->SetProjectionDimension(projectionDimension); + return filter; + } +}; +} // namespace cxITKMinimumProjectionImageFilter + +namespace nx::core +{ +//------------------------------------------------------------------------------ +std::string ITKMinimumProjectionImageFilter::name() const +{ + return FilterTraits::name; +} + +//------------------------------------------------------------------------------ +std::string ITKMinimumProjectionImageFilter::className() const +{ + return FilterTraits::className; +} + +//------------------------------------------------------------------------------ +Uuid ITKMinimumProjectionImageFilter::uuid() const +{ + return FilterTraits::uuid; +} + +//------------------------------------------------------------------------------ +std::string ITKMinimumProjectionImageFilter::humanName() const +{ + return "ITK Mean Projection Image Filter"; +} + +//------------------------------------------------------------------------------ +std::vector ITKMinimumProjectionImageFilter::defaultTags() const +{ + return {className(), "ITKImageProcessing", "ITKMinimumProjectionImageFilter", "ITKImageStatistics", "ImageStatistics"}; +} + +//------------------------------------------------------------------------------ +Parameters ITKMinimumProjectionImageFilter::parameters() const +{ + Parameters params; + params.insertSeparator(Parameters::Separator{"Input Parameter(s)"}); + params.insert(std::make_unique(k_ProjectionDimension_Key, "Projection Dimension", "The dimension index to project. 0=Slowest moving dimension.", 0u)); + + params.insertSeparator(Parameters::Separator{"Input Cell Data"}); + params.insert(std::make_unique(k_InputImageGeomPath_Key, "Image Geometry", "Select the Image Geometry Group from the DataStructure.", DataPath({"Image Geometry"}), + GeometrySelectionParameter::AllowedTypes{IGeometry::Type::Image})); + params.insert(std::make_unique(k_InputImageDataPath_Key, "Input Cell Data", "The image data that will be processed by this filter.", DataPath{}, + nx::core::ITK::GetScalarPixelAllowedTypes())); + + params.insertSeparator(Parameters::Separator{"Output Cell Data"}); + params.insert( + std::make_unique(k_OutputImageArrayName_Key, "Output Image Data Array", "The result of the processing will be stored in this Data Array.", "Output Image Data")); + + return params; +} + +//------------------------------------------------------------------------------ +IFilter::VersionType ITKMinimumProjectionImageFilter::parametersVersion() const +{ + return 1; +} + +//------------------------------------------------------------------------------ +IFilter::UniquePointer ITKMinimumProjectionImageFilter::clone() const +{ + return std::make_unique(); +} + +//------------------------------------------------------------------------------ +IFilter::PreflightResult ITKMinimumProjectionImageFilter::preflightImpl(const DataStructure& dataStructure, const Arguments& filterArgs, const MessageHandler& messageHandler, + const std::atomic_bool& shouldCancel) const +{ + auto imageGeomPath = filterArgs.value(k_InputImageGeomPath_Key); + auto selectedInputArray = filterArgs.value(k_InputImageDataPath_Key); + auto outputArrayName = filterArgs.value(k_OutputImageArrayName_Key); + auto projectionDimension = filterArgs.value(k_ProjectionDimension_Key); + const DataPath outputArrayPath = selectedInputArray.replaceName(outputArrayName); + + Result resultOutputActions = + ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); + + return {std::move(resultOutputActions)}; +} + +//------------------------------------------------------------------------------ +Result<> ITKMinimumProjectionImageFilter::executeImpl(DataStructure& dataStructure, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, + const std::atomic_bool& shouldCancel) const +{ + auto imageGeomPath = filterArgs.value(k_InputImageGeomPath_Key); + auto selectedInputArray = filterArgs.value(k_InputImageDataPath_Key); + auto outputArrayName = filterArgs.value(k_OutputImageArrayName_Key); + const DataPath outputArrayPath = selectedInputArray.replaceName(outputArrayName); + + auto projectionDimension = filterArgs.value(k_ProjectionDimension_Key); + + const cxITKMinimumProjectionImageFilter::ITKMinimumProjectionImageFilterFunctor itkFunctor = {projectionDimension}; + + auto& imageGeom = dataStructure.getDataRefAs(imageGeomPath); + + return ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath, itkFunctor, + shouldCancel); +} +} // namespace nx::core diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.hpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.hpp new file mode 100644 index 0000000000..7db396b2f0 --- /dev/null +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.hpp @@ -0,0 +1,137 @@ +#pragma once + +#include "ITKImageProcessing/ITKImageProcessing_export.hpp" + +#include "simplnx/Filter/FilterTraits.hpp" +#include "simplnx/Filter/IFilter.hpp" + +namespace nx::core +{ +/** + * @class ITKMinimumProjectionImageFilter + * @brief Minimum projection. + * + * This class was contributed to the Insight Journal by Gaetan Lehmann. The original paper can be found at https://www.insight-journal.org/browse/publication/71 + * + * @author Gaetan Lehmann. Biologie du Developpement et de la Reproduction, INRA de Jouy-en-Josas, France. + * + * + * @see ProjectionImageFilter + * + * + * @see MedianProjectionImageFilter + * + * + * @see MeanProjectionImageFilter + * + * + * @see StandardDeviationProjectionImageFilter + * + * + * @see SumProjectionImageFilter + * + * + * @see BinaryProjectionImageFilter + * + * + * @see MaximumProjectionImageFilter + * + * ITK Module: ITKImageStatistics + * ITK Group: ImageStatistics + */ +class ITKIMAGEPROCESSING_EXPORT ITKMinimumProjectionImageFilter : public IFilter +{ +public: + ITKMinimumProjectionImageFilter() = default; + ~ITKMinimumProjectionImageFilter() noexcept override = default; + + ITKMinimumProjectionImageFilter(const ITKMinimumProjectionImageFilter&) = delete; + ITKMinimumProjectionImageFilter(ITKMinimumProjectionImageFilter&&) noexcept = delete; + + ITKMinimumProjectionImageFilter& operator=(const ITKMinimumProjectionImageFilter&) = delete; + ITKMinimumProjectionImageFilter& operator=(ITKMinimumProjectionImageFilter&&) noexcept = delete; + + // Parameter Keys + static inline constexpr StringLiteral k_InputImageGeomPath_Key = "input_image_geometry_path"; + static inline constexpr StringLiteral k_InputImageDataPath_Key = "input_image_data_path"; + static inline constexpr StringLiteral k_OutputImageArrayName_Key = "output_array_name"; + static inline constexpr StringLiteral k_ProjectionDimension_Key = "projection_dimension"; + + /** + * @brief Returns the name of the filter. + * @return + */ + std::string name() const override; + + /** + * @brief Returns the C++ classname of this filter. + * @return + */ + std::string className() const override; + + /** + * @brief Returns the uuid of the filter. + * @return + */ + Uuid uuid() const override; + + /** + * @brief Returns the human readable name of the filter. + * @return + */ + std::string humanName() const override; + + /** + * @brief Returns the default tags for this filter. + * @return + */ + std::vector defaultTags() const override; + + /** + * @brief Returns the parameters of the filter (i.e. its inputs) + * @return + */ + Parameters parameters() const override; + + /** + * @brief Returns parameters version integer. + * Initial version should always be 1. + * Should be incremented everytime the parameters change. + * @return VersionType + */ + VersionType parametersVersion() const override; + + /** + * @brief Returns a copy of the filter. + * @return + */ + UniquePointer clone() const override; + +protected: + /** + * @brief Takes in a DataStructure and checks that the filter can be run on it with the given arguments. + * Returns any warnings/errors. Also returns the changes that would be applied to the DataStructure. + * Some parts of the actions may not be completely filled out if all the required information is not available at preflight time. + * @param dataStructure The input DataStructure instance + * @param filterArgs These are the input values for each parameter that is required for the filter + * @param messageHandler The MessageHandler object + * @param shouldCancel Boolean that gets set if the filter should stop executing and return + * @return Returns a Result object with error or warning values if any of those occurred during execution of this function + */ + PreflightResult preflightImpl(const DataStructure& dataStructure, const Arguments& filterArgs, const MessageHandler& messageHandler, const std::atomic_bool& shouldCancel) const override; + + /** + * @brief Applies the filter's algorithm to the DataStructure with the given arguments. Returns any warnings/errors. + * On failure, there is no guarantee that the DataStructure is in a correct state. + * @param dataStructure The input DataStructure instance + * @param filterArgs These are the input values for each parameter that is required for the filter + * @param messageHandler The MessageHandler object + * @param shouldCancel Boolean that gets set if the filter should stop executing and return + * @return Returns a Result object with error or warning values if any of those occurred during execution of this function + */ + Result<> executeImpl(DataStructure& dataStructure, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, + const std::atomic_bool& shouldCancel) const override; +}; +} // namespace nx::core + +SIMPLNX_DEF_FILTER_TRAITS(nx::core, ITKMinimumProjectionImageFilter, "86898336-8680-4c4e-b166-3f8de9e3d4f2"); From fa9302e86753fd73d2e4ec0fcb214698719fb69a Mon Sep 17 00:00:00 2001 From: nyoungbq Date: Tue, 19 Nov 2024 12:08:04 -0500 Subject: [PATCH 03/11] Update documentation, test cases, extraneous code removal --- .../docs/ITKMaximumProjectionImageFilter.md | 67 ++++++------------- .../docs/ITKMeanProjectionImageFilter.md | 2 +- .../docs/ITKMedianProjectionImageFilter.md | 67 ++++++------------- .../docs/ITKMinimumProjectionImageFilter.md | 65 ++++++------------ .../ITKMaximumProjectionImageFilter.cpp | 3 - .../Filters/ITKMeanProjectionImageFilter.cpp | 3 - .../ITKMedianProjectionImageFilter.cpp | 3 - .../ITKMinimumProjectionImageFilter.cpp | 3 - .../ITKImageProcessing/test/CMakeLists.txt | 4 ++ .../test/ITKMaximumProjectionImageTest.cpp | 54 +++++++++++++++ .../test/ITKMeanProjectionImageTest.cpp | 2 +- .../test/ITKMedianProjectionImageTest.cpp | 54 +++++++++++++++ .../test/ITKMinimumProjectionImageTest.cpp | 54 +++++++++++++++ 13 files changed, 228 insertions(+), 153 deletions(-) create mode 100644 src/Plugins/ITKImageProcessing/test/ITKMaximumProjectionImageTest.cpp create mode 100644 src/Plugins/ITKImageProcessing/test/ITKMedianProjectionImageTest.cpp create mode 100644 src/Plugins/ITKImageProcessing/test/ITKMinimumProjectionImageTest.cpp diff --git a/src/Plugins/ITKImageProcessing/docs/ITKMaximumProjectionImageFilter.md b/src/Plugins/ITKImageProcessing/docs/ITKMaximumProjectionImageFilter.md index 23687eadf4..e6dcd8eff6 100644 --- a/src/Plugins/ITKImageProcessing/docs/ITKMaximumProjectionImageFilter.md +++ b/src/Plugins/ITKImageProcessing/docs/ITKMaximumProjectionImageFilter.md @@ -1,70 +1,43 @@ -# ITK::Maximum Projection Image Filter (KW) # - - -## Group (Subgroup) ## - -ITKImageProcessing (ITKImageProcessing) - -## Description ## +# ITK Maximum Projection Image Filter (ITKMaximumProjectionImage) Maximum projection. -This class was contributed to the insight journal by Gaetan Lehmann. The original paper can be found at https://hdl.handle.net/1926/164 - -\author Gaetan Lehmann. Biologie du Developpement et de la reproduction, inra de jouy-en-josas, France. - -\see ProjectionImageFilter - -\see MedianProjectionImageFilter - -\see MeanProjectionImageFilter - -\see MinimumProjectionImageFilter - -\see StandardDeviationProjectionImageFilter - -\see SumProjectionImageFilter +## Group (Subgroup) -\see BinaryProjectionImageFilter +ITKImageStatistics (ImageStatistics) -## Parameters ## +## Description -| Name | Type | Description | -|------|------|-------------| -| ProjectionDimension | double| N/A | +This class was contributed to the Insight Journal by Gaetan Lehmann. The original paper can be found at https://www.insight-journal.org/browse/publication/71 +## Author -## Required Geometry ## +- Gaetan Lehmann. Biologie du Developpement et de la Reproduction, INRA de Jouy-en-Josas, France. -Image +## See Also -## Required Objects ## +- [ProjectionImageFilter](https://itk.org/Doxygen/html/classitk_1_1ProjectionImageFilter.html) -| Kind | Default Name | Type | Component Dimensions | Description | -|------|--------------|------|----------------------|-------------| -| **Cell Attribute Array** | None | N/A | (1) | Array containing input image +- [MedianProjectionImageFilter](https://itk.org/Doxygen/html/classitk_1_1MedianProjectionImageFilter.html) -## Created Objects ## +- [MinimumProjectionImageFilter](https://itk.org/Doxygen/html/classitk_1_1MinimumProjectionImageFilter.html) -| Kind | Default Name | Type | Component Dimensions | Description | -|------|--------------|------|----------------------|-------------| -| **Cell Attribute Array** | None | | (1) | Array containing filtered image +- [StandardDeviationProjectionImageFilter](https://itk.org/Doxygen/html/classitk_1_1StandardDeviationProjectionImageFilter.html) -## References ## +- [SumProjectionImageFilter](https://itk.org/Doxygen/html/classitk_1_1SumProjectionImageFilter.html) -[1] T.S. Yoo, M. J. Ackerman, W. E. Lorensen, W. Schroeder, V. Chalana, S. Aylward, D. Metaxas, R. Whitaker. Engineering and Algorithm Design for an Image Processing API: A Technical Report on ITK - The Insight Toolkit. In Proc. of Medicine Meets Virtual Reality, J. Westwood, ed., IOS Press Amsterdam pp 586-592 (2002). -[2] H. Johnson, M. McCormick, L. Ibanez. The ITK Software Guide: Design and Functionality. Fourth Edition. Published by Kitware Inc. 2015 ISBN: 9781-930934-28-3 -[3] H. Johnson, M. McCormick, L. Ibanez. The ITK Software Guide: Introduction and Development Guidelines. Fourth Edition. Published by Kitware Inc. 2015 ISBN: 9781-930934-27-6 +- [BinaryProjectionImageFilter](https://itk.org/Doxygen/html/classitk_1_1BinaryProjectionImageFilter.html) -## Example Pipelines ## +- [MeanProjectionImageFilter](https://itk.org/Doxygen/html/classitk_1_1MeanProjectionImageFilter.html) +% Auto generated parameter table will be inserted here +## Example Pipelines -## License & Copyright ## +## License & Copyright Please see the description file distributed with this plugin. -## DREAM3D Mailing Lists ## +## DREAM3D-NX Help -If you need more help with a filter, please consider asking your question on the DREAM3D Users mailing list: -https://groups.google.com/forum/?hl=en#!forum/dream3d-users +If you need help, need to file a bug report or want to request a new feature, please head over to the [DREAM3DNX-Issues](https://github.com/BlueQuartzSoftware/DREAM3DNX-Issues/discussions) GitHub site where the community of DREAM3D-NX users can help answer your questions. diff --git a/src/Plugins/ITKImageProcessing/docs/ITKMeanProjectionImageFilter.md b/src/Plugins/ITKImageProcessing/docs/ITKMeanProjectionImageFilter.md index 625507044b..b079821f1c 100644 --- a/src/Plugins/ITKImageProcessing/docs/ITKMeanProjectionImageFilter.md +++ b/src/Plugins/ITKImageProcessing/docs/ITKMeanProjectionImageFilter.md @@ -38,6 +38,6 @@ This class was contributed to the Insight Journal by Gaetan Lehmann. The origina Please see the description file distributed with this plugin. -## DREAM3D Mailing Lists +## DREAM3D-NX Help If you need help, need to file a bug report or want to request a new feature, please head over to the [DREAM3DNX-Issues](https://github.com/BlueQuartzSoftware/DREAM3DNX-Issues/discussions) GitHub site where the community of DREAM3D-NX users can help answer your questions. diff --git a/src/Plugins/ITKImageProcessing/docs/ITKMedianProjectionImageFilter.md b/src/Plugins/ITKImageProcessing/docs/ITKMedianProjectionImageFilter.md index 13563a8693..9edf342eca 100644 --- a/src/Plugins/ITKImageProcessing/docs/ITKMedianProjectionImageFilter.md +++ b/src/Plugins/ITKImageProcessing/docs/ITKMedianProjectionImageFilter.md @@ -1,70 +1,43 @@ -# ITK::Median Projection Image Filter (KW) # - - -## Group (Subgroup) ## - -ITKImageProcessing (ITKImageProcessing) - -## Description ## +# ITK Median Projection Image Filter (ITKMedianProjectionImage) Median projection. -This class was contributed to the Insight Journal by Gaetan Lehmann. The original paper can be found at https://hdl.handle.net/1926/164 - -\author Gaetan Lehmann. Biologie du Developpement et de la Reproduction, INRA de Jouy-en-Josas, France. - -\see ProjectionImageFilter - -\see StandardDeviationProjectionImageFilter - -\see SumProjectionImageFilter - -\see BinaryProjectionImageFilter - -\see MaximumProjectionImageFilter - -\see MinimumProjectionImageFilter +## Group (Subgroup) -\see MeanProjectionImageFilter +ITKImageStatistics (ImageStatistics) -## Parameters ## +## Description -| Name | Type | Description | -|------|------|-------------| -| ProjectionDimension | double| N/A | +This class was contributed to the Insight Journal by Gaetan Lehmann. The original paper can be found at https://www.insight-journal.org/browse/publication/71 +## Author -## Required Geometry ## +- Gaetan Lehmann. Biologie du Developpement et de la Reproduction, INRA de Jouy-en-Josas, France. -Image +## See Also -## Required Objects ## +- [ProjectionImageFilter](https://itk.org/Doxygen/html/classitk_1_1ProjectionImageFilter.html) -| Kind | Default Name | Type | Component Dimensions | Description | -|------|--------------|------|----------------------|-------------| -| **Cell Attribute Array** | None | N/A | (1) | Array containing input image +- [MeanProjectionImageFilter](https://itk.org/Doxygen/html/classitk_1_1MeanProjectionImageFilter.html) -## Created Objects ## +- [MinimumProjectionImageFilter](https://itk.org/Doxygen/html/classitk_1_1MinimumProjectionImageFilter.html) -| Kind | Default Name | Type | Component Dimensions | Description | -|------|--------------|------|----------------------|-------------| -| **Cell Attribute Array** | None | | (1) | Array containing filtered image +- [StandardDeviationProjectionImageFilter](https://itk.org/Doxygen/html/classitk_1_1StandardDeviationProjectionImageFilter.html) -## References ## +- [SumProjectionImageFilter](https://itk.org/Doxygen/html/classitk_1_1SumProjectionImageFilter.html) -[1] T.S. Yoo, M. J. Ackerman, W. E. Lorensen, W. Schroeder, V. Chalana, S. Aylward, D. Metaxas, R. Whitaker. Engineering and Algorithm Design for an Image Processing API: A Technical Report on ITK - The Insight Toolkit. In Proc. of Medicine Meets Virtual Reality, J. Westwood, ed., IOS Press Amsterdam pp 586-592 (2002). -[2] H. Johnson, M. McCormick, L. Ibanez. The ITK Software Guide: Design and Functionality. Fourth Edition. Published by Kitware Inc. 2015 ISBN: 9781-930934-28-3 -[3] H. Johnson, M. McCormick, L. Ibanez. The ITK Software Guide: Introduction and Development Guidelines. Fourth Edition. Published by Kitware Inc. 2015 ISBN: 9781-930934-27-6 +- [BinaryProjectionImageFilter](https://itk.org/Doxygen/html/classitk_1_1BinaryProjectionImageFilter.html) -## Example Pipelines ## +- [MaximumProjectionImageFilter](https://itk.org/Doxygen/html/classitk_1_1MaximumProjectionImageFilter.html) +% Auto generated parameter table will be inserted here +## Example Pipelines -## License & Copyright ## +## License & Copyright Please see the description file distributed with this plugin. -## DREAM3D Mailing Lists ## +## DREAM3D-NX Help -If you need more help with a filter, please consider asking your question on the DREAM3D Users mailing list: -https://groups.google.com/forum/?hl=en#!forum/dream3d-users +If you need help, need to file a bug report or want to request a new feature, please head over to the [DREAM3DNX-Issues](https://github.com/BlueQuartzSoftware/DREAM3DNX-Issues/discussions) GitHub site where the community of DREAM3D-NX users can help answer your questions. diff --git a/src/Plugins/ITKImageProcessing/docs/ITKMinimumProjectionImageFilter.md b/src/Plugins/ITKImageProcessing/docs/ITKMinimumProjectionImageFilter.md index f1eac81747..b4ac3d85e8 100644 --- a/src/Plugins/ITKImageProcessing/docs/ITKMinimumProjectionImageFilter.md +++ b/src/Plugins/ITKImageProcessing/docs/ITKMinimumProjectionImageFilter.md @@ -1,68 +1,43 @@ -# ITK::Minimum Projection Image Filter (KW) # - - -## Group (Subgroup) ## - -ITKImageProcessing (ITKImageProcessing) - -## Description ## +# ITK Minimum Projection Image Filter (ITKMinimumProjectionImage) Minimum projection. -This class was contributed to the Insight Journal by Gaetan Lehmann. The original paper can be found at https://hdl.handle.net/1926/164 - -\author Gaetan Lehmann. Biologie du Developpement et de la Reproduction, INRA de Jouy-en-Josas, France. - -\see ProjectionImageFilter - -\see StandardDeviationProjectionImageFilter - -\see SumProjectionImageFilter - -\see BinaryProjectionImageFilter - -\see MaximumProjectionImageFilter +## Group (Subgroup) -\see MeanProjectionImageFilter +ITKImageStatistics (ImageStatistics) -## Parameters ## +## Description -| Name | Type | Description | -|------|------|-------------| -| ProjectionDimension | double| N/A | +This class was contributed to the Insight Journal by Gaetan Lehmann. The original paper can be found at https://www.insight-journal.org/browse/publication/71 +## Author -## Required Geometry ## +- Gaetan Lehmann. Biologie du Developpement et de la Reproduction, INRA de Jouy-en-Josas, France. -Image +## See Also -## Required Objects ## +- [ProjectionImageFilter](https://itk.org/Doxygen/html/classitk_1_1ProjectionImageFilter.html) -| Kind | Default Name | Type | Component Dimensions | Description | -|------|--------------|------|----------------------|-------------| -| **Cell Attribute Array** | None | N/A | (1) | Array containing input image +- [MedianProjectionImageFilter](https://itk.org/Doxygen/html/classitk_1_1MedianProjectionImageFilter.html) -## Created Objects ## +- [MeanProjectionImageFilter](https://itk.org/Doxygen/html/classitk_1_1MeanProjectionImageFilter.html) -| Kind | Default Name | Type | Component Dimensions | Description | -|------|--------------|------|----------------------|-------------| -| **Cell Attribute Array** | None | | (1) | Array containing filtered image +- [StandardDeviationProjectionImageFilter](https://itk.org/Doxygen/html/classitk_1_1StandardDeviationProjectionImageFilter.html) -## References ## +- [SumProjectionImageFilter](https://itk.org/Doxygen/html/classitk_1_1SumProjectionImageFilter.html) -[1] T.S. Yoo, M. J. Ackerman, W. E. Lorensen, W. Schroeder, V. Chalana, S. Aylward, D. Metaxas, R. Whitaker. Engineering and Algorithm Design for an Image Processing API: A Technical Report on ITK - The Insight Toolkit. In Proc. of Medicine Meets Virtual Reality, J. Westwood, ed., IOS Press Amsterdam pp 586-592 (2002). -[2] H. Johnson, M. McCormick, L. Ibanez. The ITK Software Guide: Design and Functionality. Fourth Edition. Published by Kitware Inc. 2015 ISBN: 9781-930934-28-3 -[3] H. Johnson, M. McCormick, L. Ibanez. The ITK Software Guide: Introduction and Development Guidelines. Fourth Edition. Published by Kitware Inc. 2015 ISBN: 9781-930934-27-6 +- [BinaryProjectionImageFilter](https://itk.org/Doxygen/html/classitk_1_1BinaryProjectionImageFilter.html) -## Example Pipelines ## +- [MaximumProjectionImageFilter](https://itk.org/Doxygen/html/classitk_1_1MaximumProjectionImageFilter.html) +% Auto generated parameter table will be inserted here +## Example Pipelines -## License & Copyright ## +## License & Copyright Please see the description file distributed with this plugin. -## DREAM3D Mailing Lists ## +## DREAM3D-NX Help -If you need more help with a filter, please consider asking your question on the DREAM3D Users mailing list: -https://groups.google.com/forum/?hl=en#!forum/dream3d-users +If you need help, need to file a bug report or want to request a new feature, please head over to the [DREAM3DNX-Issues](https://github.com/BlueQuartzSoftware/DREAM3DNX-Issues/discussions) GitHub site where the community of DREAM3D-NX users can help answer your questions. diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.cpp index 8eefb3dbf9..df9d13dc68 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.cpp @@ -1,7 +1,6 @@ #include "ITKMaximumProjectionImageFilter.hpp" #include "ITKImageProcessing/Common/ITKArrayHelper.hpp" -#include "ITKImageProcessing/Common/sitkCommon.hpp" #include "simplnx/Parameters/ArraySelectionParameter.hpp" #include "simplnx/Parameters/DataObjectNameParameter.hpp" @@ -127,8 +126,6 @@ Result<> ITKMaximumProjectionImageFilter::executeImpl(DataStructure& dataStructu const cxITKMaximumProjectionImageFilter::ITKMaximumProjectionImageFilterFunctor itkFunctor = {projectionDimension}; - auto& imageGeom = dataStructure.getDataRefAs(imageGeomPath); - return ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath, itkFunctor, shouldCancel); } diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMeanProjectionImageFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMeanProjectionImageFilter.cpp index c9fd14a17d..a3eeab5923 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMeanProjectionImageFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMeanProjectionImageFilter.cpp @@ -1,7 +1,6 @@ #include "ITKMeanProjectionImageFilter.hpp" #include "ITKImageProcessing/Common/ITKArrayHelper.hpp" -#include "ITKImageProcessing/Common/sitkCommon.hpp" #include "simplnx/Parameters/ArraySelectionParameter.hpp" #include "simplnx/Parameters/DataObjectNameParameter.hpp" @@ -127,8 +126,6 @@ Result<> ITKMeanProjectionImageFilter::executeImpl(DataStructure& dataStructure, const cxITKMeanProjectionImageFilter::ITKMeanProjectionImageFilterFunctor itkFunctor = {projectionDimension}; - auto& imageGeom = dataStructure.getDataRefAs(imageGeomPath); - return ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath, itkFunctor, shouldCancel); } diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp index 294b3f24ce..045b4149ea 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp @@ -1,7 +1,6 @@ #include "ITKMedianProjectionImageFilter.hpp" #include "ITKImageProcessing/Common/ITKArrayHelper.hpp" -#include "ITKImageProcessing/Common/sitkCommon.hpp" #include "simplnx/Parameters/ArraySelectionParameter.hpp" #include "simplnx/Parameters/DataObjectNameParameter.hpp" @@ -127,8 +126,6 @@ Result<> ITKMedianProjectionImageFilter::executeImpl(DataStructure& dataStructur const cxITKMedianProjectionImageFilter::ITKMedianProjectionImageFilterFunctor itkFunctor = {projectionDimension}; - auto& imageGeom = dataStructure.getDataRefAs(imageGeomPath); - return ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath, itkFunctor, shouldCancel); } diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.cpp index 4fb2c0d909..858dfeddac 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.cpp @@ -1,7 +1,6 @@ #include "ITKMinimumProjectionImageFilter.hpp" #include "ITKImageProcessing/Common/ITKArrayHelper.hpp" -#include "ITKImageProcessing/Common/sitkCommon.hpp" #include "simplnx/Parameters/ArraySelectionParameter.hpp" #include "simplnx/Parameters/DataObjectNameParameter.hpp" @@ -127,8 +126,6 @@ Result<> ITKMinimumProjectionImageFilter::executeImpl(DataStructure& dataStructu const cxITKMinimumProjectionImageFilter::ITKMinimumProjectionImageFilterFunctor itkFunctor = {projectionDimension}; - auto& imageGeom = dataStructure.getDataRefAs(imageGeomPath); - return ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath, itkFunctor, shouldCancel); } diff --git a/src/Plugins/ITKImageProcessing/test/CMakeLists.txt b/src/Plugins/ITKImageProcessing/test/CMakeLists.txt index c498452f8a..b762c526af 100644 --- a/src/Plugins/ITKImageProcessing/test/CMakeLists.txt +++ b/src/Plugins/ITKImageProcessing/test/CMakeLists.txt @@ -70,6 +70,10 @@ if(NOT ITKIMAGEPROCESSING_LEAN_AND_MEAN) ITKLog10ImageTest.cpp ITKLogImageTest.cpp ITKMaskImageTest.cpp + ITKMaximumProjectionImageTest.cpp + ITKMeanProjectionImageTest.cpp + ITKMedianProjectionImageTest.cpp + ITKMinimumProjectionImageTest.cpp ITKMinMaxCurvatureFlowImageTest.cpp ITKNormalizeImageTest.cpp ITKNotImageTest.cpp diff --git a/src/Plugins/ITKImageProcessing/test/ITKMaximumProjectionImageTest.cpp b/src/Plugins/ITKImageProcessing/test/ITKMaximumProjectionImageTest.cpp new file mode 100644 index 0000000000..4d27fa3555 --- /dev/null +++ b/src/Plugins/ITKImageProcessing/test/ITKMaximumProjectionImageTest.cpp @@ -0,0 +1,54 @@ +#include + +#include "ITKImageProcessing/Common/sitkCommon.hpp" +#include "ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.hpp" +#include "ITKImageProcessing/ITKImageProcessing_test_dirs.hpp" +#include "ITKTestBase.hpp" + +#include "simplnx/Parameters/DataObjectNameParameter.hpp" +#include "simplnx/Parameters/NumberParameter.hpp" +#include "simplnx/UnitTest/UnitTestCommon.hpp" + +#include +namespace fs = std::filesystem; + +using namespace nx::core; +using namespace nx::core::Constants; +using namespace nx::core::UnitTest; + +TEST_CASE("ITKImageProcessing::ITKMaximumProjectionImageFilter(z_projection)", "[ITKImageProcessing][ITKMaximumProjectionImage][z_projection]") +{ + DataStructure dataStructure; + const ITKMaximumProjectionImageFilter filter; + + const DataPath inputGeometryPath({ITKTestBase::k_ImageGeometryPath}); + const DataPath cellDataPath = inputGeometryPath.createChildPath(ITKTestBase::k_ImageCellDataName); + const DataPath inputDataPath = cellDataPath.createChildPath(ITKTestBase::k_InputDataName); + const DataObjectNameParameter::ValueType outputArrayName = ITKTestBase::k_OutputDataPath; + + { // Start Image Comparison Scope + const fs::path inputFilePath = fs::path(unit_test::k_SourceDir.view()) / unit_test::k_DataDir.view() / "JSONFilters" / "Input/RA-Float.nrrd"; + Result<> imageReadResult = ITKTestBase::ReadImage(dataStructure, inputFilePath, inputGeometryPath, ITKTestBase::k_ImageCellDataName, ITKTestBase::k_InputDataName); + SIMPLNX_RESULT_REQUIRE_VALID(imageReadResult) + } // End Image Comparison Scope + + Arguments args; + args.insertOrAssign(ITKMaximumProjectionImageFilter::k_InputImageGeomPath_Key, std::make_any(inputGeometryPath)); + args.insertOrAssign(ITKMaximumProjectionImageFilter::k_InputImageDataPath_Key, std::make_any(inputDataPath)); + args.insertOrAssign(ITKMaximumProjectionImageFilter::k_OutputImageArrayName_Key, std::make_any(outputArrayName)); + args.insertOrAssign(ITKMaximumProjectionImageFilter::k_ProjectionDimension_Key, std::make_any(2)); + + auto preflightResult = filter.preflight(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_VALID(preflightResult.outputActions) + + auto executeResult = filter.execute(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result) + + const fs::path baselineFilePath = fs::path(nx::core::unit_test::k_DataDir.view()) / "JSONFilters/Baseline/BasicFilters_MaximumProjectionImageFilter_z_projection.nrrd"; + const DataPath baselineGeometryPath({ITKTestBase::k_BaselineGeometryPath}); + const DataPath baseLineCellDataPath = baselineGeometryPath.createChildPath(ITKTestBase::k_ImageCellDataName); + const DataPath baselineDataPath = baseLineCellDataPath.createChildPath(ITKTestBase::k_BaselineDataPath); + const Result<> readBaselineResult = ITKTestBase::ReadImage(dataStructure, baselineFilePath, baselineGeometryPath, ITKTestBase::k_ImageCellDataName, ITKTestBase::k_BaselineDataPath); + Result<> compareResult = ITKTestBase::CompareImages(dataStructure, baselineGeometryPath, baselineDataPath, inputGeometryPath, cellDataPath.createChildPath(outputArrayName), 0.0001); + SIMPLNX_RESULT_REQUIRE_VALID(compareResult) +} diff --git a/src/Plugins/ITKImageProcessing/test/ITKMeanProjectionImageTest.cpp b/src/Plugins/ITKImageProcessing/test/ITKMeanProjectionImageTest.cpp index bacaaf739f..6d90962901 100644 --- a/src/Plugins/ITKImageProcessing/test/ITKMeanProjectionImageTest.cpp +++ b/src/Plugins/ITKImageProcessing/test/ITKMeanProjectionImageTest.cpp @@ -36,7 +36,7 @@ TEST_CASE("ITKImageProcessing::ITKMeanProjectionImageFilter(z_projection)", "[IT args.insertOrAssign(ITKMeanProjectionImageFilter::k_InputImageGeomPath_Key, std::make_any(inputGeometryPath)); args.insertOrAssign(ITKMeanProjectionImageFilter::k_InputImageDataPath_Key, std::make_any(inputDataPath)); args.insertOrAssign(ITKMeanProjectionImageFilter::k_OutputImageArrayName_Key, std::make_any(outputArrayName)); - args.insertOrAssign(ITKMeanProjectionImage::k_ProjectionDimension_Key, std::make_any(2)); + args.insertOrAssign(ITKMeanProjectionImageFilter::k_ProjectionDimension_Key, std::make_any(2)); auto preflightResult = filter.preflight(dataStructure, args); SIMPLNX_RESULT_REQUIRE_VALID(preflightResult.outputActions) diff --git a/src/Plugins/ITKImageProcessing/test/ITKMedianProjectionImageTest.cpp b/src/Plugins/ITKImageProcessing/test/ITKMedianProjectionImageTest.cpp new file mode 100644 index 0000000000..ef7e441aa0 --- /dev/null +++ b/src/Plugins/ITKImageProcessing/test/ITKMedianProjectionImageTest.cpp @@ -0,0 +1,54 @@ +#include + +#include "ITKImageProcessing/Common/sitkCommon.hpp" +#include "ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.hpp" +#include "ITKImageProcessing/ITKImageProcessing_test_dirs.hpp" +#include "ITKTestBase.hpp" + +#include "simplnx/Parameters/DataObjectNameParameter.hpp" +#include "simplnx/Parameters/NumberParameter.hpp" +#include "simplnx/UnitTest/UnitTestCommon.hpp" + +#include +namespace fs = std::filesystem; + +using namespace nx::core; +using namespace nx::core::Constants; +using namespace nx::core::UnitTest; + +TEST_CASE("ITKImageProcessing::ITKMedianProjectionImageFilter(z_projection)", "[ITKImageProcessing][ITKMedianProjectionImage][z_projection]") +{ + DataStructure dataStructure; + const ITKMedianProjectionImageFilter filter; + + const DataPath inputGeometryPath({ITKTestBase::k_ImageGeometryPath}); + const DataPath cellDataPath = inputGeometryPath.createChildPath(ITKTestBase::k_ImageCellDataName); + const DataPath inputDataPath = cellDataPath.createChildPath(ITKTestBase::k_InputDataName); + const DataObjectNameParameter::ValueType outputArrayName = ITKTestBase::k_OutputDataPath; + + { // Start Image Comparison Scope + const fs::path inputFilePath = fs::path(unit_test::k_SourceDir.view()) / unit_test::k_DataDir.view() / "JSONFilters" / "Input/RA-Float.nrrd"; + Result<> imageReadResult = ITKTestBase::ReadImage(dataStructure, inputFilePath, inputGeometryPath, ITKTestBase::k_ImageCellDataName, ITKTestBase::k_InputDataName); + SIMPLNX_RESULT_REQUIRE_VALID(imageReadResult) + } // End Image Comparison Scope + + Arguments args; + args.insertOrAssign(ITKMedianProjectionImageFilter::k_InputImageGeomPath_Key, std::make_any(inputGeometryPath)); + args.insertOrAssign(ITKMedianProjectionImageFilter::k_InputImageDataPath_Key, std::make_any(inputDataPath)); + args.insertOrAssign(ITKMedianProjectionImageFilter::k_OutputImageArrayName_Key, std::make_any(outputArrayName)); + args.insertOrAssign(ITKMedianProjectionImageFilter::k_ProjectionDimension_Key, std::make_any(2)); + + auto preflightResult = filter.preflight(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_VALID(preflightResult.outputActions) + + auto executeResult = filter.execute(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result) + + const fs::path baselineFilePath = fs::path(nx::core::unit_test::k_DataDir.view()) / "JSONFilters/Baseline/BasicFilters_MedianProjectionImageFilter_z_projection.nrrd"; + const DataPath baselineGeometryPath({ITKTestBase::k_BaselineGeometryPath}); + const DataPath baseLineCellDataPath = baselineGeometryPath.createChildPath(ITKTestBase::k_ImageCellDataName); + const DataPath baselineDataPath = baseLineCellDataPath.createChildPath(ITKTestBase::k_BaselineDataPath); + const Result<> readBaselineResult = ITKTestBase::ReadImage(dataStructure, baselineFilePath, baselineGeometryPath, ITKTestBase::k_ImageCellDataName, ITKTestBase::k_BaselineDataPath); + Result<> compareResult = ITKTestBase::CompareImages(dataStructure, baselineGeometryPath, baselineDataPath, inputGeometryPath, cellDataPath.createChildPath(outputArrayName), 0.0001); + SIMPLNX_RESULT_REQUIRE_VALID(compareResult) +} diff --git a/src/Plugins/ITKImageProcessing/test/ITKMinimumProjectionImageTest.cpp b/src/Plugins/ITKImageProcessing/test/ITKMinimumProjectionImageTest.cpp new file mode 100644 index 0000000000..a3833f53dd --- /dev/null +++ b/src/Plugins/ITKImageProcessing/test/ITKMinimumProjectionImageTest.cpp @@ -0,0 +1,54 @@ +#include + +#include "ITKImageProcessing/Common/sitkCommon.hpp" +#include "ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.hpp" +#include "ITKImageProcessing/ITKImageProcessing_test_dirs.hpp" +#include "ITKTestBase.hpp" + +#include "simplnx/Parameters/DataObjectNameParameter.hpp" +#include "simplnx/Parameters/NumberParameter.hpp" +#include "simplnx/UnitTest/UnitTestCommon.hpp" + +#include +namespace fs = std::filesystem; + +using namespace nx::core; +using namespace nx::core::Constants; +using namespace nx::core::UnitTest; + +TEST_CASE("ITKImageProcessing::ITKMinimumProjectionImageFilter(z_projection)", "[ITKImageProcessing][ITKMinimumProjectionImage][z_projection]") +{ + DataStructure dataStructure; + const ITKMinimumProjectionImageFilter filter; + + const DataPath inputGeometryPath({ITKTestBase::k_ImageGeometryPath}); + const DataPath cellDataPath = inputGeometryPath.createChildPath(ITKTestBase::k_ImageCellDataName); + const DataPath inputDataPath = cellDataPath.createChildPath(ITKTestBase::k_InputDataName); + const DataObjectNameParameter::ValueType outputArrayName = ITKTestBase::k_OutputDataPath; + + { // Start Image Comparison Scope + const fs::path inputFilePath = fs::path(unit_test::k_SourceDir.view()) / unit_test::k_DataDir.view() / "JSONFilters" / "Input/RA-Float.nrrd"; + Result<> imageReadResult = ITKTestBase::ReadImage(dataStructure, inputFilePath, inputGeometryPath, ITKTestBase::k_ImageCellDataName, ITKTestBase::k_InputDataName); + SIMPLNX_RESULT_REQUIRE_VALID(imageReadResult) + } // End Image Comparison Scope + + Arguments args; + args.insertOrAssign(ITKMinimumProjectionImageFilter::k_InputImageGeomPath_Key, std::make_any(inputGeometryPath)); + args.insertOrAssign(ITKMinimumProjectionImageFilter::k_InputImageDataPath_Key, std::make_any(inputDataPath)); + args.insertOrAssign(ITKMinimumProjectionImageFilter::k_OutputImageArrayName_Key, std::make_any(outputArrayName)); + args.insertOrAssign(ITKMinimumProjectionImageFilter::k_ProjectionDimension_Key, std::make_any(2)); + + auto preflightResult = filter.preflight(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_VALID(preflightResult.outputActions) + + auto executeResult = filter.execute(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result) + + const fs::path baselineFilePath = fs::path(nx::core::unit_test::k_DataDir.view()) / "JSONFilters/Baseline/BasicFilters_MinimumProjectionImageFilter_z_projection.nrrd"; + const DataPath baselineGeometryPath({ITKTestBase::k_BaselineGeometryPath}); + const DataPath baseLineCellDataPath = baselineGeometryPath.createChildPath(ITKTestBase::k_ImageCellDataName); + const DataPath baselineDataPath = baseLineCellDataPath.createChildPath(ITKTestBase::k_BaselineDataPath); + const Result<> readBaselineResult = ITKTestBase::ReadImage(dataStructure, baselineFilePath, baselineGeometryPath, ITKTestBase::k_ImageCellDataName, ITKTestBase::k_BaselineDataPath); + Result<> compareResult = ITKTestBase::CompareImages(dataStructure, baselineGeometryPath, baselineDataPath, inputGeometryPath, cellDataPath.createChildPath(outputArrayName), 0.0001); + SIMPLNX_RESULT_REQUIRE_VALID(compareResult) +} From 5387abf1c3488a130688d610a9aca2187efe5ebc Mon Sep 17 00:00:00 2001 From: nyoungbq Date: Tue, 3 Dec 2024 11:55:05 -0500 Subject: [PATCH 04/11] Make Filters conform to the Binary Projection precedent --- .../ITKBinaryProjectionImageFilter.cpp | 16 +++++----- .../ITKMaximumProjectionImageFilter.cpp | 29 ++++++++++++++++--- .../Filters/ITKMeanProjectionImageFilter.cpp | 25 ++++++++++++++-- .../ITKMedianProjectionImageFilter.cpp | 29 ++++++++++++++++--- .../ITKMinimumProjectionImageFilter.cpp | 29 ++++++++++++++++--- 5 files changed, 107 insertions(+), 21 deletions(-) diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKBinaryProjectionImageFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKBinaryProjectionImageFilter.cpp index 7f0507da9d..cb5e6adce5 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKBinaryProjectionImageFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKBinaryProjectionImageFilter.cpp @@ -142,13 +142,15 @@ Result<> ITKBinaryProjectionImageFilter::executeImpl(DataStructure& dataStructur const cxITKBinaryProjectionImageFilter::ITKBinaryProjectionImageFunctor itkFunctor = {projectionDimension, foregroundValue, backgroundValue}; - auto& imageGeom = dataStructure.getDataRefAs(imageGeomPath); - auto result = ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath, itkFunctor, shouldCancel); + if(result.invalid()) + { + return result; + } + + auto& imageGeom = dataStructure.getDataRefAs(imageGeomPath); - IArray& iArrayRef = dataStructure.getDataRefAs(outputArrayPath); - auto iArrayTupleShape = iArrayRef.getTupleShape(); - std::cout << fmt::format("{}", fmt::join(iArrayRef.getTupleShape(), ",")) << std::endl; + auto iArrayTupleShape = dataStructure.getDataAs(outputArrayPath)->getTupleShape(); // Update the Image Geometry with the new dimensions imageGeom.setDimensions({iArrayTupleShape[2], iArrayTupleShape[1], iArrayTupleShape[0]}); @@ -158,10 +160,10 @@ Result<> ITKBinaryProjectionImageFilter::executeImpl(DataStructure& dataStructur auto amPathVector = outputArrayPath.getPathVector(); amPathVector.pop_back(); DataPath amPath(amPathVector); - AttributeMatrix& attributeMatrix = dataStructure.getDataRefAs(amPath); + auto& attributeMatrix = dataStructure.getDataRefAs(amPath); attributeMatrix.resizeTuples(iArrayTupleShape); - return result; + return {}; } namespace diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.cpp index df9d13dc68..6da4938708 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.cpp @@ -99,7 +99,7 @@ IFilter::UniquePointer ITKMaximumProjectionImageFilter::clone() const //------------------------------------------------------------------------------ IFilter::PreflightResult ITKMaximumProjectionImageFilter::preflightImpl(const DataStructure& dataStructure, const Arguments& filterArgs, const MessageHandler& messageHandler, - const std::atomic_bool& shouldCancel) const + const std::atomic_bool& shouldCancel) const { auto imageGeomPath = filterArgs.value(k_InputImageGeomPath_Key); auto selectedInputArray = filterArgs.value(k_InputImageDataPath_Key); @@ -115,7 +115,7 @@ IFilter::PreflightResult ITKMaximumProjectionImageFilter::preflightImpl(const Da //------------------------------------------------------------------------------ Result<> ITKMaximumProjectionImageFilter::executeImpl(DataStructure& dataStructure, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, - const std::atomic_bool& shouldCancel) const + const std::atomic_bool& shouldCancel) const { auto imageGeomPath = filterArgs.value(k_InputImageGeomPath_Key); auto selectedInputArray = filterArgs.value(k_InputImageDataPath_Key); @@ -126,7 +126,28 @@ Result<> ITKMaximumProjectionImageFilter::executeImpl(DataStructure& dataStructu const cxITKMaximumProjectionImageFilter::ITKMaximumProjectionImageFilterFunctor itkFunctor = {projectionDimension}; - return ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath, itkFunctor, - shouldCancel); + auto result = ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, + outputArrayPath, itkFunctor, shouldCancel); + if(result.invalid()) + { + return result; + } + + auto& imageGeom = dataStructure.getDataRefAs(imageGeomPath); + + auto iArrayTupleShape = dataStructure.getDataAs(outputArrayPath)->getTupleShape(); + + // Update the Image Geometry with the new dimensions + imageGeom.setDimensions({iArrayTupleShape[2], iArrayTupleShape[1], iArrayTupleShape[0]}); + + // Update the AttributeMatrix with the new tuple shape. THIS WILL ALSO CHANGE ANY OTHER DATA ARRAY THAT IS ALSO + // STORED IN THAT ATTRIBUTE MATRIX + auto amPathVector = outputArrayPath.getPathVector(); + amPathVector.pop_back(); + DataPath amPath(amPathVector); + auto& attributeMatrix = dataStructure.getDataRefAs(amPath); + attributeMatrix.resizeTuples(iArrayTupleShape); + + return {}; } } // namespace nx::core diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMeanProjectionImageFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMeanProjectionImageFilter.cpp index a3eeab5923..eb72a45594 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMeanProjectionImageFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMeanProjectionImageFilter.cpp @@ -126,7 +126,28 @@ Result<> ITKMeanProjectionImageFilter::executeImpl(DataStructure& dataStructure, const cxITKMeanProjectionImageFilter::ITKMeanProjectionImageFilterFunctor itkFunctor = {projectionDimension}; - return ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath, itkFunctor, - shouldCancel); + auto result = ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath, + itkFunctor, shouldCancel); + if(result.invalid()) + { + return result; + } + + auto& imageGeom = dataStructure.getDataRefAs(imageGeomPath); + + auto iArrayTupleShape = dataStructure.getDataAs(outputArrayPath)->getTupleShape(); + + // Update the Image Geometry with the new dimensions + imageGeom.setDimensions({iArrayTupleShape[2], iArrayTupleShape[1], iArrayTupleShape[0]}); + + // Update the AttributeMatrix with the new tuple shape. THIS WILL ALSO CHANGE ANY OTHER DATA ARRAY THAT IS ALSO + // STORED IN THAT ATTRIBUTE MATRIX + auto amPathVector = outputArrayPath.getPathVector(); + amPathVector.pop_back(); + DataPath amPath(amPathVector); + auto& attributeMatrix = dataStructure.getDataRefAs(amPath); + attributeMatrix.resizeTuples(iArrayTupleShape); + + return {}; } } // namespace nx::core diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp index 045b4149ea..1b62b2d1a6 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp @@ -99,7 +99,7 @@ IFilter::UniquePointer ITKMedianProjectionImageFilter::clone() const //------------------------------------------------------------------------------ IFilter::PreflightResult ITKMedianProjectionImageFilter::preflightImpl(const DataStructure& dataStructure, const Arguments& filterArgs, const MessageHandler& messageHandler, - const std::atomic_bool& shouldCancel) const + const std::atomic_bool& shouldCancel) const { auto imageGeomPath = filterArgs.value(k_InputImageGeomPath_Key); auto selectedInputArray = filterArgs.value(k_InputImageDataPath_Key); @@ -115,7 +115,7 @@ IFilter::PreflightResult ITKMedianProjectionImageFilter::preflightImpl(const Dat //------------------------------------------------------------------------------ Result<> ITKMedianProjectionImageFilter::executeImpl(DataStructure& dataStructure, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, - const std::atomic_bool& shouldCancel) const + const std::atomic_bool& shouldCancel) const { auto imageGeomPath = filterArgs.value(k_InputImageGeomPath_Key); auto selectedInputArray = filterArgs.value(k_InputImageDataPath_Key); @@ -126,7 +126,28 @@ Result<> ITKMedianProjectionImageFilter::executeImpl(DataStructure& dataStructur const cxITKMedianProjectionImageFilter::ITKMedianProjectionImageFilterFunctor itkFunctor = {projectionDimension}; - return ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath, itkFunctor, - shouldCancel); + auto result = ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath, + itkFunctor, shouldCancel); + if(result.invalid()) + { + return result; + } + + auto& imageGeom = dataStructure.getDataRefAs(imageGeomPath); + + auto iArrayTupleShape = dataStructure.getDataAs(outputArrayPath)->getTupleShape(); + + // Update the Image Geometry with the new dimensions + imageGeom.setDimensions({iArrayTupleShape[2], iArrayTupleShape[1], iArrayTupleShape[0]}); + + // Update the AttributeMatrix with the new tuple shape. THIS WILL ALSO CHANGE ANY OTHER DATA ARRAY THAT IS ALSO + // STORED IN THAT ATTRIBUTE MATRIX + auto amPathVector = outputArrayPath.getPathVector(); + amPathVector.pop_back(); + DataPath amPath(amPathVector); + auto& attributeMatrix = dataStructure.getDataRefAs(amPath); + attributeMatrix.resizeTuples(iArrayTupleShape); + + return {}; } } // namespace nx::core diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.cpp index 858dfeddac..8e2572c426 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.cpp @@ -99,7 +99,7 @@ IFilter::UniquePointer ITKMinimumProjectionImageFilter::clone() const //------------------------------------------------------------------------------ IFilter::PreflightResult ITKMinimumProjectionImageFilter::preflightImpl(const DataStructure& dataStructure, const Arguments& filterArgs, const MessageHandler& messageHandler, - const std::atomic_bool& shouldCancel) const + const std::atomic_bool& shouldCancel) const { auto imageGeomPath = filterArgs.value(k_InputImageGeomPath_Key); auto selectedInputArray = filterArgs.value(k_InputImageDataPath_Key); @@ -115,7 +115,7 @@ IFilter::PreflightResult ITKMinimumProjectionImageFilter::preflightImpl(const Da //------------------------------------------------------------------------------ Result<> ITKMinimumProjectionImageFilter::executeImpl(DataStructure& dataStructure, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, - const std::atomic_bool& shouldCancel) const + const std::atomic_bool& shouldCancel) const { auto imageGeomPath = filterArgs.value(k_InputImageGeomPath_Key); auto selectedInputArray = filterArgs.value(k_InputImageDataPath_Key); @@ -126,7 +126,28 @@ Result<> ITKMinimumProjectionImageFilter::executeImpl(DataStructure& dataStructu const cxITKMinimumProjectionImageFilter::ITKMinimumProjectionImageFilterFunctor itkFunctor = {projectionDimension}; - return ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath, itkFunctor, - shouldCancel); + auto result = ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, + outputArrayPath, itkFunctor, shouldCancel); + if(result.invalid()) + { + return result; + } + + auto& imageGeom = dataStructure.getDataRefAs(imageGeomPath); + + auto iArrayTupleShape = dataStructure.getDataAs(outputArrayPath)->getTupleShape(); + + // Update the Image Geometry with the new dimensions + imageGeom.setDimensions({iArrayTupleShape[2], iArrayTupleShape[1], iArrayTupleShape[0]}); + + // Update the AttributeMatrix with the new tuple shape. THIS WILL ALSO CHANGE ANY OTHER DATA ARRAY THAT IS ALSO + // STORED IN THAT ATTRIBUTE MATRIX + auto amPathVector = outputArrayPath.getPathVector(); + amPathVector.pop_back(); + DataPath amPath(amPathVector); + auto& attributeMatrix = dataStructure.getDataRefAs(amPath); + attributeMatrix.resizeTuples(iArrayTupleShape); + + return {}; } } // namespace nx::core From 272f37fff78d39effd2c3318aea2250ff6feb1f5 Mon Sep 17 00:00:00 2001 From: nyoungbq Date: Thu, 5 Dec 2024 16:44:18 -0500 Subject: [PATCH 05/11] Added functionality to preserve integrity of input geometry (off by default) Done by creating a new resized geom with only projected data in it --- .../ITKBinaryProjectionImageFilter.cpp | 58 ++++++++++++++----- .../ITKBinaryProjectionImageFilter.hpp | 4 +- .../ITKMaximumProjectionImageFilter.cpp | 53 +++++++++++++---- .../ITKMaximumProjectionImageFilter.hpp | 4 +- .../Filters/ITKMeanProjectionImageFilter.cpp | 53 +++++++++++++---- .../Filters/ITKMeanProjectionImageFilter.hpp | 4 +- .../ITKMedianProjectionImageFilter.cpp | 53 +++++++++++++---- .../ITKMedianProjectionImageFilter.hpp | 4 +- .../ITKMinimumProjectionImageFilter.cpp | 53 +++++++++++++---- .../ITKMinimumProjectionImageFilter.hpp | 4 +- 10 files changed, 232 insertions(+), 58 deletions(-) diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKBinaryProjectionImageFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKBinaryProjectionImageFilter.cpp index cb5e6adce5..ed12355052 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKBinaryProjectionImageFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKBinaryProjectionImageFilter.cpp @@ -3,7 +3,9 @@ #include "ITKImageProcessing/Common/ITKArrayHelper.hpp" #include "ITKImageProcessing/Common/sitkCommon.hpp" +#include "simplnx/Filter/Actions/CreateImageGeometryAction.hpp" #include "simplnx/Parameters/ArraySelectionParameter.hpp" +#include "simplnx/Parameters/BoolParameter.hpp" #include "simplnx/Parameters/DataGroupSelectionParameter.hpp" #include "simplnx/Parameters/DataObjectNameParameter.hpp" #include "simplnx/Parameters/GeometrySelectionParameter.hpp" @@ -77,6 +79,7 @@ Parameters ITKBinaryProjectionImageFilter::parameters() const Parameters params; params.insertSeparator(Parameters::Separator{"Input Parameter(s)"}); params.insert(std::make_unique(k_ProjectionDimension_Key, "Projection Dimension", "The dimension index to project. 0=Slowest moving dimension.", 0u)); + params.insertLinkableParameter(std::make_unique(k_RemoveOriginalGeometry_Key, "Perform In-Place", "Performs the projection in-place for the given Image Geometry", true)); params.insert(std::make_unique( k_ForegroundValue_Key, "Foreground Value", "Set the value in the image to consider as 'foreground'. Defaults to maximum value of PixelType. Subclasses may alias this to DilateValue or ErodeValue.", 1.0)); @@ -91,9 +94,12 @@ Parameters ITKBinaryProjectionImageFilter::parameters() const params.insert(std::make_unique(k_InputImageDataPath_Key, "Input Cell Data", "The image data that will be processed by this filter.", DataPath{}, nx::core::ITK::GetScalarPixelAllowedTypes())); - params.insertSeparator(Parameters::Separator{"Output Cell Data"}); - params.insert(std::make_unique(k_OutputImageArrayName_Key, "Output Cell Data", - "The result of the processing will be stored in this Data Array inside the same group as the input data.", "Output Image Data")); + params.insertSeparator(Parameters::Separator{"Output Data"}); + params.insert(std::make_unique(k_OutputImageGeomName_Key, "Created Image Geometry", "The name of the projected geometry", "Projected Image")); + params.insert( + std::make_unique(k_OutputImageArrayName_Key, "Output Image Data Array", "The result of the processing will be stored in this Data Array.", "Output Image Data")); + + params.linkParameters(k_RemoveOriginalGeometry_Key, k_OutputImageGeomName_Key, false); return params; } @@ -101,7 +107,7 @@ Parameters ITKBinaryProjectionImageFilter::parameters() const //------------------------------------------------------------------------------ IFilter::VersionType ITKBinaryProjectionImageFilter::parametersVersion() const { - return 1; + return 2; } //------------------------------------------------------------------------------ @@ -120,9 +126,30 @@ IFilter::PreflightResult ITKBinaryProjectionImageFilter::preflightImpl(const Dat auto projectionDimension = filterArgs.value(k_ProjectionDimension_Key); auto foregroundValue = filterArgs.value(k_ForegroundValue_Key); auto backgroundValue = filterArgs.value(k_BackgroundValue_Key); - const DataPath outputArrayPath = selectedInputArray.replaceName(outputArrayName); + auto preformInPlace = filterArgs.value(k_RemoveOriginalGeometry_Key); + auto outputGeomName = filterArgs.value(k_OutputImageGeomName_Key); + DataPath outputArrayPath = selectedInputArray.replaceName(outputArrayName); + + Result resultOutputActions; + // The input geometry must be preserved, so we will just copy the needed array into newly created output geometry + if(!preformInPlace) + { + DataPath outputGeomPath({outputGeomName}); + + const auto& originalGeometry = dataStructure.getDataRefAs(imageGeomPath); + + // Make copy of input geometry + resultOutputActions.value().appendAction(std::make_unique( + outputGeomPath, originalGeometry.getDimensions().toContainer(), originalGeometry.getOrigin().toContainer(), + originalGeometry.getSpacing().toContainer(), originalGeometry.getCellDataPath().getTargetName())); + + outputArrayPath = outputGeomPath.createChildPath(originalGeometry.getCellDataPath().getTargetName()).createChildPath(outputArrayName); + } - Result resultOutputActions = ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); + Result helperOutputActions = ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); + + // Consolidate actions + resultOutputActions.value().actions.insert(resultOutputActions.value().actions.end(), helperOutputActions.value().actions.begin(), helperOutputActions.value().actions.end()); return {std::move(resultOutputActions)}; } @@ -134,7 +161,17 @@ Result<> ITKBinaryProjectionImageFilter::executeImpl(DataStructure& dataStructur auto imageGeomPath = filterArgs.value(k_InputImageGeomPath_Key); auto selectedInputArray = filterArgs.value(k_InputImageDataPath_Key); auto outputArrayName = filterArgs.value(k_OutputImageArrayName_Key); - const DataPath outputArrayPath = selectedInputArray.replaceName(outputArrayName); + DataPath outputArrayPath = selectedInputArray.replaceName(outputArrayName); + + auto preformInPlace = filterArgs.value(k_RemoveOriginalGeometry_Key); + + if(!preformInPlace) + { + const auto& originalGeometry = dataStructure.getDataRefAs(imageGeomPath); + + imageGeomPath = DataPath({filterArgs.value(k_OutputImageGeomName_Key)}); + outputArrayPath = imageGeomPath.createChildPath(originalGeometry.getCellDataPath().getTargetName()).createChildPath(outputArrayName); + } auto projectionDimension = filterArgs.value(k_ProjectionDimension_Key); auto foregroundValue = filterArgs.value(k_ForegroundValue_Key); @@ -149,7 +186,6 @@ Result<> ITKBinaryProjectionImageFilter::executeImpl(DataStructure& dataStructur } auto& imageGeom = dataStructure.getDataRefAs(imageGeomPath); - auto iArrayTupleShape = dataStructure.getDataAs(outputArrayPath)->getTupleShape(); // Update the Image Geometry with the new dimensions @@ -157,11 +193,7 @@ Result<> ITKBinaryProjectionImageFilter::executeImpl(DataStructure& dataStructur // Update the AttributeMatrix with the new tuple shape. THIS WILL ALSO CHANGE ANY OTHER DATA ARRAY THAT IS ALSO // STORED IN THAT ATTRIBUTE MATRIX - auto amPathVector = outputArrayPath.getPathVector(); - amPathVector.pop_back(); - DataPath amPath(amPathVector); - auto& attributeMatrix = dataStructure.getDataRefAs(amPath); - attributeMatrix.resizeTuples(iArrayTupleShape); + dataStructure.getDataAs(outputArrayPath.getParent())->resizeTuples(iArrayTupleShape); return {}; } diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKBinaryProjectionImageFilter.hpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKBinaryProjectionImageFilter.hpp index a489dd4459..322036e202 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKBinaryProjectionImageFilter.hpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKBinaryProjectionImageFilter.hpp @@ -55,10 +55,12 @@ class ITKIMAGEPROCESSING_EXPORT ITKBinaryProjectionImageFilter : public IFilter ITKBinaryProjectionImageFilter& operator=(ITKBinaryProjectionImageFilter&&) noexcept = delete; // Parameter Keys + static inline constexpr StringLiteral k_ProjectionDimension_Key = "projection_dimension"; + static inline constexpr StringLiteral k_RemoveOriginalGeometry_Key = "remove_original_geometry"; static inline constexpr StringLiteral k_InputImageGeomPath_Key = "input_image_geometry_path"; static inline constexpr StringLiteral k_InputImageDataPath_Key = "input_image_data_path"; + static inline constexpr StringLiteral k_OutputImageGeomName_Key = "output_image_geometry_name"; static inline constexpr StringLiteral k_OutputImageArrayName_Key = "output_array_name"; - static inline constexpr StringLiteral k_ProjectionDimension_Key = "projection_dimension"; static inline constexpr StringLiteral k_ForegroundValue_Key = "foreground_value"; static inline constexpr StringLiteral k_BackgroundValue_Key = "background_value"; diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.cpp index 6da4938708..5158d9e30b 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.cpp @@ -2,10 +2,13 @@ #include "ITKImageProcessing/Common/ITKArrayHelper.hpp" +#include "simplnx/Filter/Actions/CreateImageGeometryAction.hpp" #include "simplnx/Parameters/ArraySelectionParameter.hpp" +#include "simplnx/Parameters/BoolParameter.hpp" #include "simplnx/Parameters/DataObjectNameParameter.hpp" #include "simplnx/Parameters/GeometrySelectionParameter.hpp" #include "simplnx/Parameters/NumberParameter.hpp" +#include "simplnx/Parameters/StringParameter.hpp" #include @@ -71,6 +74,7 @@ Parameters ITKMaximumProjectionImageFilter::parameters() const Parameters params; params.insertSeparator(Parameters::Separator{"Input Parameter(s)"}); params.insert(std::make_unique(k_ProjectionDimension_Key, "Projection Dimension", "The dimension index to project. 0=Slowest moving dimension.", 0u)); + params.insertLinkableParameter(std::make_unique(k_RemoveOriginalGeometry_Key, "Perform In-Place", "Performs the projection in-place for the given Image Geometry", true)); params.insertSeparator(Parameters::Separator{"Input Cell Data"}); params.insert(std::make_unique(k_InputImageGeomPath_Key, "Image Geometry", "Select the Image Geometry Group from the DataStructure.", DataPath({"Image Geometry"}), @@ -78,10 +82,13 @@ Parameters ITKMaximumProjectionImageFilter::parameters() const params.insert(std::make_unique(k_InputImageDataPath_Key, "Input Cell Data", "The image data that will be processed by this filter.", DataPath{}, nx::core::ITK::GetScalarPixelAllowedTypes())); - params.insertSeparator(Parameters::Separator{"Output Cell Data"}); + params.insertSeparator(Parameters::Separator{"Output Data"}); + params.insert(std::make_unique(k_OutputImageGeomName_Key, "Created Image Geometry", "The name of the projected geometry", "Projected Image")); params.insert( std::make_unique(k_OutputImageArrayName_Key, "Output Image Data Array", "The result of the processing will be stored in this Data Array.", "Output Image Data")); + params.linkParameters(k_RemoveOriginalGeometry_Key, k_OutputImageGeomName_Key, false); + return params; } @@ -105,11 +112,32 @@ IFilter::PreflightResult ITKMaximumProjectionImageFilter::preflightImpl(const Da auto selectedInputArray = filterArgs.value(k_InputImageDataPath_Key); auto outputArrayName = filterArgs.value(k_OutputImageArrayName_Key); auto projectionDimension = filterArgs.value(k_ProjectionDimension_Key); - const DataPath outputArrayPath = selectedInputArray.replaceName(outputArrayName); + auto preformInPlace = filterArgs.value(k_RemoveOriginalGeometry_Key); + auto outputGeomName = filterArgs.value(k_OutputImageGeomName_Key); + DataPath outputArrayPath = selectedInputArray.replaceName(outputArrayName); + + Result resultOutputActions; + // The input geometry must be preserved, so we will just copy the needed array into newly created output geometry + if(!preformInPlace) + { + DataPath outputGeomPath({outputGeomName}); + + const auto& originalGeometry = dataStructure.getDataRefAs(imageGeomPath); + + // Make copy of input geometry + resultOutputActions.value().appendAction(std::make_unique( + outputGeomPath, originalGeometry.getDimensions().toContainer(), originalGeometry.getOrigin().toContainer(), + originalGeometry.getSpacing().toContainer(), originalGeometry.getCellDataPath().getTargetName())); + + outputArrayPath = outputGeomPath.createChildPath(originalGeometry.getCellDataPath().getTargetName()).createChildPath(outputArrayName); + } - Result resultOutputActions = + Result helperOutputActions = ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); + // Consolidate actions + resultOutputActions.value().actions.insert(resultOutputActions.value().actions.end(), helperOutputActions.value().actions.begin(), helperOutputActions.value().actions.end()); + return {std::move(resultOutputActions)}; } @@ -120,7 +148,17 @@ Result<> ITKMaximumProjectionImageFilter::executeImpl(DataStructure& dataStructu auto imageGeomPath = filterArgs.value(k_InputImageGeomPath_Key); auto selectedInputArray = filterArgs.value(k_InputImageDataPath_Key); auto outputArrayName = filterArgs.value(k_OutputImageArrayName_Key); - const DataPath outputArrayPath = selectedInputArray.replaceName(outputArrayName); + DataPath outputArrayPath = selectedInputArray.replaceName(outputArrayName); + + auto preformInPlace = filterArgs.value(k_RemoveOriginalGeometry_Key); + + if(!preformInPlace) + { + const auto& originalGeometry = dataStructure.getDataRefAs(imageGeomPath); + + imageGeomPath = DataPath({filterArgs.value(k_OutputImageGeomName_Key)}); + outputArrayPath = imageGeomPath.createChildPath(originalGeometry.getCellDataPath().getTargetName()).createChildPath(outputArrayName); + } auto projectionDimension = filterArgs.value(k_ProjectionDimension_Key); @@ -134,7 +172,6 @@ Result<> ITKMaximumProjectionImageFilter::executeImpl(DataStructure& dataStructu } auto& imageGeom = dataStructure.getDataRefAs(imageGeomPath); - auto iArrayTupleShape = dataStructure.getDataAs(outputArrayPath)->getTupleShape(); // Update the Image Geometry with the new dimensions @@ -142,11 +179,7 @@ Result<> ITKMaximumProjectionImageFilter::executeImpl(DataStructure& dataStructu // Update the AttributeMatrix with the new tuple shape. THIS WILL ALSO CHANGE ANY OTHER DATA ARRAY THAT IS ALSO // STORED IN THAT ATTRIBUTE MATRIX - auto amPathVector = outputArrayPath.getPathVector(); - amPathVector.pop_back(); - DataPath amPath(amPathVector); - auto& attributeMatrix = dataStructure.getDataRefAs(amPath); - attributeMatrix.resizeTuples(iArrayTupleShape); + dataStructure.getDataAs(outputArrayPath.getParent())->resizeTuples(iArrayTupleShape); return {}; } diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.hpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.hpp index fba489af3d..162cb5e309 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.hpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.hpp @@ -52,10 +52,12 @@ class ITKIMAGEPROCESSING_EXPORT ITKMaximumProjectionImageFilter : public IFilter ITKMaximumProjectionImageFilter& operator=(ITKMaximumProjectionImageFilter&&) noexcept = delete; // Parameter Keys + static inline constexpr StringLiteral k_ProjectionDimension_Key = "projection_dimension"; + static inline constexpr StringLiteral k_RemoveOriginalGeometry_Key = "remove_original_geometry"; static inline constexpr StringLiteral k_InputImageGeomPath_Key = "input_image_geometry_path"; static inline constexpr StringLiteral k_InputImageDataPath_Key = "input_image_data_path"; + static inline constexpr StringLiteral k_OutputImageGeomName_Key = "output_image_geometry_name"; static inline constexpr StringLiteral k_OutputImageArrayName_Key = "output_array_name"; - static inline constexpr StringLiteral k_ProjectionDimension_Key = "projection_dimension"; /** * @brief Returns the name of the filter. diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMeanProjectionImageFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMeanProjectionImageFilter.cpp index eb72a45594..bcdb1e40fe 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMeanProjectionImageFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMeanProjectionImageFilter.cpp @@ -2,10 +2,13 @@ #include "ITKImageProcessing/Common/ITKArrayHelper.hpp" +#include "simplnx/Filter/Actions/CreateImageGeometryAction.hpp" #include "simplnx/Parameters/ArraySelectionParameter.hpp" +#include "simplnx/Parameters/BoolParameter.hpp" #include "simplnx/Parameters/DataObjectNameParameter.hpp" #include "simplnx/Parameters/GeometrySelectionParameter.hpp" #include "simplnx/Parameters/NumberParameter.hpp" +#include "simplnx/Parameters/StringParameter.hpp" #include @@ -71,6 +74,7 @@ Parameters ITKMeanProjectionImageFilter::parameters() const Parameters params; params.insertSeparator(Parameters::Separator{"Input Parameter(s)"}); params.insert(std::make_unique(k_ProjectionDimension_Key, "Projection Dimension", "The dimension index to project. 0=Slowest moving dimension.", 0u)); + params.insertLinkableParameter(std::make_unique(k_RemoveOriginalGeometry_Key, "Perform In-Place", "Performs the projection in-place for the given Image Geometry", true)); params.insertSeparator(Parameters::Separator{"Input Cell Data"}); params.insert(std::make_unique(k_InputImageGeomPath_Key, "Image Geometry", "Select the Image Geometry Group from the DataStructure.", DataPath({"Image Geometry"}), @@ -78,10 +82,13 @@ Parameters ITKMeanProjectionImageFilter::parameters() const params.insert(std::make_unique(k_InputImageDataPath_Key, "Input Cell Data", "The image data that will be processed by this filter.", DataPath{}, nx::core::ITK::GetScalarPixelAllowedTypes())); - params.insertSeparator(Parameters::Separator{"Output Cell Data"}); + params.insertSeparator(Parameters::Separator{"Output Data"}); + params.insert(std::make_unique(k_OutputImageGeomName_Key, "Created Image Geometry", "The name of the projected geometry", "Projected Image")); params.insert( std::make_unique(k_OutputImageArrayName_Key, "Output Image Data Array", "The result of the processing will be stored in this Data Array.", "Output Image Data")); + params.linkParameters(k_RemoveOriginalGeometry_Key, k_OutputImageGeomName_Key, false); + return params; } @@ -105,11 +112,32 @@ IFilter::PreflightResult ITKMeanProjectionImageFilter::preflightImpl(const DataS auto selectedInputArray = filterArgs.value(k_InputImageDataPath_Key); auto outputArrayName = filterArgs.value(k_OutputImageArrayName_Key); auto projectionDimension = filterArgs.value(k_ProjectionDimension_Key); - const DataPath outputArrayPath = selectedInputArray.replaceName(outputArrayName); + auto preformInPlace = filterArgs.value(k_RemoveOriginalGeometry_Key); + auto outputGeomName = filterArgs.value(k_OutputImageGeomName_Key); + DataPath outputArrayPath = selectedInputArray.replaceName(outputArrayName); + + Result resultOutputActions; + // The input geometry must be preserved, so we will just copy the needed array into newly created output geometry + if(!preformInPlace) + { + DataPath outputGeomPath({outputGeomName}); + + const auto& originalGeometry = dataStructure.getDataRefAs(imageGeomPath); + + // Make copy of input geometry + resultOutputActions.value().appendAction(std::make_unique( + outputGeomPath, originalGeometry.getDimensions().toContainer(), originalGeometry.getOrigin().toContainer(), + originalGeometry.getSpacing().toContainer(), originalGeometry.getCellDataPath().getTargetName())); + + outputArrayPath = outputGeomPath.createChildPath(originalGeometry.getCellDataPath().getTargetName()).createChildPath(outputArrayName); + } - Result resultOutputActions = + Result helperOutputActions = ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); + // Consolidate actions + resultOutputActions.value().actions.insert(resultOutputActions.value().actions.end(), helperOutputActions.value().actions.begin(), helperOutputActions.value().actions.end()); + return {std::move(resultOutputActions)}; } @@ -120,7 +148,17 @@ Result<> ITKMeanProjectionImageFilter::executeImpl(DataStructure& dataStructure, auto imageGeomPath = filterArgs.value(k_InputImageGeomPath_Key); auto selectedInputArray = filterArgs.value(k_InputImageDataPath_Key); auto outputArrayName = filterArgs.value(k_OutputImageArrayName_Key); - const DataPath outputArrayPath = selectedInputArray.replaceName(outputArrayName); + DataPath outputArrayPath = selectedInputArray.replaceName(outputArrayName); + + auto preformInPlace = filterArgs.value(k_RemoveOriginalGeometry_Key); + + if(!preformInPlace) + { + const auto& originalGeometry = dataStructure.getDataRefAs(imageGeomPath); + + imageGeomPath = DataPath({filterArgs.value(k_OutputImageGeomName_Key)}); + outputArrayPath = imageGeomPath.createChildPath(originalGeometry.getCellDataPath().getTargetName()).createChildPath(outputArrayName); + } auto projectionDimension = filterArgs.value(k_ProjectionDimension_Key); @@ -134,7 +172,6 @@ Result<> ITKMeanProjectionImageFilter::executeImpl(DataStructure& dataStructure, } auto& imageGeom = dataStructure.getDataRefAs(imageGeomPath); - auto iArrayTupleShape = dataStructure.getDataAs(outputArrayPath)->getTupleShape(); // Update the Image Geometry with the new dimensions @@ -142,11 +179,7 @@ Result<> ITKMeanProjectionImageFilter::executeImpl(DataStructure& dataStructure, // Update the AttributeMatrix with the new tuple shape. THIS WILL ALSO CHANGE ANY OTHER DATA ARRAY THAT IS ALSO // STORED IN THAT ATTRIBUTE MATRIX - auto amPathVector = outputArrayPath.getPathVector(); - amPathVector.pop_back(); - DataPath amPath(amPathVector); - auto& attributeMatrix = dataStructure.getDataRefAs(amPath); - attributeMatrix.resizeTuples(iArrayTupleShape); + dataStructure.getDataAs(outputArrayPath.getParent())->resizeTuples(iArrayTupleShape); return {}; } diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMeanProjectionImageFilter.hpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMeanProjectionImageFilter.hpp index fadb7a1756..f72cf95c32 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMeanProjectionImageFilter.hpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMeanProjectionImageFilter.hpp @@ -52,10 +52,12 @@ class ITKIMAGEPROCESSING_EXPORT ITKMeanProjectionImageFilter : public IFilter ITKMeanProjectionImageFilter& operator=(ITKMeanProjectionImageFilter&&) noexcept = delete; // Parameter Keys + static inline constexpr StringLiteral k_ProjectionDimension_Key = "projection_dimension"; + static inline constexpr StringLiteral k_RemoveOriginalGeometry_Key = "remove_original_geometry"; static inline constexpr StringLiteral k_InputImageGeomPath_Key = "input_image_geometry_path"; static inline constexpr StringLiteral k_InputImageDataPath_Key = "input_image_data_path"; + static inline constexpr StringLiteral k_OutputImageGeomName_Key = "output_image_geometry_name"; static inline constexpr StringLiteral k_OutputImageArrayName_Key = "output_array_name"; - static inline constexpr StringLiteral k_ProjectionDimension_Key = "projection_dimension"; /** * @brief Returns the name of the filter. diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp index 1b62b2d1a6..aa318dd306 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp @@ -2,10 +2,13 @@ #include "ITKImageProcessing/Common/ITKArrayHelper.hpp" +#include "simplnx/Filter/Actions/CreateImageGeometryAction.hpp" #include "simplnx/Parameters/ArraySelectionParameter.hpp" +#include "simplnx/Parameters/BoolParameter.hpp" #include "simplnx/Parameters/DataObjectNameParameter.hpp" #include "simplnx/Parameters/GeometrySelectionParameter.hpp" #include "simplnx/Parameters/NumberParameter.hpp" +#include "simplnx/Parameters/StringParameter.hpp" #include @@ -71,6 +74,7 @@ Parameters ITKMedianProjectionImageFilter::parameters() const Parameters params; params.insertSeparator(Parameters::Separator{"Input Parameter(s)"}); params.insert(std::make_unique(k_ProjectionDimension_Key, "Projection Dimension", "The dimension index to project. 0=Slowest moving dimension.", 0u)); + params.insertLinkableParameter(std::make_unique(k_RemoveOriginalGeometry_Key, "Perform In-Place", "Performs the projection in-place for the given Image Geometry", true)); params.insertSeparator(Parameters::Separator{"Input Cell Data"}); params.insert(std::make_unique(k_InputImageGeomPath_Key, "Image Geometry", "Select the Image Geometry Group from the DataStructure.", DataPath({"Image Geometry"}), @@ -78,10 +82,13 @@ Parameters ITKMedianProjectionImageFilter::parameters() const params.insert(std::make_unique(k_InputImageDataPath_Key, "Input Cell Data", "The image data that will be processed by this filter.", DataPath{}, nx::core::ITK::GetScalarPixelAllowedTypes())); - params.insertSeparator(Parameters::Separator{"Output Cell Data"}); + params.insertSeparator(Parameters::Separator{"Output Data"}); + params.insert(std::make_unique(k_OutputImageGeomName_Key, "Created Image Geometry", "The name of the projected geometry", "Projected Image")); params.insert( std::make_unique(k_OutputImageArrayName_Key, "Output Image Data Array", "The result of the processing will be stored in this Data Array.", "Output Image Data")); + params.linkParameters(k_RemoveOriginalGeometry_Key, k_OutputImageGeomName_Key, false); + return params; } @@ -105,11 +112,32 @@ IFilter::PreflightResult ITKMedianProjectionImageFilter::preflightImpl(const Dat auto selectedInputArray = filterArgs.value(k_InputImageDataPath_Key); auto outputArrayName = filterArgs.value(k_OutputImageArrayName_Key); auto projectionDimension = filterArgs.value(k_ProjectionDimension_Key); - const DataPath outputArrayPath = selectedInputArray.replaceName(outputArrayName); + auto preformInPlace = filterArgs.value(k_RemoveOriginalGeometry_Key); + auto outputGeomName = filterArgs.value(k_OutputImageGeomName_Key); + DataPath outputArrayPath = selectedInputArray.replaceName(outputArrayName); + + Result resultOutputActions; + // The input geometry must be preserved, so we will just copy the needed array into newly created output geometry + if(!preformInPlace) + { + DataPath outputGeomPath({outputGeomName}); + + const auto& originalGeometry = dataStructure.getDataRefAs(imageGeomPath); + + // Make copy of input geometry + resultOutputActions.value().appendAction(std::make_unique( + outputGeomPath, originalGeometry.getDimensions().toContainer(), originalGeometry.getOrigin().toContainer(), + originalGeometry.getSpacing().toContainer(), originalGeometry.getCellDataPath().getTargetName())); + + outputArrayPath = outputGeomPath.createChildPath(originalGeometry.getCellDataPath().getTargetName()).createChildPath(outputArrayName); + } - Result resultOutputActions = + Result helperOutputActions = ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); + // Consolidate actions + resultOutputActions.value().actions.insert(resultOutputActions.value().actions.end(), helperOutputActions.value().actions.begin(), helperOutputActions.value().actions.end()); + return {std::move(resultOutputActions)}; } @@ -120,7 +148,17 @@ Result<> ITKMedianProjectionImageFilter::executeImpl(DataStructure& dataStructur auto imageGeomPath = filterArgs.value(k_InputImageGeomPath_Key); auto selectedInputArray = filterArgs.value(k_InputImageDataPath_Key); auto outputArrayName = filterArgs.value(k_OutputImageArrayName_Key); - const DataPath outputArrayPath = selectedInputArray.replaceName(outputArrayName); + DataPath outputArrayPath = selectedInputArray.replaceName(outputArrayName); + + auto preformInPlace = filterArgs.value(k_RemoveOriginalGeometry_Key); + + if(!preformInPlace) + { + const auto& originalGeometry = dataStructure.getDataRefAs(imageGeomPath); + + imageGeomPath = DataPath({filterArgs.value(k_OutputImageGeomName_Key)}); + outputArrayPath = imageGeomPath.createChildPath(originalGeometry.getCellDataPath().getTargetName()).createChildPath(outputArrayName); + } auto projectionDimension = filterArgs.value(k_ProjectionDimension_Key); @@ -134,7 +172,6 @@ Result<> ITKMedianProjectionImageFilter::executeImpl(DataStructure& dataStructur } auto& imageGeom = dataStructure.getDataRefAs(imageGeomPath); - auto iArrayTupleShape = dataStructure.getDataAs(outputArrayPath)->getTupleShape(); // Update the Image Geometry with the new dimensions @@ -142,11 +179,7 @@ Result<> ITKMedianProjectionImageFilter::executeImpl(DataStructure& dataStructur // Update the AttributeMatrix with the new tuple shape. THIS WILL ALSO CHANGE ANY OTHER DATA ARRAY THAT IS ALSO // STORED IN THAT ATTRIBUTE MATRIX - auto amPathVector = outputArrayPath.getPathVector(); - amPathVector.pop_back(); - DataPath amPath(amPathVector); - auto& attributeMatrix = dataStructure.getDataRefAs(amPath); - attributeMatrix.resizeTuples(iArrayTupleShape); + dataStructure.getDataAs(outputArrayPath.getParent())->resizeTuples(iArrayTupleShape); return {}; } diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.hpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.hpp index 68b4f15833..b2d04342dc 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.hpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.hpp @@ -52,10 +52,12 @@ class ITKIMAGEPROCESSING_EXPORT ITKMedianProjectionImageFilter : public IFilter ITKMedianProjectionImageFilter& operator=(ITKMedianProjectionImageFilter&&) noexcept = delete; // Parameter Keys + static inline constexpr StringLiteral k_ProjectionDimension_Key = "projection_dimension"; + static inline constexpr StringLiteral k_RemoveOriginalGeometry_Key = "remove_original_geometry"; static inline constexpr StringLiteral k_InputImageGeomPath_Key = "input_image_geometry_path"; static inline constexpr StringLiteral k_InputImageDataPath_Key = "input_image_data_path"; + static inline constexpr StringLiteral k_OutputImageGeomName_Key = "output_image_geometry_name"; static inline constexpr StringLiteral k_OutputImageArrayName_Key = "output_array_name"; - static inline constexpr StringLiteral k_ProjectionDimension_Key = "projection_dimension"; /** * @brief Returns the name of the filter. diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.cpp index 8e2572c426..92bd27c59d 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.cpp @@ -2,10 +2,13 @@ #include "ITKImageProcessing/Common/ITKArrayHelper.hpp" +#include "simplnx/Filter/Actions/CreateImageGeometryAction.hpp" #include "simplnx/Parameters/ArraySelectionParameter.hpp" +#include "simplnx/Parameters/BoolParameter.hpp" #include "simplnx/Parameters/DataObjectNameParameter.hpp" #include "simplnx/Parameters/GeometrySelectionParameter.hpp" #include "simplnx/Parameters/NumberParameter.hpp" +#include "simplnx/Parameters/StringParameter.hpp" #include @@ -71,6 +74,7 @@ Parameters ITKMinimumProjectionImageFilter::parameters() const Parameters params; params.insertSeparator(Parameters::Separator{"Input Parameter(s)"}); params.insert(std::make_unique(k_ProjectionDimension_Key, "Projection Dimension", "The dimension index to project. 0=Slowest moving dimension.", 0u)); + params.insertLinkableParameter(std::make_unique(k_RemoveOriginalGeometry_Key, "Perform In-Place", "Performs the projection in-place for the given Image Geometry", true)); params.insertSeparator(Parameters::Separator{"Input Cell Data"}); params.insert(std::make_unique(k_InputImageGeomPath_Key, "Image Geometry", "Select the Image Geometry Group from the DataStructure.", DataPath({"Image Geometry"}), @@ -78,10 +82,13 @@ Parameters ITKMinimumProjectionImageFilter::parameters() const params.insert(std::make_unique(k_InputImageDataPath_Key, "Input Cell Data", "The image data that will be processed by this filter.", DataPath{}, nx::core::ITK::GetScalarPixelAllowedTypes())); - params.insertSeparator(Parameters::Separator{"Output Cell Data"}); + params.insertSeparator(Parameters::Separator{"Output Data"}); + params.insert(std::make_unique(k_OutputImageGeomName_Key, "Created Image Geometry", "The name of the projected geometry", "Projected Image")); params.insert( std::make_unique(k_OutputImageArrayName_Key, "Output Image Data Array", "The result of the processing will be stored in this Data Array.", "Output Image Data")); + params.linkParameters(k_RemoveOriginalGeometry_Key, k_OutputImageGeomName_Key, false); + return params; } @@ -105,11 +112,32 @@ IFilter::PreflightResult ITKMinimumProjectionImageFilter::preflightImpl(const Da auto selectedInputArray = filterArgs.value(k_InputImageDataPath_Key); auto outputArrayName = filterArgs.value(k_OutputImageArrayName_Key); auto projectionDimension = filterArgs.value(k_ProjectionDimension_Key); - const DataPath outputArrayPath = selectedInputArray.replaceName(outputArrayName); + auto preformInPlace = filterArgs.value(k_RemoveOriginalGeometry_Key); + auto outputGeomName = filterArgs.value(k_OutputImageGeomName_Key); + DataPath outputArrayPath = selectedInputArray.replaceName(outputArrayName); + + Result resultOutputActions; + // The input geometry must be preserved, so we will just copy the needed array into newly created output geometry + if(!preformInPlace) + { + DataPath outputGeomPath({outputGeomName}); + + const auto& originalGeometry = dataStructure.getDataRefAs(imageGeomPath); + + // Make copy of input geometry + resultOutputActions.value().appendAction(std::make_unique( + outputGeomPath, originalGeometry.getDimensions().toContainer(), originalGeometry.getOrigin().toContainer(), + originalGeometry.getSpacing().toContainer(), originalGeometry.getCellDataPath().getTargetName())); + + outputArrayPath = outputGeomPath.createChildPath(originalGeometry.getCellDataPath().getTargetName()).createChildPath(outputArrayName); + } - Result resultOutputActions = + Result helperOutputActions = ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); + // Consolidate actions + resultOutputActions.value().actions.insert(resultOutputActions.value().actions.end(), helperOutputActions.value().actions.begin(), helperOutputActions.value().actions.end()); + return {std::move(resultOutputActions)}; } @@ -120,7 +148,17 @@ Result<> ITKMinimumProjectionImageFilter::executeImpl(DataStructure& dataStructu auto imageGeomPath = filterArgs.value(k_InputImageGeomPath_Key); auto selectedInputArray = filterArgs.value(k_InputImageDataPath_Key); auto outputArrayName = filterArgs.value(k_OutputImageArrayName_Key); - const DataPath outputArrayPath = selectedInputArray.replaceName(outputArrayName); + DataPath outputArrayPath = selectedInputArray.replaceName(outputArrayName); + + auto preformInPlace = filterArgs.value(k_RemoveOriginalGeometry_Key); + + if(!preformInPlace) + { + const auto& originalGeometry = dataStructure.getDataRefAs(imageGeomPath); + + imageGeomPath = DataPath({filterArgs.value(k_OutputImageGeomName_Key)}); + outputArrayPath = imageGeomPath.createChildPath(originalGeometry.getCellDataPath().getTargetName()).createChildPath(outputArrayName); + } auto projectionDimension = filterArgs.value(k_ProjectionDimension_Key); @@ -134,7 +172,6 @@ Result<> ITKMinimumProjectionImageFilter::executeImpl(DataStructure& dataStructu } auto& imageGeom = dataStructure.getDataRefAs(imageGeomPath); - auto iArrayTupleShape = dataStructure.getDataAs(outputArrayPath)->getTupleShape(); // Update the Image Geometry with the new dimensions @@ -142,11 +179,7 @@ Result<> ITKMinimumProjectionImageFilter::executeImpl(DataStructure& dataStructu // Update the AttributeMatrix with the new tuple shape. THIS WILL ALSO CHANGE ANY OTHER DATA ARRAY THAT IS ALSO // STORED IN THAT ATTRIBUTE MATRIX - auto amPathVector = outputArrayPath.getPathVector(); - amPathVector.pop_back(); - DataPath amPath(amPathVector); - auto& attributeMatrix = dataStructure.getDataRefAs(amPath); - attributeMatrix.resizeTuples(iArrayTupleShape); + dataStructure.getDataAs(outputArrayPath.getParent())->resizeTuples(iArrayTupleShape); return {}; } diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.hpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.hpp index 7db396b2f0..2bbd9ff23b 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.hpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.hpp @@ -52,10 +52,12 @@ class ITKIMAGEPROCESSING_EXPORT ITKMinimumProjectionImageFilter : public IFilter ITKMinimumProjectionImageFilter& operator=(ITKMinimumProjectionImageFilter&&) noexcept = delete; // Parameter Keys + static inline constexpr StringLiteral k_ProjectionDimension_Key = "projection_dimension"; + static inline constexpr StringLiteral k_RemoveOriginalGeometry_Key = "remove_original_geometry"; static inline constexpr StringLiteral k_InputImageGeomPath_Key = "input_image_geometry_path"; static inline constexpr StringLiteral k_InputImageDataPath_Key = "input_image_data_path"; + static inline constexpr StringLiteral k_OutputImageGeomName_Key = "output_image_geometry_name"; static inline constexpr StringLiteral k_OutputImageArrayName_Key = "output_array_name"; - static inline constexpr StringLiteral k_ProjectionDimension_Key = "projection_dimension"; /** * @brief Returns the name of the filter. From d7275c780d3396c7c194e2e296b8d393fa4d464d Mon Sep 17 00:00:00 2001 From: nyoungbq Date: Tue, 10 Dec 2024 16:58:57 -0500 Subject: [PATCH 06/11] Typing,naming, test cases --- .../ITKMaximumProjectionImageFilter.cpp | 4 +- .../ITKMedianProjectionImageFilter.cpp | 4 +- .../ITKMinimumProjectionImageFilter.cpp | 4 +- .../test/ITKMedianProjectionImageTest.cpp | 147 +++++++++++++++++- 4 files changed, 145 insertions(+), 14 deletions(-) diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.cpp index 5158d9e30b..bcf0716df5 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.cpp @@ -19,7 +19,7 @@ namespace cxITKMaximumProjectionImageFilter using ArrayOptionsType = ITK::ScalarPixelIdTypeList; // VectorPixelIDTypeList; template -using FilterOutputType = double; +using FilterOutputType = float; struct ITKMaximumProjectionImageFilterFunctor { @@ -59,7 +59,7 @@ Uuid ITKMaximumProjectionImageFilter::uuid() const //------------------------------------------------------------------------------ std::string ITKMaximumProjectionImageFilter::humanName() const { - return "ITK Mean Projection Image Filter"; + return "ITK Maximum Projection Image Filter"; } //------------------------------------------------------------------------------ diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp index aa318dd306..9e7d0fbe7d 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp @@ -19,7 +19,7 @@ namespace cxITKMedianProjectionImageFilter using ArrayOptionsType = ITK::ScalarPixelIdTypeList; // VectorPixelIDTypeList; template -using FilterOutputType = double; +using FilterOutputType = float; struct ITKMedianProjectionImageFilterFunctor { @@ -59,7 +59,7 @@ Uuid ITKMedianProjectionImageFilter::uuid() const //------------------------------------------------------------------------------ std::string ITKMedianProjectionImageFilter::humanName() const { - return "ITK Mean Projection Image Filter"; + return "ITK Median Projection Image Filter"; } //------------------------------------------------------------------------------ diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.cpp index 92bd27c59d..aaf3ce7afa 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.cpp @@ -19,7 +19,7 @@ namespace cxITKMinimumProjectionImageFilter using ArrayOptionsType = ITK::ScalarPixelIdTypeList; // VectorPixelIDTypeList; template -using FilterOutputType = double; +using FilterOutputType = float; struct ITKMinimumProjectionImageFilterFunctor { @@ -59,7 +59,7 @@ Uuid ITKMinimumProjectionImageFilter::uuid() const //------------------------------------------------------------------------------ std::string ITKMinimumProjectionImageFilter::humanName() const { - return "ITK Mean Projection Image Filter"; + return "ITK Minimum Projection Image Filter"; } //------------------------------------------------------------------------------ diff --git a/src/Plugins/ITKImageProcessing/test/ITKMedianProjectionImageTest.cpp b/src/Plugins/ITKImageProcessing/test/ITKMedianProjectionImageTest.cpp index ef7e441aa0..9f2d5fb3e8 100644 --- a/src/Plugins/ITKImageProcessing/test/ITKMedianProjectionImageTest.cpp +++ b/src/Plugins/ITKImageProcessing/test/ITKMedianProjectionImageTest.cpp @@ -16,7 +16,7 @@ using namespace nx::core; using namespace nx::core::Constants; using namespace nx::core::UnitTest; -TEST_CASE("ITKImageProcessing::ITKMedianProjectionImageFilter(z_projection)", "[ITKImageProcessing][ITKMedianProjectionImage][z_projection]") +TEST_CASE("ITKImageProcessing::ITKMedianProjectionImageFilter: Default Test", "[ITKImageProcessing][ITKMedianProjectionImage][defaults]") { DataStructure dataStructure; const ITKMedianProjectionImageFilter filter; @@ -33,6 +33,76 @@ TEST_CASE("ITKImageProcessing::ITKMedianProjectionImageFilter(z_projection)", "[ } // End Image Comparison Scope Arguments args; + args.insertOrAssign(ITKMedianProjectionImageFilter::k_RemoveOriginalGeometry_Key, std::make_any(true)); + args.insertOrAssign(ITKMedianProjectionImageFilter::k_InputImageGeomPath_Key, std::make_any(inputGeometryPath)); + args.insertOrAssign(ITKMedianProjectionImageFilter::k_InputImageDataPath_Key, std::make_any(inputDataPath)); + args.insertOrAssign(ITKMedianProjectionImageFilter::k_OutputImageArrayName_Key, std::make_any(outputArrayName)); + args.insertOrAssign(ITKMedianProjectionImageFilter::k_ProjectionDimension_Key, std::make_any(0)); + + auto preflightResult = filter.preflight(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_VALID(preflightResult.outputActions) + + auto executeResult = filter.execute(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result) + + const std::string md5Hash = ITKTestBase::ComputeMd5Hash(dataStructure, cellDataPath.createChildPath(outputArrayName)); + REQUIRE(md5Hash == "86de48c070480cb9809e28715f6e70e1"); +} + +TEST_CASE("ITKImageProcessing::ITKMedianProjectionImageFilter: New Geometry Default Test", "[ITKImageProcessing][ITKMedianProjectionImage][defaults]") +{ + DataStructure dataStructure; + const ITKMedianProjectionImageFilter filter; + + const DataPath inputGeometryPath({ITKTestBase::k_ImageGeometryPath}); + const DataPath cellDataPath = inputGeometryPath.createChildPath(ITKTestBase::k_ImageCellDataName); + const DataPath inputDataPath = cellDataPath.createChildPath(ITKTestBase::k_InputDataName); + const DataObjectNameParameter::ValueType outputArrayName = ITKTestBase::k_OutputDataPath; + const DataObjectNameParameter::ValueType outputImageName = "New Image Geometry"; + const DataPath outputDataPath = DataPath({outputImageName, ITKTestBase::k_ImageCellDataName, outputArrayName}); + + { // Start Image Comparison Scope + const fs::path inputFilePath = fs::path(unit_test::k_SourceDir.view()) / unit_test::k_DataDir.view() / "JSONFilters" / "Input/RA-Float.nrrd"; + Result<> imageReadResult = ITKTestBase::ReadImage(dataStructure, inputFilePath, inputGeometryPath, ITKTestBase::k_ImageCellDataName, ITKTestBase::k_InputDataName); + SIMPLNX_RESULT_REQUIRE_VALID(imageReadResult) + } // End Image Comparison Scope + + Arguments args; + args.insertOrAssign(ITKMedianProjectionImageFilter::k_RemoveOriginalGeometry_Key, std::make_any(false)); + args.insertOrAssign(ITKMedianProjectionImageFilter::k_InputImageGeomPath_Key, std::make_any(inputGeometryPath)); + args.insertOrAssign(ITKMedianProjectionImageFilter::k_InputImageDataPath_Key, std::make_any(inputDataPath)); + args.insertOrAssign(ITKMedianProjectionImageFilter::k_OutputImageArrayName_Key, std::make_any(outputArrayName)); + args.insertOrAssign(ITKMedianProjectionImageFilter::k_OutputImageGeomName_Key, std::make_any(outputImageName)); + args.insertOrAssign(ITKMedianProjectionImageFilter::k_ProjectionDimension_Key, std::make_any(0)); + + auto preflightResult = filter.preflight(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_VALID(preflightResult.outputActions) + + auto executeResult = filter.execute(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result) + + const std::string md5Hash = ITKTestBase::ComputeMd5Hash(dataStructure, outputDataPath); + REQUIRE(md5Hash == "86de48c070480cb9809e28715f6e70e1"); +} + +TEST_CASE("ITKImageProcessing::ITKMedianProjectionImageFilter: Dimensional Test", "[ITKImageProcessing][ITKMedianProjectionImage][defaults]") +{ + DataStructure dataStructure; + const ITKMedianProjectionImageFilter filter; + + const DataPath inputGeometryPath({ITKTestBase::k_ImageGeometryPath}); + const DataPath cellDataPath = inputGeometryPath.createChildPath(ITKTestBase::k_ImageCellDataName); + const DataPath inputDataPath = cellDataPath.createChildPath(ITKTestBase::k_InputDataName); + const DataObjectNameParameter::ValueType outputArrayName = ITKTestBase::k_OutputDataPath; + + { // Start Image Comparison Scope + const fs::path inputFilePath = fs::path(unit_test::k_SourceDir.view()) / unit_test::k_DataDir.view() / "JSONFilters" / "Input/RA-Float.nrrd"; + Result<> imageReadResult = ITKTestBase::ReadImage(dataStructure, inputFilePath, inputGeometryPath, ITKTestBase::k_ImageCellDataName, ITKTestBase::k_InputDataName); + SIMPLNX_RESULT_REQUIRE_VALID(imageReadResult) + } // End Image Comparison Scope + + Arguments args; + args.insertOrAssign(ITKMedianProjectionImageFilter::k_RemoveOriginalGeometry_Key, std::make_any(true)); args.insertOrAssign(ITKMedianProjectionImageFilter::k_InputImageGeomPath_Key, std::make_any(inputGeometryPath)); args.insertOrAssign(ITKMedianProjectionImageFilter::k_InputImageDataPath_Key, std::make_any(inputDataPath)); args.insertOrAssign(ITKMedianProjectionImageFilter::k_OutputImageArrayName_Key, std::make_any(outputArrayName)); @@ -44,11 +114,72 @@ TEST_CASE("ITKImageProcessing::ITKMedianProjectionImageFilter(z_projection)", "[ auto executeResult = filter.execute(dataStructure, args); SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result) - const fs::path baselineFilePath = fs::path(nx::core::unit_test::k_DataDir.view()) / "JSONFilters/Baseline/BasicFilters_MedianProjectionImageFilter_z_projection.nrrd"; - const DataPath baselineGeometryPath({ITKTestBase::k_BaselineGeometryPath}); - const DataPath baseLineCellDataPath = baselineGeometryPath.createChildPath(ITKTestBase::k_ImageCellDataName); - const DataPath baselineDataPath = baseLineCellDataPath.createChildPath(ITKTestBase::k_BaselineDataPath); - const Result<> readBaselineResult = ITKTestBase::ReadImage(dataStructure, baselineFilePath, baselineGeometryPath, ITKTestBase::k_ImageCellDataName, ITKTestBase::k_BaselineDataPath); - Result<> compareResult = ITKTestBase::CompareImages(dataStructure, baselineGeometryPath, baselineDataPath, inputGeometryPath, cellDataPath.createChildPath(outputArrayName), 0.0001); - SIMPLNX_RESULT_REQUIRE_VALID(compareResult) + const std::string md5Hash = ITKTestBase::ComputeMd5Hash(dataStructure, cellDataPath.createChildPath(outputArrayName)); + REQUIRE(md5Hash == "0990f0f6c63ea9d63b701ed7c2467de7"); +} + +TEST_CASE("ITKImageProcessing::ITKMedianProjectionImageFilter: Image Short Test", "[ITKImageProcessing][ITKMedianProjectionImage][defaults]") +{ + DataStructure dataStructure; + const ITKMedianProjectionImageFilter filter; + + const DataPath inputGeometryPath({ITKTestBase::k_ImageGeometryPath}); + const DataPath cellDataPath = inputGeometryPath.createChildPath(ITKTestBase::k_ImageCellDataName); + const DataPath inputDataPath = cellDataPath.createChildPath(ITKTestBase::k_InputDataName); + const DataObjectNameParameter::ValueType outputArrayName = ITKTestBase::k_OutputDataPath; + + { // Start Image Comparison Scope + const fs::path inputFilePath = fs::path(unit_test::k_SourceDir.view()) / unit_test::k_DataDir.view() / "JSONFilters" / "Input/Ramp-Up-Short.nrrd"; + Result<> imageReadResult = ITKTestBase::ReadImage(dataStructure, inputFilePath, inputGeometryPath, ITKTestBase::k_ImageCellDataName, ITKTestBase::k_InputDataName); + SIMPLNX_RESULT_REQUIRE_VALID(imageReadResult) + } // End Image Comparison Scope + + Arguments args; + args.insertOrAssign(ITKMedianProjectionImageFilter::k_RemoveOriginalGeometry_Key, std::make_any(true)); + args.insertOrAssign(ITKMedianProjectionImageFilter::k_InputImageGeomPath_Key, std::make_any(inputGeometryPath)); + args.insertOrAssign(ITKMedianProjectionImageFilter::k_InputImageDataPath_Key, std::make_any(inputDataPath)); + args.insertOrAssign(ITKMedianProjectionImageFilter::k_OutputImageArrayName_Key, std::make_any(outputArrayName)); + args.insertOrAssign(ITKMedianProjectionImageFilter::k_ProjectionDimension_Key, std::make_any(1)); + + auto preflightResult = filter.preflight(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_VALID(preflightResult.outputActions) + + auto executeResult = filter.execute(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result) + + const std::string md5Hash = ITKTestBase::ComputeMd5Hash(dataStructure, cellDataPath.createChildPath(outputArrayName)); + REQUIRE(md5Hash == "9fcc7164f3294811cbf2d875b0e494d1"); +} + +TEST_CASE("ITKImageProcessing::ITKMedianProjectionImageFilter: Image RGB Test", "[ITKImageProcessing][ITKMedianProjectionImage][defaults]") +{ + DataStructure dataStructure; + const ITKMedianProjectionImageFilter filter; + + const DataPath inputGeometryPath({ITKTestBase::k_ImageGeometryPath}); + const DataPath cellDataPath = inputGeometryPath.createChildPath(ITKTestBase::k_ImageCellDataName); + const DataPath inputDataPath = cellDataPath.createChildPath(ITKTestBase::k_InputDataName); + const DataObjectNameParameter::ValueType outputArrayName = ITKTestBase::k_OutputDataPath; + + { // Start Image Comparison Scope + const fs::path inputFilePath = fs::path(unit_test::k_SourceDir.view()) / unit_test::k_DataDir.view() / "JSONFilters" / "Input/VM1111Shrink-RGB.png"; + Result<> imageReadResult = ITKTestBase::ReadImage(dataStructure, inputFilePath, inputGeometryPath, ITKTestBase::k_ImageCellDataName, ITKTestBase::k_InputDataName); + SIMPLNX_RESULT_REQUIRE_VALID(imageReadResult) + } // End Image Comparison Scope + + Arguments args; + args.insertOrAssign(ITKMedianProjectionImageFilter::k_RemoveOriginalGeometry_Key, std::make_any(true)); + args.insertOrAssign(ITKMedianProjectionImageFilter::k_InputImageGeomPath_Key, std::make_any(inputGeometryPath)); + args.insertOrAssign(ITKMedianProjectionImageFilter::k_InputImageDataPath_Key, std::make_any(inputDataPath)); + args.insertOrAssign(ITKMedianProjectionImageFilter::k_OutputImageArrayName_Key, std::make_any(outputArrayName)); + args.insertOrAssign(ITKMedianProjectionImageFilter::k_ProjectionDimension_Key, std::make_any(1)); + + auto preflightResult = filter.preflight(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_VALID(preflightResult.outputActions) + + auto executeResult = filter.execute(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result) + + const std::string md5Hash = ITKTestBase::ComputeMd5Hash(dataStructure, cellDataPath.createChildPath(outputArrayName)); + REQUIRE(md5Hash == "b66bc7e92a21a33c46d9a334d2292845"); } From adaa62e78e2e1ce58811f2e77dcc16571fdbe3a7 Mon Sep 17 00:00:00 2001 From: nyoungbq Date: Wed, 11 Dec 2024 12:21:33 -0500 Subject: [PATCH 07/11] create the additional test cases from SIMPL [6 failing] --- .../test/ITKMaximumProjectionImageTest.cpp | 147 +++++++++++++++++- .../test/ITKMinimumProjectionImageTest.cpp | 147 +++++++++++++++++- 2 files changed, 278 insertions(+), 16 deletions(-) diff --git a/src/Plugins/ITKImageProcessing/test/ITKMaximumProjectionImageTest.cpp b/src/Plugins/ITKImageProcessing/test/ITKMaximumProjectionImageTest.cpp index 4d27fa3555..e05bef1ce1 100644 --- a/src/Plugins/ITKImageProcessing/test/ITKMaximumProjectionImageTest.cpp +++ b/src/Plugins/ITKImageProcessing/test/ITKMaximumProjectionImageTest.cpp @@ -16,7 +16,7 @@ using namespace nx::core; using namespace nx::core::Constants; using namespace nx::core::UnitTest; -TEST_CASE("ITKImageProcessing::ITKMaximumProjectionImageFilter(z_projection)", "[ITKImageProcessing][ITKMaximumProjectionImage][z_projection]") +TEST_CASE("ITKImageProcessing::ITKMaximumProjectionImageFilter: Default Test", "[ITKImageProcessing][ITKMaximumProjectionImage][defaults]") { DataStructure dataStructure; const ITKMaximumProjectionImageFilter filter; @@ -33,6 +33,76 @@ TEST_CASE("ITKImageProcessing::ITKMaximumProjectionImageFilter(z_projection)", " } // End Image Comparison Scope Arguments args; + args.insertOrAssign(ITKMaximumProjectionImageFilter::k_RemoveOriginalGeometry_Key, std::make_any(true)); + args.insertOrAssign(ITKMaximumProjectionImageFilter::k_InputImageGeomPath_Key, std::make_any(inputGeometryPath)); + args.insertOrAssign(ITKMaximumProjectionImageFilter::k_InputImageDataPath_Key, std::make_any(inputDataPath)); + args.insertOrAssign(ITKMaximumProjectionImageFilter::k_OutputImageArrayName_Key, std::make_any(outputArrayName)); + args.insertOrAssign(ITKMaximumProjectionImageFilter::k_ProjectionDimension_Key, std::make_any(0)); + + auto preflightResult = filter.preflight(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_VALID(preflightResult.outputActions) + + auto executeResult = filter.execute(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result) + + const std::string md5Hash = ITKTestBase::ComputeMd5Hash(dataStructure, cellDataPath.createChildPath(outputArrayName)); + REQUIRE(md5Hash == "fb78c55635b17fc9ff38ef0ef14f0948"); +} + +TEST_CASE("ITKImageProcessing::ITKMaximumProjectionImageFilter: New Geometry Default Test", "[ITKImageProcessing][ITKMaximumProjectionImage][defaults]") +{ + DataStructure dataStructure; + const ITKMaximumProjectionImageFilter filter; + + const DataPath inputGeometryPath({ITKTestBase::k_ImageGeometryPath}); + const DataPath cellDataPath = inputGeometryPath.createChildPath(ITKTestBase::k_ImageCellDataName); + const DataPath inputDataPath = cellDataPath.createChildPath(ITKTestBase::k_InputDataName); + const DataObjectNameParameter::ValueType outputArrayName = ITKTestBase::k_OutputDataPath; + const DataObjectNameParameter::ValueType outputImageName = "New Image Geometry"; + const DataPath outputDataPath = DataPath({outputImageName, ITKTestBase::k_ImageCellDataName, outputArrayName}); + + { // Start Image Comparison Scope + const fs::path inputFilePath = fs::path(unit_test::k_SourceDir.view()) / unit_test::k_DataDir.view() / "JSONFilters" / "Input/RA-Float.nrrd"; + Result<> imageReadResult = ITKTestBase::ReadImage(dataStructure, inputFilePath, inputGeometryPath, ITKTestBase::k_ImageCellDataName, ITKTestBase::k_InputDataName); + SIMPLNX_RESULT_REQUIRE_VALID(imageReadResult) + } // End Image Comparison Scope + + Arguments args; + args.insertOrAssign(ITKMaximumProjectionImageFilter::k_RemoveOriginalGeometry_Key, std::make_any(false)); + args.insertOrAssign(ITKMaximumProjectionImageFilter::k_InputImageGeomPath_Key, std::make_any(inputGeometryPath)); + args.insertOrAssign(ITKMaximumProjectionImageFilter::k_InputImageDataPath_Key, std::make_any(inputDataPath)); + args.insertOrAssign(ITKMaximumProjectionImageFilter::k_OutputImageArrayName_Key, std::make_any(outputArrayName)); + args.insertOrAssign(ITKMaximumProjectionImageFilter::k_OutputImageGeomName_Key, std::make_any(outputImageName)); + args.insertOrAssign(ITKMaximumProjectionImageFilter::k_ProjectionDimension_Key, std::make_any(0)); + + auto preflightResult = filter.preflight(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_VALID(preflightResult.outputActions) + + auto executeResult = filter.execute(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result) + + const std::string md5Hash = ITKTestBase::ComputeMd5Hash(dataStructure, outputDataPath); + REQUIRE(md5Hash == "fb78c55635b17fc9ff38ef0ef14f0948"); +} + +TEST_CASE("ITKImageProcessing::ITKMaximumProjectionImageFilter: Dimensional Test", "[ITKImageProcessing][ITKMaximumProjectionImage][defaults]") +{ + DataStructure dataStructure; + const ITKMaximumProjectionImageFilter filter; + + const DataPath inputGeometryPath({ITKTestBase::k_ImageGeometryPath}); + const DataPath cellDataPath = inputGeometryPath.createChildPath(ITKTestBase::k_ImageCellDataName); + const DataPath inputDataPath = cellDataPath.createChildPath(ITKTestBase::k_InputDataName); + const DataObjectNameParameter::ValueType outputArrayName = ITKTestBase::k_OutputDataPath; + + { // Start Image Comparison Scope + const fs::path inputFilePath = fs::path(unit_test::k_SourceDir.view()) / unit_test::k_DataDir.view() / "JSONFilters" / "Input/RA-Float.nrrd"; + Result<> imageReadResult = ITKTestBase::ReadImage(dataStructure, inputFilePath, inputGeometryPath, ITKTestBase::k_ImageCellDataName, ITKTestBase::k_InputDataName); + SIMPLNX_RESULT_REQUIRE_VALID(imageReadResult) + } // End Image Comparison Scope + + Arguments args; + args.insertOrAssign(ITKMaximumProjectionImageFilter::k_RemoveOriginalGeometry_Key, std::make_any(true)); args.insertOrAssign(ITKMaximumProjectionImageFilter::k_InputImageGeomPath_Key, std::make_any(inputGeometryPath)); args.insertOrAssign(ITKMaximumProjectionImageFilter::k_InputImageDataPath_Key, std::make_any(inputDataPath)); args.insertOrAssign(ITKMaximumProjectionImageFilter::k_OutputImageArrayName_Key, std::make_any(outputArrayName)); @@ -44,11 +114,72 @@ TEST_CASE("ITKImageProcessing::ITKMaximumProjectionImageFilter(z_projection)", " auto executeResult = filter.execute(dataStructure, args); SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result) - const fs::path baselineFilePath = fs::path(nx::core::unit_test::k_DataDir.view()) / "JSONFilters/Baseline/BasicFilters_MaximumProjectionImageFilter_z_projection.nrrd"; - const DataPath baselineGeometryPath({ITKTestBase::k_BaselineGeometryPath}); - const DataPath baseLineCellDataPath = baselineGeometryPath.createChildPath(ITKTestBase::k_ImageCellDataName); - const DataPath baselineDataPath = baseLineCellDataPath.createChildPath(ITKTestBase::k_BaselineDataPath); - const Result<> readBaselineResult = ITKTestBase::ReadImage(dataStructure, baselineFilePath, baselineGeometryPath, ITKTestBase::k_ImageCellDataName, ITKTestBase::k_BaselineDataPath); - Result<> compareResult = ITKTestBase::CompareImages(dataStructure, baselineGeometryPath, baselineDataPath, inputGeometryPath, cellDataPath.createChildPath(outputArrayName), 0.0001); - SIMPLNX_RESULT_REQUIRE_VALID(compareResult) + const std::string md5Hash = ITKTestBase::ComputeMd5Hash(dataStructure, cellDataPath.createChildPath(outputArrayName)); + REQUIRE(md5Hash == "f3f0d97c83c6b0d92df10c28e2481520"); +} + +TEST_CASE("ITKImageProcessing::ITKMaximumProjectionImageFilter: Image Short Test", "[ITKImageProcessing][ITKMaximumProjectionImage][defaults]") +{ + DataStructure dataStructure; + const ITKMaximumProjectionImageFilter filter; + + const DataPath inputGeometryPath({ITKTestBase::k_ImageGeometryPath}); + const DataPath cellDataPath = inputGeometryPath.createChildPath(ITKTestBase::k_ImageCellDataName); + const DataPath inputDataPath = cellDataPath.createChildPath(ITKTestBase::k_InputDataName); + const DataObjectNameParameter::ValueType outputArrayName = ITKTestBase::k_OutputDataPath; + + { // Start Image Comparison Scope + const fs::path inputFilePath = fs::path(unit_test::k_SourceDir.view()) / unit_test::k_DataDir.view() / "JSONFilters" / "Input/Ramp-Up-Short.nrrd"; + Result<> imageReadResult = ITKTestBase::ReadImage(dataStructure, inputFilePath, inputGeometryPath, ITKTestBase::k_ImageCellDataName, ITKTestBase::k_InputDataName); + SIMPLNX_RESULT_REQUIRE_VALID(imageReadResult) + } // End Image Comparison Scope + + Arguments args; + args.insertOrAssign(ITKMaximumProjectionImageFilter::k_RemoveOriginalGeometry_Key, std::make_any(true)); + args.insertOrAssign(ITKMaximumProjectionImageFilter::k_InputImageGeomPath_Key, std::make_any(inputGeometryPath)); + args.insertOrAssign(ITKMaximumProjectionImageFilter::k_InputImageDataPath_Key, std::make_any(inputDataPath)); + args.insertOrAssign(ITKMaximumProjectionImageFilter::k_OutputImageArrayName_Key, std::make_any(outputArrayName)); + args.insertOrAssign(ITKMaximumProjectionImageFilter::k_ProjectionDimension_Key, std::make_any(1)); + + auto preflightResult = filter.preflight(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_VALID(preflightResult.outputActions) + + auto executeResult = filter.execute(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result) + + const std::string md5Hash = ITKTestBase::ComputeMd5Hash(dataStructure, cellDataPath.createChildPath(outputArrayName)); + REQUIRE(md5Hash == "5390344262c91e83bc9208b0991a2fc9"); +} + +TEST_CASE("ITKImageProcessing::ITKMaximumProjectionImageFilter: Image RGB Test", "[ITKImageProcessing][ITKMaximumProjectionImage][defaults]") +{ + DataStructure dataStructure; + const ITKMaximumProjectionImageFilter filter; + + const DataPath inputGeometryPath({ITKTestBase::k_ImageGeometryPath}); + const DataPath cellDataPath = inputGeometryPath.createChildPath(ITKTestBase::k_ImageCellDataName); + const DataPath inputDataPath = cellDataPath.createChildPath(ITKTestBase::k_InputDataName); + const DataObjectNameParameter::ValueType outputArrayName = ITKTestBase::k_OutputDataPath; + + { // Start Image Comparison Scope + const fs::path inputFilePath = fs::path(unit_test::k_SourceDir.view()) / unit_test::k_DataDir.view() / "JSONFilters" / "Input/VM1111Shrink-RGB.png"; + Result<> imageReadResult = ITKTestBase::ReadImage(dataStructure, inputFilePath, inputGeometryPath, ITKTestBase::k_ImageCellDataName, ITKTestBase::k_InputDataName); + SIMPLNX_RESULT_REQUIRE_VALID(imageReadResult) + } // End Image Comparison Scope + + Arguments args; + args.insertOrAssign(ITKMaximumProjectionImageFilter::k_RemoveOriginalGeometry_Key, std::make_any(true)); + args.insertOrAssign(ITKMaximumProjectionImageFilter::k_InputImageGeomPath_Key, std::make_any(inputGeometryPath)); + args.insertOrAssign(ITKMaximumProjectionImageFilter::k_InputImageDataPath_Key, std::make_any(inputDataPath)); + args.insertOrAssign(ITKMaximumProjectionImageFilter::k_OutputImageArrayName_Key, std::make_any(outputArrayName)); + args.insertOrAssign(ITKMaximumProjectionImageFilter::k_ProjectionDimension_Key, std::make_any(1)); + + auto preflightResult = filter.preflight(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_VALID(preflightResult.outputActions) + + auto executeResult = filter.execute(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result) + + const std::string md5Hash = ITKTestBase::ComputeMd5Hash(dataStructure, cellDataPath.createChildPath(outputArrayName)); + REQUIRE(md5Hash == "92134e0dd38fccdf054ff23e67a72e75"); } diff --git a/src/Plugins/ITKImageProcessing/test/ITKMinimumProjectionImageTest.cpp b/src/Plugins/ITKImageProcessing/test/ITKMinimumProjectionImageTest.cpp index a3833f53dd..418f943304 100644 --- a/src/Plugins/ITKImageProcessing/test/ITKMinimumProjectionImageTest.cpp +++ b/src/Plugins/ITKImageProcessing/test/ITKMinimumProjectionImageTest.cpp @@ -16,7 +16,7 @@ using namespace nx::core; using namespace nx::core::Constants; using namespace nx::core::UnitTest; -TEST_CASE("ITKImageProcessing::ITKMinimumProjectionImageFilter(z_projection)", "[ITKImageProcessing][ITKMinimumProjectionImage][z_projection]") +TEST_CASE("ITKImageProcessing::ITKMinimumProjectionImageFilter: Default Test", "[ITKImageProcessing][ITKMinimumProjectionImage][defaults]") { DataStructure dataStructure; const ITKMinimumProjectionImageFilter filter; @@ -33,6 +33,76 @@ TEST_CASE("ITKImageProcessing::ITKMinimumProjectionImageFilter(z_projection)", " } // End Image Comparison Scope Arguments args; + args.insertOrAssign(ITKMinimumProjectionImageFilter::k_RemoveOriginalGeometry_Key, std::make_any(true)); + args.insertOrAssign(ITKMinimumProjectionImageFilter::k_InputImageGeomPath_Key, std::make_any(inputGeometryPath)); + args.insertOrAssign(ITKMinimumProjectionImageFilter::k_InputImageDataPath_Key, std::make_any(inputDataPath)); + args.insertOrAssign(ITKMinimumProjectionImageFilter::k_OutputImageArrayName_Key, std::make_any(outputArrayName)); + args.insertOrAssign(ITKMinimumProjectionImageFilter::k_ProjectionDimension_Key, std::make_any(0)); + + auto preflightResult = filter.preflight(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_VALID(preflightResult.outputActions) + + auto executeResult = filter.execute(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result) + + const std::string md5Hash = ITKTestBase::ComputeMd5Hash(dataStructure, cellDataPath.createChildPath(outputArrayName)); + REQUIRE(md5Hash == "5591e0307db733396e8cc8143e7f29f7"); +} + +TEST_CASE("ITKImageProcessing::ITKMinimumProjectionImageFilter: New Geometry Default Test", "[ITKImageProcessing][ITKMinimumProjectionImage][defaults]") +{ + DataStructure dataStructure; + const ITKMinimumProjectionImageFilter filter; + + const DataPath inputGeometryPath({ITKTestBase::k_ImageGeometryPath}); + const DataPath cellDataPath = inputGeometryPath.createChildPath(ITKTestBase::k_ImageCellDataName); + const DataPath inputDataPath = cellDataPath.createChildPath(ITKTestBase::k_InputDataName); + const DataObjectNameParameter::ValueType outputArrayName = ITKTestBase::k_OutputDataPath; + const DataObjectNameParameter::ValueType outputImageName = "New Image Geometry"; + const DataPath outputDataPath = DataPath({outputImageName, ITKTestBase::k_ImageCellDataName, outputArrayName}); + + { // Start Image Comparison Scope + const fs::path inputFilePath = fs::path(unit_test::k_SourceDir.view()) / unit_test::k_DataDir.view() / "JSONFilters" / "Input/RA-Float.nrrd"; + Result<> imageReadResult = ITKTestBase::ReadImage(dataStructure, inputFilePath, inputGeometryPath, ITKTestBase::k_ImageCellDataName, ITKTestBase::k_InputDataName); + SIMPLNX_RESULT_REQUIRE_VALID(imageReadResult) + } // End Image Comparison Scope + + Arguments args; + args.insertOrAssign(ITKMinimumProjectionImageFilter::k_RemoveOriginalGeometry_Key, std::make_any(false)); + args.insertOrAssign(ITKMinimumProjectionImageFilter::k_InputImageGeomPath_Key, std::make_any(inputGeometryPath)); + args.insertOrAssign(ITKMinimumProjectionImageFilter::k_InputImageDataPath_Key, std::make_any(inputDataPath)); + args.insertOrAssign(ITKMinimumProjectionImageFilter::k_OutputImageArrayName_Key, std::make_any(outputArrayName)); + args.insertOrAssign(ITKMinimumProjectionImageFilter::k_OutputImageGeomName_Key, std::make_any(outputImageName)); + args.insertOrAssign(ITKMinimumProjectionImageFilter::k_ProjectionDimension_Key, std::make_any(0)); + + auto preflightResult = filter.preflight(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_VALID(preflightResult.outputActions) + + auto executeResult = filter.execute(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result) + + const std::string md5Hash = ITKTestBase::ComputeMd5Hash(dataStructure, outputDataPath); + REQUIRE(md5Hash == "5591e0307db733396e8cc8143e7f29f7"); +} + +TEST_CASE("ITKImageProcessing::ITKMinimumProjectionImageFilter: Dimensional Test", "[ITKImageProcessing][ITKMinimumProjectionImage][defaults]") +{ + DataStructure dataStructure; + const ITKMinimumProjectionImageFilter filter; + + const DataPath inputGeometryPath({ITKTestBase::k_ImageGeometryPath}); + const DataPath cellDataPath = inputGeometryPath.createChildPath(ITKTestBase::k_ImageCellDataName); + const DataPath inputDataPath = cellDataPath.createChildPath(ITKTestBase::k_InputDataName); + const DataObjectNameParameter::ValueType outputArrayName = ITKTestBase::k_OutputDataPath; + + { // Start Image Comparison Scope + const fs::path inputFilePath = fs::path(unit_test::k_SourceDir.view()) / unit_test::k_DataDir.view() / "JSONFilters" / "Input/RA-Float.nrrd"; + Result<> imageReadResult = ITKTestBase::ReadImage(dataStructure, inputFilePath, inputGeometryPath, ITKTestBase::k_ImageCellDataName, ITKTestBase::k_InputDataName); + SIMPLNX_RESULT_REQUIRE_VALID(imageReadResult) + } // End Image Comparison Scope + + Arguments args; + args.insertOrAssign(ITKMinimumProjectionImageFilter::k_RemoveOriginalGeometry_Key, std::make_any(true)); args.insertOrAssign(ITKMinimumProjectionImageFilter::k_InputImageGeomPath_Key, std::make_any(inputGeometryPath)); args.insertOrAssign(ITKMinimumProjectionImageFilter::k_InputImageDataPath_Key, std::make_any(inputDataPath)); args.insertOrAssign(ITKMinimumProjectionImageFilter::k_OutputImageArrayName_Key, std::make_any(outputArrayName)); @@ -44,11 +114,72 @@ TEST_CASE("ITKImageProcessing::ITKMinimumProjectionImageFilter(z_projection)", " auto executeResult = filter.execute(dataStructure, args); SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result) - const fs::path baselineFilePath = fs::path(nx::core::unit_test::k_DataDir.view()) / "JSONFilters/Baseline/BasicFilters_MinimumProjectionImageFilter_z_projection.nrrd"; - const DataPath baselineGeometryPath({ITKTestBase::k_BaselineGeometryPath}); - const DataPath baseLineCellDataPath = baselineGeometryPath.createChildPath(ITKTestBase::k_ImageCellDataName); - const DataPath baselineDataPath = baseLineCellDataPath.createChildPath(ITKTestBase::k_BaselineDataPath); - const Result<> readBaselineResult = ITKTestBase::ReadImage(dataStructure, baselineFilePath, baselineGeometryPath, ITKTestBase::k_ImageCellDataName, ITKTestBase::k_BaselineDataPath); - Result<> compareResult = ITKTestBase::CompareImages(dataStructure, baselineGeometryPath, baselineDataPath, inputGeometryPath, cellDataPath.createChildPath(outputArrayName), 0.0001); - SIMPLNX_RESULT_REQUIRE_VALID(compareResult) + const std::string md5Hash = ITKTestBase::ComputeMd5Hash(dataStructure, cellDataPath.createChildPath(outputArrayName)); + REQUIRE(md5Hash == "6c16b87a823ca190294ac8b678ba4300"); +} + +TEST_CASE("ITKImageProcessing::ITKMinimumProjectionImageFilter: Image Short Test", "[ITKImageProcessing][ITKMinimumProjectionImage][defaults]") +{ + DataStructure dataStructure; + const ITKMinimumProjectionImageFilter filter; + + const DataPath inputGeometryPath({ITKTestBase::k_ImageGeometryPath}); + const DataPath cellDataPath = inputGeometryPath.createChildPath(ITKTestBase::k_ImageCellDataName); + const DataPath inputDataPath = cellDataPath.createChildPath(ITKTestBase::k_InputDataName); + const DataObjectNameParameter::ValueType outputArrayName = ITKTestBase::k_OutputDataPath; + + { // Start Image Comparison Scope + const fs::path inputFilePath = fs::path(unit_test::k_SourceDir.view()) / unit_test::k_DataDir.view() / "JSONFilters" / "Input/Ramp-Up-Short.nrrd"; + Result<> imageReadResult = ITKTestBase::ReadImage(dataStructure, inputFilePath, inputGeometryPath, ITKTestBase::k_ImageCellDataName, ITKTestBase::k_InputDataName); + SIMPLNX_RESULT_REQUIRE_VALID(imageReadResult) + } // End Image Comparison Scope + + Arguments args; + args.insertOrAssign(ITKMinimumProjectionImageFilter::k_RemoveOriginalGeometry_Key, std::make_any(true)); + args.insertOrAssign(ITKMinimumProjectionImageFilter::k_InputImageGeomPath_Key, std::make_any(inputGeometryPath)); + args.insertOrAssign(ITKMinimumProjectionImageFilter::k_InputImageDataPath_Key, std::make_any(inputDataPath)); + args.insertOrAssign(ITKMinimumProjectionImageFilter::k_OutputImageArrayName_Key, std::make_any(outputArrayName)); + args.insertOrAssign(ITKMinimumProjectionImageFilter::k_ProjectionDimension_Key, std::make_any(1)); + + auto preflightResult = filter.preflight(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_VALID(preflightResult.outputActions) + + auto executeResult = filter.execute(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result) + + const std::string md5Hash = ITKTestBase::ComputeMd5Hash(dataStructure, cellDataPath.createChildPath(outputArrayName)); + REQUIRE(md5Hash == "c4d83f61ffd5cc3a163155bb5d6a0698"); +} + +TEST_CASE("ITKImageProcessing::ITKMinimumProjectionImageFilter: Image RGB Test", "[ITKImageProcessing][ITKMinimumProjectionImage][defaults]") +{ + DataStructure dataStructure; + const ITKMinimumProjectionImageFilter filter; + + const DataPath inputGeometryPath({ITKTestBase::k_ImageGeometryPath}); + const DataPath cellDataPath = inputGeometryPath.createChildPath(ITKTestBase::k_ImageCellDataName); + const DataPath inputDataPath = cellDataPath.createChildPath(ITKTestBase::k_InputDataName); + const DataObjectNameParameter::ValueType outputArrayName = ITKTestBase::k_OutputDataPath; + + { // Start Image Comparison Scope + const fs::path inputFilePath = fs::path(unit_test::k_SourceDir.view()) / unit_test::k_DataDir.view() / "JSONFilters" / "Input/VM1111Shrink-RGB.png"; + Result<> imageReadResult = ITKTestBase::ReadImage(dataStructure, inputFilePath, inputGeometryPath, ITKTestBase::k_ImageCellDataName, ITKTestBase::k_InputDataName); + SIMPLNX_RESULT_REQUIRE_VALID(imageReadResult) + } // End Image Comparison Scope + + Arguments args; + args.insertOrAssign(ITKMinimumProjectionImageFilter::k_RemoveOriginalGeometry_Key, std::make_any(true)); + args.insertOrAssign(ITKMinimumProjectionImageFilter::k_InputImageGeomPath_Key, std::make_any(inputGeometryPath)); + args.insertOrAssign(ITKMinimumProjectionImageFilter::k_InputImageDataPath_Key, std::make_any(inputDataPath)); + args.insertOrAssign(ITKMinimumProjectionImageFilter::k_OutputImageArrayName_Key, std::make_any(outputArrayName)); + args.insertOrAssign(ITKMinimumProjectionImageFilter::k_ProjectionDimension_Key, std::make_any(1)); + + auto preflightResult = filter.preflight(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_VALID(preflightResult.outputActions) + + auto executeResult = filter.execute(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result) + + const std::string md5Hash = ITKTestBase::ComputeMd5Hash(dataStructure, cellDataPath.createChildPath(outputArrayName)); + REQUIRE(md5Hash == "344c2d7cf14b5e8b30b266b77a0548c2"); } From 3d3d1e5a901a612bf1e7fbf7becef17a03756478 Mon Sep 17 00:00:00 2001 From: nyoungbq Date: Fri, 13 Dec 2024 14:46:51 -0500 Subject: [PATCH 08/11] Limit typing and strip RGB/ARGB support --- .../ITKMaximumProjectionImageFilter.cpp | 95 +++++++++++++++++- .../ITKMedianProjectionImageFilter.cpp | 99 ++++++++++++++++++- .../ITKMinimumProjectionImageFilter.cpp | 95 +++++++++++++++++- .../test/ITKMaximumProjectionImageTest.cpp | 71 +++++++------ .../test/ITKMedianProjectionImageTest.cpp | 73 +++++++------- .../test/ITKMinimumProjectionImageTest.cpp | 71 +++++++------ 6 files changed, 395 insertions(+), 109 deletions(-) diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.cpp index bcf0716df5..fd12b0fd66 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.cpp @@ -2,6 +2,8 @@ #include "ITKImageProcessing/Common/ITKArrayHelper.hpp" +#include "simplnx/Common/TypesUtility.hpp" +#include "simplnx/DataStructure/IDataArray.hpp" #include "simplnx/Filter/Actions/CreateImageGeometryAction.hpp" #include "simplnx/Parameters/ArraySelectionParameter.hpp" #include "simplnx/Parameters/BoolParameter.hpp" @@ -18,8 +20,15 @@ namespace cxITKMaximumProjectionImageFilter { using ArrayOptionsType = ITK::ScalarPixelIdTypeList; // VectorPixelIDTypeList; + +template +using FilterOutputTypeUI8 = uint8; + template -using FilterOutputType = float; +using FilterOutputTypeUI16 = uint16; + +template +using FilterOutputTypeF32 = float32; struct ITKMaximumProjectionImageFilterFunctor { @@ -132,8 +141,49 @@ IFilter::PreflightResult ITKMaximumProjectionImageFilter::preflightImpl(const Da outputArrayPath = outputGeomPath.createChildPath(originalGeometry.getCellDataPath().getTargetName()).createChildPath(outputArrayName); } - Result helperOutputActions = - ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); + Result helperOutputActions = {}; + DataType type = dataStructure.getDataAs(selectedInputArray)->getDataType(); + switch(type) + { + case DataType::uint8: { + helperOutputActions = + ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); + break; + } + case DataType::uint16: { + helperOutputActions = + ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); + break; + } + case DataType::float32: { + helperOutputActions = + ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); + break; + } + case DataType::int8: + [[fallthrough]]; + case DataType::int16: + [[fallthrough]]; + case DataType::int32: + [[fallthrough]]; + case DataType::uint32: + [[fallthrough]]; + case DataType::int64: + [[fallthrough]]; + case DataType::uint64: { + [[fallthrough]]; + } + case DataType::float64: { + [[fallthrough]]; + } + case DataType::boolean: { + return MakePreflightErrorResult(-76600, fmt::format("Input {} type is not currently supported. Please reach out to devs if you have a use case.", DataTypeToString(type))); + } + } + if(helperOutputActions.invalid()) + { + return {std::move(helperOutputActions)}; + } // Consolidate actions resultOutputActions.value().actions.insert(resultOutputActions.value().actions.end(), helperOutputActions.value().actions.begin(), helperOutputActions.value().actions.end()); @@ -164,8 +214,45 @@ Result<> ITKMaximumProjectionImageFilter::executeImpl(DataStructure& dataStructu const cxITKMaximumProjectionImageFilter::ITKMaximumProjectionImageFilterFunctor itkFunctor = {projectionDimension}; - auto result = ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, + Result<> result = {}; + DataType type = dataStructure.getDataAs(selectedInputArray)->getDataType(); + switch(type) + { + case DataType::uint8: { + result = ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, + outputArrayPath, itkFunctor, shouldCancel); + break; + } + case DataType::uint16: { + result = ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, + outputArrayPath, itkFunctor, shouldCancel); + break; + } + case DataType::float32: { + result = ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath, itkFunctor, shouldCancel); + break; + } + case DataType::int8: + [[fallthrough]]; + case DataType::int16: + [[fallthrough]]; + case DataType::int32: + [[fallthrough]]; + case DataType::uint32: + [[fallthrough]]; + case DataType::int64: + [[fallthrough]]; + case DataType::uint64: { + [[fallthrough]]; + } + case DataType::float64: { + [[fallthrough]]; + } + case DataType::boolean: { + return MakeErrorResult(-76601, fmt::format("Input {} type is not currently supported. Please reach out to devs if you have a use case.", DataTypeToString(type))); + } + } if(result.invalid()) { return result; diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp index 9e7d0fbe7d..c7818264cc 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp @@ -2,6 +2,8 @@ #include "ITKImageProcessing/Common/ITKArrayHelper.hpp" +#include "simplnx/Common/TypesUtility.hpp" +#include "simplnx/DataStructure/IDataArray.hpp" #include "simplnx/Filter/Actions/CreateImageGeometryAction.hpp" #include "simplnx/Parameters/ArraySelectionParameter.hpp" #include "simplnx/Parameters/BoolParameter.hpp" @@ -17,9 +19,19 @@ using namespace nx::core; namespace cxITKMedianProjectionImageFilter { using ArrayOptionsType = ITK::ScalarPixelIdTypeList; + +// Uncommenting below line enables RGB/ARGB images that are currently unsupported +// using ArrayOptionsType = ITK::ArrayOptions, ITK::ArrayUseAllTypes>; // VectorPixelIDTypeList; + +template +using FilterOutputTypeUI8 = uint8; + template -using FilterOutputType = float; +using FilterOutputTypeUI16 = uint16; + +template +using FilterOutputTypeF32 = float32; struct ITKMedianProjectionImageFilterFunctor { @@ -132,8 +144,50 @@ IFilter::PreflightResult ITKMedianProjectionImageFilter::preflightImpl(const Dat outputArrayPath = outputGeomPath.createChildPath(originalGeometry.getCellDataPath().getTargetName()).createChildPath(outputArrayName); } - Result helperOutputActions = - ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); + Result helperOutputActions = {}; + DataType type = dataStructure.getDataAs(selectedInputArray)->getDataType(); + switch(type) + { + case DataType::uint8: { + helperOutputActions = + ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); + break; + } + case DataType::uint16: { + helperOutputActions = + ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); + break; + } + case DataType::float32: { + helperOutputActions = + ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); + break; + } + case DataType::int8: + [[fallthrough]]; + case DataType::int16: + [[fallthrough]]; + case DataType::int32: + [[fallthrough]]; + case DataType::uint32: + [[fallthrough]]; + case DataType::int64: + [[fallthrough]]; + case DataType::uint64: { + [[fallthrough]]; + } + case DataType::float64: { + [[fallthrough]]; + } + case DataType::boolean: { + return MakePreflightErrorResult(-76590, fmt::format("Input {} type is not currently supported. Please reach out to devs if you have a use case.", DataTypeToString(type))); + } + } + + if(helperOutputActions.invalid()) + { + return {std::move(helperOutputActions)}; + } // Consolidate actions resultOutputActions.value().actions.insert(resultOutputActions.value().actions.end(), helperOutputActions.value().actions.begin(), helperOutputActions.value().actions.end()); @@ -164,8 +218,45 @@ Result<> ITKMedianProjectionImageFilter::executeImpl(DataStructure& dataStructur const cxITKMedianProjectionImageFilter::ITKMedianProjectionImageFilterFunctor itkFunctor = {projectionDimension}; - auto result = ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath, + Result<> result = {}; + DataType type = dataStructure.getDataAs(selectedInputArray)->getDataType(); + switch(type) + { + case DataType::uint8: { + result = ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath, itkFunctor, shouldCancel); + break; + } + case DataType::uint16: { + result = ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath, + itkFunctor, shouldCancel); + break; + } + case DataType::float32: { + result = ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath, + itkFunctor, shouldCancel); + break; + } + case DataType::int8: + [[fallthrough]]; + case DataType::int16: + [[fallthrough]]; + case DataType::int32: + [[fallthrough]]; + case DataType::uint32: + [[fallthrough]]; + case DataType::int64: + [[fallthrough]]; + case DataType::uint64: { + [[fallthrough]]; + } + case DataType::float64: { + [[fallthrough]]; + } + case DataType::boolean: { + return MakeErrorResult(-76591, fmt::format("Input {} type is not currently supported. Please reach out to devs if you have a use case.", DataTypeToString(type))); + } + } if(result.invalid()) { return result; diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.cpp index aaf3ce7afa..635830c13a 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.cpp @@ -2,6 +2,8 @@ #include "ITKImageProcessing/Common/ITKArrayHelper.hpp" +#include "simplnx/Common/TypesUtility.hpp" +#include "simplnx/DataStructure/IDataArray.hpp" #include "simplnx/Filter/Actions/CreateImageGeometryAction.hpp" #include "simplnx/Parameters/ArraySelectionParameter.hpp" #include "simplnx/Parameters/BoolParameter.hpp" @@ -18,8 +20,15 @@ namespace cxITKMinimumProjectionImageFilter { using ArrayOptionsType = ITK::ScalarPixelIdTypeList; // VectorPixelIDTypeList; + +template +using FilterOutputTypeUI8 = uint8; + template -using FilterOutputType = float; +using FilterOutputTypeUI16 = uint16; + +template +using FilterOutputTypeF32 = float32; struct ITKMinimumProjectionImageFilterFunctor { @@ -132,8 +141,49 @@ IFilter::PreflightResult ITKMinimumProjectionImageFilter::preflightImpl(const Da outputArrayPath = outputGeomPath.createChildPath(originalGeometry.getCellDataPath().getTargetName()).createChildPath(outputArrayName); } - Result helperOutputActions = - ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); + Result helperOutputActions = {}; + DataType type = dataStructure.getDataAs(selectedInputArray)->getDataType(); + switch(type) + { + case DataType::uint8: { + helperOutputActions = + ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); + break; + } + case DataType::uint16: { + helperOutputActions = + ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); + break; + } + case DataType::float32: { + helperOutputActions = + ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); + break; + } + case DataType::int8: + [[fallthrough]]; + case DataType::int16: + [[fallthrough]]; + case DataType::int32: + [[fallthrough]]; + case DataType::uint32: + [[fallthrough]]; + case DataType::int64: + [[fallthrough]]; + case DataType::uint64: { + [[fallthrough]]; + } + case DataType::float64: { + [[fallthrough]]; + } + case DataType::boolean: { + return MakePreflightErrorResult(-76610, fmt::format("Input {} type is not currently supported. Please reach out to devs if you have a use case.", DataTypeToString(type))); + } + } + if(helperOutputActions.invalid()) + { + return {std::move(helperOutputActions)}; + } // Consolidate actions resultOutputActions.value().actions.insert(resultOutputActions.value().actions.end(), helperOutputActions.value().actions.begin(), helperOutputActions.value().actions.end()); @@ -164,8 +214,45 @@ Result<> ITKMinimumProjectionImageFilter::executeImpl(DataStructure& dataStructu const cxITKMinimumProjectionImageFilter::ITKMinimumProjectionImageFilterFunctor itkFunctor = {projectionDimension}; - auto result = ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, + Result<> result = {}; + DataType type = dataStructure.getDataAs(selectedInputArray)->getDataType(); + switch(type) + { + case DataType::uint8: { + result = ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, + outputArrayPath, itkFunctor, shouldCancel); + break; + } + case DataType::uint16: { + result = ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, + outputArrayPath, itkFunctor, shouldCancel); + break; + } + case DataType::float32: { + result = ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath, itkFunctor, shouldCancel); + break; + } + case DataType::int8: + [[fallthrough]]; + case DataType::int16: + [[fallthrough]]; + case DataType::int32: + [[fallthrough]]; + case DataType::uint32: + [[fallthrough]]; + case DataType::int64: + [[fallthrough]]; + case DataType::uint64: { + [[fallthrough]]; + } + case DataType::float64: { + [[fallthrough]]; + } + case DataType::boolean: { + return MakeErrorResult(-76601, fmt::format("Input {} type is not currently supported. Please reach out to devs if you have a use case.", DataTypeToString(type))); + } + } if(result.invalid()) { return result; diff --git a/src/Plugins/ITKImageProcessing/test/ITKMaximumProjectionImageTest.cpp b/src/Plugins/ITKImageProcessing/test/ITKMaximumProjectionImageTest.cpp index e05bef1ce1..ef274d5fd2 100644 --- a/src/Plugins/ITKImageProcessing/test/ITKMaximumProjectionImageTest.cpp +++ b/src/Plugins/ITKImageProcessing/test/ITKMaximumProjectionImageTest.cpp @@ -151,35 +151,42 @@ TEST_CASE("ITKImageProcessing::ITKMaximumProjectionImageFilter: Image Short Test REQUIRE(md5Hash == "5390344262c91e83bc9208b0991a2fc9"); } -TEST_CASE("ITKImageProcessing::ITKMaximumProjectionImageFilter: Image RGB Test", "[ITKImageProcessing][ITKMaximumProjectionImage][defaults]") -{ - DataStructure dataStructure; - const ITKMaximumProjectionImageFilter filter; - - const DataPath inputGeometryPath({ITKTestBase::k_ImageGeometryPath}); - const DataPath cellDataPath = inputGeometryPath.createChildPath(ITKTestBase::k_ImageCellDataName); - const DataPath inputDataPath = cellDataPath.createChildPath(ITKTestBase::k_InputDataName); - const DataObjectNameParameter::ValueType outputArrayName = ITKTestBase::k_OutputDataPath; - - { // Start Image Comparison Scope - const fs::path inputFilePath = fs::path(unit_test::k_SourceDir.view()) / unit_test::k_DataDir.view() / "JSONFilters" / "Input/VM1111Shrink-RGB.png"; - Result<> imageReadResult = ITKTestBase::ReadImage(dataStructure, inputFilePath, inputGeometryPath, ITKTestBase::k_ImageCellDataName, ITKTestBase::k_InputDataName); - SIMPLNX_RESULT_REQUIRE_VALID(imageReadResult) - } // End Image Comparison Scope - - Arguments args; - args.insertOrAssign(ITKMaximumProjectionImageFilter::k_RemoveOriginalGeometry_Key, std::make_any(true)); - args.insertOrAssign(ITKMaximumProjectionImageFilter::k_InputImageGeomPath_Key, std::make_any(inputGeometryPath)); - args.insertOrAssign(ITKMaximumProjectionImageFilter::k_InputImageDataPath_Key, std::make_any(inputDataPath)); - args.insertOrAssign(ITKMaximumProjectionImageFilter::k_OutputImageArrayName_Key, std::make_any(outputArrayName)); - args.insertOrAssign(ITKMaximumProjectionImageFilter::k_ProjectionDimension_Key, std::make_any(1)); - - auto preflightResult = filter.preflight(dataStructure, args); - SIMPLNX_RESULT_REQUIRE_VALID(preflightResult.outputActions) - - auto executeResult = filter.execute(dataStructure, args); - SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result) - - const std::string md5Hash = ITKTestBase::ComputeMd5Hash(dataStructure, cellDataPath.createChildPath(outputArrayName)); - REQUIRE(md5Hash == "92134e0dd38fccdf054ff23e67a72e75"); -} +/** + * TODO: Review RGB/ARGB Image Functionality with Filter + * In the current implementation RGB/ARGB has been disabled due to the inability to validate test case. The below test + * case is an adaptation from SIMPL, however, the MD5 doesn't match. In old SIMPL, when you attempt to replicate pipeline + * an error states it doesn't allow RGB images, however the old test case is passing. For the time being the functionality + * has been disabled. + */ +// TEST_CASE("ITKImageProcessing::ITKMaximumProjectionImageFilter: Image RGB Test", "[ITKImageProcessing][ITKMaximumProjectionImage][defaults]") +//{ +// DataStructure dataStructure; +// const ITKMaximumProjectionImageFilter filter; +// +// const DataPath inputGeometryPath({ITKTestBase::k_ImageGeometryPath}); +// const DataPath cellDataPath = inputGeometryPath.createChildPath(ITKTestBase::k_ImageCellDataName); +// const DataPath inputDataPath = cellDataPath.createChildPath(ITKTestBase::k_InputDataName); +// const DataObjectNameParameter::ValueType outputArrayName = ITKTestBase::k_OutputDataPath; +// +// { // Start Image Comparison Scope +// const fs::path inputFilePath = fs::path(unit_test::k_SourceDir.view()) / unit_test::k_DataDir.view() / "JSONFilters" / "Input/VM1111Shrink-RGB.png"; +// Result<> imageReadResult = ITKTestBase::ReadImage(dataStructure, inputFilePath, inputGeometryPath, ITKTestBase::k_ImageCellDataName, ITKTestBase::k_InputDataName); +// SIMPLNX_RESULT_REQUIRE_VALID(imageReadResult) +// } // End Image Comparison Scope +// +// Arguments args; +// args.insertOrAssign(ITKMaximumProjectionImageFilter::k_RemoveOriginalGeometry_Key, std::make_any(true)); +// args.insertOrAssign(ITKMaximumProjectionImageFilter::k_InputImageGeomPath_Key, std::make_any(inputGeometryPath)); +// args.insertOrAssign(ITKMaximumProjectionImageFilter::k_InputImageDataPath_Key, std::make_any(inputDataPath)); +// args.insertOrAssign(ITKMaximumProjectionImageFilter::k_OutputImageArrayName_Key, std::make_any(outputArrayName)); +// args.insertOrAssign(ITKMaximumProjectionImageFilter::k_ProjectionDimension_Key, std::make_any(1)); +// +// auto preflightResult = filter.preflight(dataStructure, args); +// SIMPLNX_RESULT_REQUIRE_VALID(preflightResult.outputActions) +// +// auto executeResult = filter.execute(dataStructure, args); +// SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result) +// +// const std::string md5Hash = ITKTestBase::ComputeMd5Hash(dataStructure, cellDataPath.createChildPath(outputArrayName)); +// REQUIRE(md5Hash == "92134e0dd38fccdf054ff23e67a72e75"); +// } diff --git a/src/Plugins/ITKImageProcessing/test/ITKMedianProjectionImageTest.cpp b/src/Plugins/ITKImageProcessing/test/ITKMedianProjectionImageTest.cpp index 9f2d5fb3e8..76398a183b 100644 --- a/src/Plugins/ITKImageProcessing/test/ITKMedianProjectionImageTest.cpp +++ b/src/Plugins/ITKImageProcessing/test/ITKMedianProjectionImageTest.cpp @@ -89,7 +89,7 @@ TEST_CASE("ITKImageProcessing::ITKMedianProjectionImageFilter: Dimensional Test" { DataStructure dataStructure; const ITKMedianProjectionImageFilter filter; - + const DataPath inputGeometryPath({ITKTestBase::k_ImageGeometryPath}); const DataPath cellDataPath = inputGeometryPath.createChildPath(ITKTestBase::k_ImageCellDataName); const DataPath inputDataPath = cellDataPath.createChildPath(ITKTestBase::k_InputDataName); @@ -151,35 +151,42 @@ TEST_CASE("ITKImageProcessing::ITKMedianProjectionImageFilter: Image Short Test" REQUIRE(md5Hash == "9fcc7164f3294811cbf2d875b0e494d1"); } -TEST_CASE("ITKImageProcessing::ITKMedianProjectionImageFilter: Image RGB Test", "[ITKImageProcessing][ITKMedianProjectionImage][defaults]") -{ - DataStructure dataStructure; - const ITKMedianProjectionImageFilter filter; - - const DataPath inputGeometryPath({ITKTestBase::k_ImageGeometryPath}); - const DataPath cellDataPath = inputGeometryPath.createChildPath(ITKTestBase::k_ImageCellDataName); - const DataPath inputDataPath = cellDataPath.createChildPath(ITKTestBase::k_InputDataName); - const DataObjectNameParameter::ValueType outputArrayName = ITKTestBase::k_OutputDataPath; - - { // Start Image Comparison Scope - const fs::path inputFilePath = fs::path(unit_test::k_SourceDir.view()) / unit_test::k_DataDir.view() / "JSONFilters" / "Input/VM1111Shrink-RGB.png"; - Result<> imageReadResult = ITKTestBase::ReadImage(dataStructure, inputFilePath, inputGeometryPath, ITKTestBase::k_ImageCellDataName, ITKTestBase::k_InputDataName); - SIMPLNX_RESULT_REQUIRE_VALID(imageReadResult) - } // End Image Comparison Scope - - Arguments args; - args.insertOrAssign(ITKMedianProjectionImageFilter::k_RemoveOriginalGeometry_Key, std::make_any(true)); - args.insertOrAssign(ITKMedianProjectionImageFilter::k_InputImageGeomPath_Key, std::make_any(inputGeometryPath)); - args.insertOrAssign(ITKMedianProjectionImageFilter::k_InputImageDataPath_Key, std::make_any(inputDataPath)); - args.insertOrAssign(ITKMedianProjectionImageFilter::k_OutputImageArrayName_Key, std::make_any(outputArrayName)); - args.insertOrAssign(ITKMedianProjectionImageFilter::k_ProjectionDimension_Key, std::make_any(1)); - - auto preflightResult = filter.preflight(dataStructure, args); - SIMPLNX_RESULT_REQUIRE_VALID(preflightResult.outputActions) - - auto executeResult = filter.execute(dataStructure, args); - SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result) - - const std::string md5Hash = ITKTestBase::ComputeMd5Hash(dataStructure, cellDataPath.createChildPath(outputArrayName)); - REQUIRE(md5Hash == "b66bc7e92a21a33c46d9a334d2292845"); -} +/** + * TODO: Review RGB/ARGB Image Functionality with Filter + * In the current implementation RGB/ARGB has been disabled due to the inability to validate test case. The below test + * case is an adaptation from SIMPL, however, the MD5 doesn't match. In old SIMPL, when you attempt to replicate pipeline + * an error states it doesn't allow RGB images, however the old test case is passing. For the time being the functionality + * has been disabled. + */ +// TEST_CASE("ITKImageProcessing::ITKMedianProjectionImageFilter: Image RGB Test", "[ITKImageProcessing][ITKMedianProjectionImage][defaults]") +//{ +// DataStructure dataStructure; +// const ITKMedianProjectionImageFilter filter; +// +// const DataPath inputGeometryPath({ITKTestBase::k_ImageGeometryPath}); +// const DataPath cellDataPath = inputGeometryPath.createChildPath(ITKTestBase::k_ImageCellDataName); +// const DataPath inputDataPath = cellDataPath.createChildPath(ITKTestBase::k_InputDataName); +// const DataObjectNameParameter::ValueType outputArrayName = ITKTestBase::k_OutputDataPath; +// +// { // Start Image Comparison Scope +// const fs::path inputFilePath = fs::path(unit_test::k_SourceDir.view()) / unit_test::k_DataDir.view() / "JSONFilters" / "Input/VM1111Shrink-RGB.png"; +// Result<> imageReadResult = ITKTestBase::ReadImage(dataStructure, inputFilePath, inputGeometryPath, ITKTestBase::k_ImageCellDataName, ITKTestBase::k_InputDataName); +// SIMPLNX_RESULT_REQUIRE_VALID(imageReadResult) +// } // End Image Comparison Scope +// +// Arguments args; +// args.insertOrAssign(ITKMedianProjectionImageFilter::k_RemoveOriginalGeometry_Key, std::make_any(true)); +// args.insertOrAssign(ITKMedianProjectionImageFilter::k_InputImageGeomPath_Key, std::make_any(inputGeometryPath)); +// args.insertOrAssign(ITKMedianProjectionImageFilter::k_InputImageDataPath_Key, std::make_any(inputDataPath)); +// args.insertOrAssign(ITKMedianProjectionImageFilter::k_OutputImageArrayName_Key, std::make_any(outputArrayName)); +// args.insertOrAssign(ITKMedianProjectionImageFilter::k_ProjectionDimension_Key, std::make_any(1)); +// +// auto preflightResult = filter.preflight(dataStructure, args); +// SIMPLNX_RESULT_REQUIRE_VALID(preflightResult.outputActions) +// +// auto executeResult = filter.execute(dataStructure, args); +// SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result) +// +// const std::string md5Hash = ITKTestBase::ComputeMd5Hash(dataStructure, cellDataPath.createChildPath(outputArrayName)); +// REQUIRE(md5Hash == "b66bc7e92a21a33c46d9a334d2292845"); +// } diff --git a/src/Plugins/ITKImageProcessing/test/ITKMinimumProjectionImageTest.cpp b/src/Plugins/ITKImageProcessing/test/ITKMinimumProjectionImageTest.cpp index 418f943304..f16e3789d2 100644 --- a/src/Plugins/ITKImageProcessing/test/ITKMinimumProjectionImageTest.cpp +++ b/src/Plugins/ITKImageProcessing/test/ITKMinimumProjectionImageTest.cpp @@ -151,35 +151,42 @@ TEST_CASE("ITKImageProcessing::ITKMinimumProjectionImageFilter: Image Short Test REQUIRE(md5Hash == "c4d83f61ffd5cc3a163155bb5d6a0698"); } -TEST_CASE("ITKImageProcessing::ITKMinimumProjectionImageFilter: Image RGB Test", "[ITKImageProcessing][ITKMinimumProjectionImage][defaults]") -{ - DataStructure dataStructure; - const ITKMinimumProjectionImageFilter filter; - - const DataPath inputGeometryPath({ITKTestBase::k_ImageGeometryPath}); - const DataPath cellDataPath = inputGeometryPath.createChildPath(ITKTestBase::k_ImageCellDataName); - const DataPath inputDataPath = cellDataPath.createChildPath(ITKTestBase::k_InputDataName); - const DataObjectNameParameter::ValueType outputArrayName = ITKTestBase::k_OutputDataPath; - - { // Start Image Comparison Scope - const fs::path inputFilePath = fs::path(unit_test::k_SourceDir.view()) / unit_test::k_DataDir.view() / "JSONFilters" / "Input/VM1111Shrink-RGB.png"; - Result<> imageReadResult = ITKTestBase::ReadImage(dataStructure, inputFilePath, inputGeometryPath, ITKTestBase::k_ImageCellDataName, ITKTestBase::k_InputDataName); - SIMPLNX_RESULT_REQUIRE_VALID(imageReadResult) - } // End Image Comparison Scope - - Arguments args; - args.insertOrAssign(ITKMinimumProjectionImageFilter::k_RemoveOriginalGeometry_Key, std::make_any(true)); - args.insertOrAssign(ITKMinimumProjectionImageFilter::k_InputImageGeomPath_Key, std::make_any(inputGeometryPath)); - args.insertOrAssign(ITKMinimumProjectionImageFilter::k_InputImageDataPath_Key, std::make_any(inputDataPath)); - args.insertOrAssign(ITKMinimumProjectionImageFilter::k_OutputImageArrayName_Key, std::make_any(outputArrayName)); - args.insertOrAssign(ITKMinimumProjectionImageFilter::k_ProjectionDimension_Key, std::make_any(1)); - - auto preflightResult = filter.preflight(dataStructure, args); - SIMPLNX_RESULT_REQUIRE_VALID(preflightResult.outputActions) - - auto executeResult = filter.execute(dataStructure, args); - SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result) - - const std::string md5Hash = ITKTestBase::ComputeMd5Hash(dataStructure, cellDataPath.createChildPath(outputArrayName)); - REQUIRE(md5Hash == "344c2d7cf14b5e8b30b266b77a0548c2"); -} +/** + * TODO: Review RGB/ARGB Image Functionality with Filter + * In the current implementation RGB/ARGB has been disabled due to the inability to validate test case. The below test + * case is an adaptation from SIMPL, however, the MD5 doesn't match. In old SIMPL, when you attempt to replicate pipeline + * an error states it doesn't allow RGB images, however the old test case is passing. For the time being the functionality + * has been disabled. + */ +// TEST_CASE("ITKImageProcessing::ITKMinimumProjectionImageFilter: Image RGB Test", "[ITKImageProcessing][ITKMinimumProjectionImage][defaults]") +//{ +// DataStructure dataStructure; +// const ITKMinimumProjectionImageFilter filter; +// +// const DataPath inputGeometryPath({ITKTestBase::k_ImageGeometryPath}); +// const DataPath cellDataPath = inputGeometryPath.createChildPath(ITKTestBase::k_ImageCellDataName); +// const DataPath inputDataPath = cellDataPath.createChildPath(ITKTestBase::k_InputDataName); +// const DataObjectNameParameter::ValueType outputArrayName = ITKTestBase::k_OutputDataPath; +// +// { // Start Image Comparison Scope +// const fs::path inputFilePath = fs::path(unit_test::k_SourceDir.view()) / unit_test::k_DataDir.view() / "JSONFilters" / "Input/VM1111Shrink-RGB.png"; +// Result<> imageReadResult = ITKTestBase::ReadImage(dataStructure, inputFilePath, inputGeometryPath, ITKTestBase::k_ImageCellDataName, ITKTestBase::k_InputDataName); +// SIMPLNX_RESULT_REQUIRE_VALID(imageReadResult) +// } // End Image Comparison Scope +// +// Arguments args; +// args.insertOrAssign(ITKMinimumProjectionImageFilter::k_RemoveOriginalGeometry_Key, std::make_any(true)); +// args.insertOrAssign(ITKMinimumProjectionImageFilter::k_InputImageGeomPath_Key, std::make_any(inputGeometryPath)); +// args.insertOrAssign(ITKMinimumProjectionImageFilter::k_InputImageDataPath_Key, std::make_any(inputDataPath)); +// args.insertOrAssign(ITKMinimumProjectionImageFilter::k_OutputImageArrayName_Key, std::make_any(outputArrayName)); +// args.insertOrAssign(ITKMinimumProjectionImageFilter::k_ProjectionDimension_Key, std::make_any(1)); +// +// auto preflightResult = filter.preflight(dataStructure, args); +// SIMPLNX_RESULT_REQUIRE_VALID(preflightResult.outputActions) +// +// auto executeResult = filter.execute(dataStructure, args); +// SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result) +// +// const std::string md5Hash = ITKTestBase::ComputeMd5Hash(dataStructure, cellDataPath.createChildPath(outputArrayName)); +// REQUIRE(md5Hash == "344c2d7cf14b5e8b30b266b77a0548c2"); +// } From bee7487bb9865da001fb6f1a59474ac637db1c91 Mon Sep 17 00:00:00 2001 From: nyoungbq Date: Fri, 13 Dec 2024 15:04:47 -0500 Subject: [PATCH 09/11] Patch image short test --- .../Filters/ITKMaximumProjectionImageFilter.cpp | 17 +++++++++++++---- .../Filters/ITKMedianProjectionImageFilter.cpp | 17 +++++++++++++---- .../Filters/ITKMinimumProjectionImageFilter.cpp | 17 +++++++++++++---- 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.cpp index fd12b0fd66..715b001db2 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.cpp @@ -24,6 +24,9 @@ using ArrayOptionsType = ITK::ScalarPixelIdTypeList; template using FilterOutputTypeUI8 = uint8; +template +using FilterOutputTypeI16 = int16; + template using FilterOutputTypeUI16 = uint16; @@ -150,6 +153,11 @@ IFilter::PreflightResult ITKMaximumProjectionImageFilter::preflightImpl(const Da ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); break; } + case DataType::int16: { + helperOutputActions = + ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); + break; + } case DataType::uint16: { helperOutputActions = ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); @@ -162,8 +170,6 @@ IFilter::PreflightResult ITKMaximumProjectionImageFilter::preflightImpl(const Da } case DataType::int8: [[fallthrough]]; - case DataType::int16: - [[fallthrough]]; case DataType::int32: [[fallthrough]]; case DataType::uint32: @@ -223,6 +229,11 @@ Result<> ITKMaximumProjectionImageFilter::executeImpl(DataStructure& dataStructu outputArrayPath, itkFunctor, shouldCancel); break; } + case DataType::int16: { + result = ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, + outputArrayPath, itkFunctor, shouldCancel); + break; + } case DataType::uint16: { result = ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath, itkFunctor, shouldCancel); @@ -235,8 +246,6 @@ Result<> ITKMaximumProjectionImageFilter::executeImpl(DataStructure& dataStructu } case DataType::int8: [[fallthrough]]; - case DataType::int16: - [[fallthrough]]; case DataType::int32: [[fallthrough]]; case DataType::uint32: diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp index c7818264cc..1ab5278db1 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp @@ -27,6 +27,9 @@ using ArrayOptionsType = ITK::ScalarPixelIdTypeList; template using FilterOutputTypeUI8 = uint8; +template +using FilterOutputTypeI16 = int16; + template using FilterOutputTypeUI16 = uint16; @@ -153,6 +156,11 @@ IFilter::PreflightResult ITKMedianProjectionImageFilter::preflightImpl(const Dat ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); break; } + case DataType::int16: { + helperOutputActions = + ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); + break; + } case DataType::uint16: { helperOutputActions = ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); @@ -165,8 +173,6 @@ IFilter::PreflightResult ITKMedianProjectionImageFilter::preflightImpl(const Dat } case DataType::int8: [[fallthrough]]; - case DataType::int16: - [[fallthrough]]; case DataType::int32: [[fallthrough]]; case DataType::uint32: @@ -227,6 +233,11 @@ Result<> ITKMedianProjectionImageFilter::executeImpl(DataStructure& dataStructur itkFunctor, shouldCancel); break; } + case DataType::int16: { + result = ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath, + itkFunctor, shouldCancel); + break; + } case DataType::uint16: { result = ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath, itkFunctor, shouldCancel); @@ -239,8 +250,6 @@ Result<> ITKMedianProjectionImageFilter::executeImpl(DataStructure& dataStructur } case DataType::int8: [[fallthrough]]; - case DataType::int16: - [[fallthrough]]; case DataType::int32: [[fallthrough]]; case DataType::uint32: diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.cpp index 635830c13a..004bf9e614 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.cpp @@ -24,6 +24,9 @@ using ArrayOptionsType = ITK::ScalarPixelIdTypeList; template using FilterOutputTypeUI8 = uint8; +template +using FilterOutputTypeI16 = int16; + template using FilterOutputTypeUI16 = uint16; @@ -150,6 +153,11 @@ IFilter::PreflightResult ITKMinimumProjectionImageFilter::preflightImpl(const Da ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); break; } + case DataType::int16: { + helperOutputActions = + ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); + break; + } case DataType::uint16: { helperOutputActions = ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); @@ -162,8 +170,6 @@ IFilter::PreflightResult ITKMinimumProjectionImageFilter::preflightImpl(const Da } case DataType::int8: [[fallthrough]]; - case DataType::int16: - [[fallthrough]]; case DataType::int32: [[fallthrough]]; case DataType::uint32: @@ -223,6 +229,11 @@ Result<> ITKMinimumProjectionImageFilter::executeImpl(DataStructure& dataStructu outputArrayPath, itkFunctor, shouldCancel); break; } + case DataType::int16: { + result = ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, + outputArrayPath, itkFunctor, shouldCancel); + break; + } case DataType::uint16: { result = ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath, itkFunctor, shouldCancel); @@ -235,8 +246,6 @@ Result<> ITKMinimumProjectionImageFilter::executeImpl(DataStructure& dataStructu } case DataType::int8: [[fallthrough]]; - case DataType::int16: - [[fallthrough]]; case DataType::int32: [[fallthrough]]; case DataType::uint32: From 62ad45ef5fc2df67741256efdbd95a1fc6920786 Mon Sep 17 00:00:00 2001 From: nyoungbq Date: Wed, 15 Jan 2025 10:39:27 -0500 Subject: [PATCH 10/11] [broken compile] code review and centralization --- src/Plugins/ITKImageProcessing/CMakeLists.txt | 1 + .../Common/ProjectionUtils.hpp | 211 ++++++++++++++++++ .../ITKMedianProjectionImageFilter.cpp | 160 +------------ 3 files changed, 220 insertions(+), 152 deletions(-) create mode 100644 src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ProjectionUtils.hpp diff --git a/src/Plugins/ITKImageProcessing/CMakeLists.txt b/src/Plugins/ITKImageProcessing/CMakeLists.txt index be0d09c6ea..239bda2a10 100644 --- a/src/Plugins/ITKImageProcessing/CMakeLists.txt +++ b/src/Plugins/ITKImageProcessing/CMakeLists.txt @@ -265,6 +265,7 @@ set(${PLUGIN_NAME}_Common_Srcs ${${PLUGIN_NAME}_SOURCE_DIR}/src/${PLUGIN_NAME}/Common/ITKArrayHelper.cpp ${${PLUGIN_NAME}_SOURCE_DIR}/src/${PLUGIN_NAME}/Common/ITKProgressObserver.hpp ${${PLUGIN_NAME}_SOURCE_DIR}/src/${PLUGIN_NAME}/Common/ITKDream3DFilterInterruption.hpp + ${${PLUGIN_NAME}_SOURCE_DIR}/src/${PLUGIN_NAME}/Common/ProjectionUtils.hpp ${${PLUGIN_NAME}_SOURCE_DIR}/src/${PLUGIN_NAME}/Common/ReadImageUtils.hpp ${${PLUGIN_NAME}_SOURCE_DIR}/src/${PLUGIN_NAME}/Common/ReadImageUtils.cpp ) diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ProjectionUtils.hpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ProjectionUtils.hpp new file mode 100644 index 0000000000..49ac7cd0c4 --- /dev/null +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ProjectionUtils.hpp @@ -0,0 +1,211 @@ +#pragma once + +#include "simplnx/Common/Result.hpp" +#include "simplnx/Common/Types.hpp" +#include "simplnx/Filter/Actions/CreateImageGeometryAction.hpp" +#include "simplnx/Filter/IFilter.hpp" + +#include "ITKArrayHelper.hpp" + +using namespace nx::core; + +namespace ProjectionUtilities +{ +// uint8, int16, uint16, float32 +using ITKProjectionSupportedOutputTypes = ArrayTypeOptions; + +template +struct FixedOutputTypeHelper +{ + template + using FilterOutputType = T; +}; + +template +struct RunITKProjectionDataCheckFunctor +{ + template + auto operator()(const DataStructure& dataStructure, const DataPath& selectedInputArray, const DataPath& imageGeomPath, const DataPath& outputArrayPath) const + { + return ITK::DataCheck::FilterOutputType>(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); + } +}; + +template +struct RunITKProjectionExecuteFunctor +{ + template + auto operator()(DataStructure& dataStructure, const DataPath& selectedInputArray, const DataPath& imageGeomPath, const DataPath& outputArrayPath, ITKFunctorType&& itkFunctor, + const std::atomic_bool& shouldCancel) const + { + return ITK::Execute::FilterOutputType>(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath, itkFunctor, + shouldCancel); + } +}; + +template +auto RunTemplateFunctor(FuncT&& func, FallbackFuncT&& fallback, DataType dataType, ArgsT&&... args) +{ + if constexpr(ArrayTypeOptions::UsingBoolean) + { + if(dataType == DataType::boolean) + { + return func.template operator()(std::forward(args)...); + } + } + if constexpr(ArrayTypeOptions::UsingInt8) + { + if(dataType == DataType::int8) + { + return func.template operator()(std::forward(args)...); + } + } + if constexpr(ArrayTypeOptions::UsingInt16) + { + if(dataType == DataType::int16) + { + return func.template operator()(std::forward(args)...); + } + } + if constexpr(ArrayTypeOptions::UsingInt32) + { + if(dataType == DataType::int32) + { + return func.template operator()(std::forward(args)...); + } + } + if constexpr(ArrayTypeOptions::UsingInt64) + { + if(dataType == DataType::int64) + { + return func.template operator()(std::forward(args)...); + } + } + if constexpr(ArrayTypeOptions::UsingUInt8) + { + if(dataType == DataType::uint8) + { + return func.template operator()(std::forward(args)...); + } + } + if constexpr(ArrayTypeOptions::UsingUInt16) + { + if(dataType == DataType::uint16) + { + return func.template operator()(std::forward(args)...); + } + } + if constexpr(ArrayTypeOptions::UsingUInt32) + { + if(dataType == DataType::uint32) + { + return func.template operator()(std::forward(args)...); + } + } + if constexpr(ArrayTypeOptions::UsingUInt64) + { + if(dataType == DataType::uint64) + { + return func.template operator()(std::forward(args)...); + } + } + if constexpr(ArrayTypeOptions::UsingFloat32) + { + if(dataType == DataType::float32) + { + return func.template operator()(std::forward(args)...); + } + } + if constexpr(ArrayTypeOptions::UsingFloat64) + { + if(dataType == DataType::float64) + { + return func.template operator()(std::forward(args)...); + } + } + return fallback(dataType); +} + +template +IFilter::PreflightResult RunITKProjectionDataCheck(const DataStructure& dataStructure, const DataPath& selectedInputArray, const DataPath& imageGeomPath, const std::string& outputGeomName, + bool performInPlace, const std::string& outputArrayName) +{ + DataPath outputArrayPath = selectedInputArray.replaceName(outputArrayName); + Result resultOutputActions; + // The input geometry must be preserved, so we will just copy the needed array into newly created output geometry + if(!performInPlace) + { + DataPath outputGeomPath({outputGeomName}); + + const auto& originalGeometry = dataStructure.getDataRefAs(imageGeomPath); + + // Make copy of input geometry + resultOutputActions.value().appendAction(std::make_unique( + outputGeomPath, originalGeometry.getDimensions().toContainer(), originalGeometry.getOrigin().toContainer(), + originalGeometry.getSpacing().toContainer(), originalGeometry.getCellDataPath().getTargetName())); + + outputArrayPath = outputGeomPath.createChildPath(originalGeometry.getCellDataPath().getTargetName()).createChildPath(outputArrayName); + } + + auto fallbackFunc = [](DataType dataType) { + return MakeErrorResult(-76590, fmt::format("Input {} type is not currently supported. Please reach out to devs if you have a use case.", DataTypeToString(dataType))); + }; + + DataType type = dataStructure.getDataRefAs(selectedInputArray).getDataType(); + Result helperOutputActions = RunTemplateFunctor(RunITKProjectionDataCheckFunctor{}, fallbackFunc, type, dataStructure, + selectedInputArray, imageGeomPath, outputArrayPath); + + if(helperOutputActions.invalid()) + { + return {std::move(helperOutputActions)}; + } + + // Consolidate actions + resultOutputActions.value().actions.insert(resultOutputActions.value().actions.end(), helperOutputActions.value().actions.begin(), helperOutputActions.value().actions.end()); + + return {std::move(resultOutputActions)}; +} + +template +Result<> RunITKProjectionExecute(DataStructure& dataStructure, const DataPath& selectedInputArray, const DataPath& imageGeomPath, const std::atomic_bool& shouldCancel, + const std::string& outputArrayName, bool performInPlace, ITKFunctorType&& itkFunctor, const std::string& outputImageGeomName) +{ + DataPath outputArrayPath = selectedInputArray.replaceName(outputArrayName); + + DataPath finalImageGeomPath = imageGeomPath; + + if(!performInPlace) + { + const auto& originalGeometry = dataStructure.getDataRefAs(imageGeomPath); + + finalImageGeomPath = DataPath({outputImageGeomName}); + outputArrayPath = finalImageGeomPath.createChildPath(originalGeometry.getCellDataPath().getTargetName()).createChildPath(outputArrayName); + } + + DataType type = dataStructure.getDataRefAs(selectedInputArray).getDataType(); + + auto fallbackFunc = [](DataType dataType) { + return MakeErrorResult(-76591, fmt::format("Input {} type is not currently supported. Please reach out to devs if you have a use case.", DataTypeToString(dataType))); + }; + + Result<> result = RunTemplateFunctor(RunITKProjectionExecuteFunctor{}, fallbackFunc, type, dataStructure, selectedInputArray, + finalImageGeomPath, outputArrayPath, itkFunctor, shouldCancel); + + if(result.invalid()) + { + return result; + } + + auto& imageGeom = dataStructure.getDataRefAs(finalImageGeomPath); + auto iArrayTupleShape = dataStructure.getDataAs(outputArrayPath)->getTupleShape(); + + // Update the Image Geometry with the new dimensions + imageGeom.setDimensions({iArrayTupleShape[2], iArrayTupleShape[1], iArrayTupleShape[0]}); + + // Update the AttributeMatrix with the new tuple shape. THIS WILL ALSO CHANGE ANY OTHER DATA ARRAY THAT IS ALSO + // STORED IN THAT ATTRIBUTE MATRIX + dataStructure.getDataAs(outputArrayPath.getParent())->resizeTuples(iArrayTupleShape); + + return {}; +} +} // namespace ProjectionUtilities \ No newline at end of file diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp index 1ab5278db1..c39f219134 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp @@ -12,6 +12,8 @@ #include "simplnx/Parameters/NumberParameter.hpp" #include "simplnx/Parameters/StringParameter.hpp" +#include "ITKImageProcessing/Common/ProjectionUtils.hpp" + #include using namespace nx::core; @@ -24,18 +26,6 @@ using ArrayOptionsType = ITK::ScalarPixelIdTypeList; // using ArrayOptionsType = ITK::ArrayOptions, ITK::ArrayUseAllTypes>; // VectorPixelIDTypeList; -template -using FilterOutputTypeUI8 = uint8; - -template -using FilterOutputTypeI16 = int16; - -template -using FilterOutputTypeUI16 = uint16; - -template -using FilterOutputTypeF32 = float32; - struct ITKMedianProjectionImageFilterFunctor { uint32 projectionDimension = 0u; @@ -127,78 +117,10 @@ IFilter::PreflightResult ITKMedianProjectionImageFilter::preflightImpl(const Dat auto selectedInputArray = filterArgs.value(k_InputImageDataPath_Key); auto outputArrayName = filterArgs.value(k_OutputImageArrayName_Key); auto projectionDimension = filterArgs.value(k_ProjectionDimension_Key); - auto preformInPlace = filterArgs.value(k_RemoveOriginalGeometry_Key); + auto performInPlace = filterArgs.value(k_RemoveOriginalGeometry_Key); auto outputGeomName = filterArgs.value(k_OutputImageGeomName_Key); - DataPath outputArrayPath = selectedInputArray.replaceName(outputArrayName); - - Result resultOutputActions; - // The input geometry must be preserved, so we will just copy the needed array into newly created output geometry - if(!preformInPlace) - { - DataPath outputGeomPath({outputGeomName}); - - const auto& originalGeometry = dataStructure.getDataRefAs(imageGeomPath); - - // Make copy of input geometry - resultOutputActions.value().appendAction(std::make_unique( - outputGeomPath, originalGeometry.getDimensions().toContainer(), originalGeometry.getOrigin().toContainer(), - originalGeometry.getSpacing().toContainer(), originalGeometry.getCellDataPath().getTargetName())); - - outputArrayPath = outputGeomPath.createChildPath(originalGeometry.getCellDataPath().getTargetName()).createChildPath(outputArrayName); - } - - Result helperOutputActions = {}; - DataType type = dataStructure.getDataAs(selectedInputArray)->getDataType(); - switch(type) - { - case DataType::uint8: { - helperOutputActions = - ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); - break; - } - case DataType::int16: { - helperOutputActions = - ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); - break; - } - case DataType::uint16: { - helperOutputActions = - ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); - break; - } - case DataType::float32: { - helperOutputActions = - ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); - break; - } - case DataType::int8: - [[fallthrough]]; - case DataType::int32: - [[fallthrough]]; - case DataType::uint32: - [[fallthrough]]; - case DataType::int64: - [[fallthrough]]; - case DataType::uint64: { - [[fallthrough]]; - } - case DataType::float64: { - [[fallthrough]]; - } - case DataType::boolean: { - return MakePreflightErrorResult(-76590, fmt::format("Input {} type is not currently supported. Please reach out to devs if you have a use case.", DataTypeToString(type))); - } - } - - if(helperOutputActions.invalid()) - { - return {std::move(helperOutputActions)}; - } - - // Consolidate actions - resultOutputActions.value().actions.insert(resultOutputActions.value().actions.end(), helperOutputActions.value().actions.begin(), helperOutputActions.value().actions.end()); - return {std::move(resultOutputActions)}; + return ProjectionUtilities::RunITKProjectionDataCheck(dataStructure, selectedInputArray, imageGeomPath, outputGeomName, performInPlace, outputArrayName); } //------------------------------------------------------------------------------ @@ -208,79 +130,13 @@ Result<> ITKMedianProjectionImageFilter::executeImpl(DataStructure& dataStructur auto imageGeomPath = filterArgs.value(k_InputImageGeomPath_Key); auto selectedInputArray = filterArgs.value(k_InputImageDataPath_Key); auto outputArrayName = filterArgs.value(k_OutputImageArrayName_Key); - DataPath outputArrayPath = selectedInputArray.replaceName(outputArrayName); - - auto preformInPlace = filterArgs.value(k_RemoveOriginalGeometry_Key); - - if(!preformInPlace) - { - const auto& originalGeometry = dataStructure.getDataRefAs(imageGeomPath); - - imageGeomPath = DataPath({filterArgs.value(k_OutputImageGeomName_Key)}); - outputArrayPath = imageGeomPath.createChildPath(originalGeometry.getCellDataPath().getTargetName()).createChildPath(outputArrayName); - } - + auto outputImageGeomName = filterArgs.value(k_OutputImageGeomName_Key); + auto performInPlace = filterArgs.value(k_RemoveOriginalGeometry_Key); auto projectionDimension = filterArgs.value(k_ProjectionDimension_Key); const cxITKMedianProjectionImageFilter::ITKMedianProjectionImageFilterFunctor itkFunctor = {projectionDimension}; - Result<> result = {}; - DataType type = dataStructure.getDataAs(selectedInputArray)->getDataType(); - switch(type) - { - case DataType::uint8: { - result = ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath, - itkFunctor, shouldCancel); - break; - } - case DataType::int16: { - result = ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath, - itkFunctor, shouldCancel); - break; - } - case DataType::uint16: { - result = ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath, - itkFunctor, shouldCancel); - break; - } - case DataType::float32: { - result = ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath, - itkFunctor, shouldCancel); - break; - } - case DataType::int8: - [[fallthrough]]; - case DataType::int32: - [[fallthrough]]; - case DataType::uint32: - [[fallthrough]]; - case DataType::int64: - [[fallthrough]]; - case DataType::uint64: { - [[fallthrough]]; - } - case DataType::float64: { - [[fallthrough]]; - } - case DataType::boolean: { - return MakeErrorResult(-76591, fmt::format("Input {} type is not currently supported. Please reach out to devs if you have a use case.", DataTypeToString(type))); - } - } - if(result.invalid()) - { - return result; - } - - auto& imageGeom = dataStructure.getDataRefAs(imageGeomPath); - auto iArrayTupleShape = dataStructure.getDataAs(outputArrayPath)->getTupleShape(); - - // Update the Image Geometry with the new dimensions - imageGeom.setDimensions({iArrayTupleShape[2], iArrayTupleShape[1], iArrayTupleShape[0]}); - - // Update the AttributeMatrix with the new tuple shape. THIS WILL ALSO CHANGE ANY OTHER DATA ARRAY THAT IS ALSO - // STORED IN THAT ATTRIBUTE MATRIX - dataStructure.getDataAs(outputArrayPath.getParent())->resizeTuples(iArrayTupleShape); - - return {}; + return ProjectionUtilities::RunITKProjectionExecute(dataStructure, selectedInputArray, imageGeomPath, shouldCancel, outputArrayName, performInPlace, itkFunctor, + outputImageGeomName); } } // namespace nx::core From 31c1deedc014c257d04bb7bd6a52f63ccdc8ee37 Mon Sep 17 00:00:00 2001 From: nyoungbq Date: Wed, 15 Jan 2025 12:50:20 -0500 Subject: [PATCH 11/11] [compiling, passing] finish review feedback --- .../Common/ProjectionUtils.hpp | 4 +- .../ITKMaximumProjectionImageFilter.cpp | 163 +----------------- .../ITKMedianProjectionImageFilter.cpp | 3 - .../ITKMinimumProjectionImageFilter.cpp | 163 +----------------- 4 files changed, 20 insertions(+), 313 deletions(-) diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ProjectionUtils.hpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ProjectionUtils.hpp index 49ac7cd0c4..8995b1771a 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ProjectionUtils.hpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ProjectionUtils.hpp @@ -27,7 +27,7 @@ struct RunITKProjectionDataCheckFunctor template auto operator()(const DataStructure& dataStructure, const DataPath& selectedInputArray, const DataPath& imageGeomPath, const DataPath& outputArrayPath) const { - return ITK::DataCheck::FilterOutputType>(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); + return ITK::DataCheck::template FilterOutputType>(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); } }; @@ -38,7 +38,7 @@ struct RunITKProjectionExecuteFunctor auto operator()(DataStructure& dataStructure, const DataPath& selectedInputArray, const DataPath& imageGeomPath, const DataPath& outputArrayPath, ITKFunctorType&& itkFunctor, const std::atomic_bool& shouldCancel) const { - return ITK::Execute::FilterOutputType>(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath, itkFunctor, + return ITK::Execute::template FilterOutputType>(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath, itkFunctor, shouldCancel); } }; diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.cpp index 715b001db2..0ccce7029a 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMaximumProjectionImageFilter.cpp @@ -1,10 +1,7 @@ #include "ITKMaximumProjectionImageFilter.hpp" -#include "ITKImageProcessing/Common/ITKArrayHelper.hpp" - #include "simplnx/Common/TypesUtility.hpp" #include "simplnx/DataStructure/IDataArray.hpp" -#include "simplnx/Filter/Actions/CreateImageGeometryAction.hpp" #include "simplnx/Parameters/ArraySelectionParameter.hpp" #include "simplnx/Parameters/BoolParameter.hpp" #include "simplnx/Parameters/DataObjectNameParameter.hpp" @@ -12,6 +9,8 @@ #include "simplnx/Parameters/NumberParameter.hpp" #include "simplnx/Parameters/StringParameter.hpp" +#include "ITKImageProcessing/Common/ProjectionUtils.hpp" + #include using namespace nx::core; @@ -21,18 +20,6 @@ namespace cxITKMaximumProjectionImageFilter using ArrayOptionsType = ITK::ScalarPixelIdTypeList; // VectorPixelIDTypeList; -template -using FilterOutputTypeUI8 = uint8; - -template -using FilterOutputTypeI16 = int16; - -template -using FilterOutputTypeUI16 = uint16; - -template -using FilterOutputTypeF32 = float32; - struct ITKMaximumProjectionImageFilterFunctor { uint32 projectionDimension = 0u; @@ -124,77 +111,11 @@ IFilter::PreflightResult ITKMaximumProjectionImageFilter::preflightImpl(const Da auto selectedInputArray = filterArgs.value(k_InputImageDataPath_Key); auto outputArrayName = filterArgs.value(k_OutputImageArrayName_Key); auto projectionDimension = filterArgs.value(k_ProjectionDimension_Key); - auto preformInPlace = filterArgs.value(k_RemoveOriginalGeometry_Key); + auto performInPlace = filterArgs.value(k_RemoveOriginalGeometry_Key); auto outputGeomName = filterArgs.value(k_OutputImageGeomName_Key); - DataPath outputArrayPath = selectedInputArray.replaceName(outputArrayName); - - Result resultOutputActions; - // The input geometry must be preserved, so we will just copy the needed array into newly created output geometry - if(!preformInPlace) - { - DataPath outputGeomPath({outputGeomName}); - - const auto& originalGeometry = dataStructure.getDataRefAs(imageGeomPath); - - // Make copy of input geometry - resultOutputActions.value().appendAction(std::make_unique( - outputGeomPath, originalGeometry.getDimensions().toContainer(), originalGeometry.getOrigin().toContainer(), - originalGeometry.getSpacing().toContainer(), originalGeometry.getCellDataPath().getTargetName())); - - outputArrayPath = outputGeomPath.createChildPath(originalGeometry.getCellDataPath().getTargetName()).createChildPath(outputArrayName); - } - - Result helperOutputActions = {}; - DataType type = dataStructure.getDataAs(selectedInputArray)->getDataType(); - switch(type) - { - case DataType::uint8: { - helperOutputActions = - ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); - break; - } - case DataType::int16: { - helperOutputActions = - ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); - break; - } - case DataType::uint16: { - helperOutputActions = - ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); - break; - } - case DataType::float32: { - helperOutputActions = - ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); - break; - } - case DataType::int8: - [[fallthrough]]; - case DataType::int32: - [[fallthrough]]; - case DataType::uint32: - [[fallthrough]]; - case DataType::int64: - [[fallthrough]]; - case DataType::uint64: { - [[fallthrough]]; - } - case DataType::float64: { - [[fallthrough]]; - } - case DataType::boolean: { - return MakePreflightErrorResult(-76600, fmt::format("Input {} type is not currently supported. Please reach out to devs if you have a use case.", DataTypeToString(type))); - } - } - if(helperOutputActions.invalid()) - { - return {std::move(helperOutputActions)}; - } - - // Consolidate actions - resultOutputActions.value().actions.insert(resultOutputActions.value().actions.end(), helperOutputActions.value().actions.begin(), helperOutputActions.value().actions.end()); - return {std::move(resultOutputActions)}; + return ProjectionUtilities::RunITKProjectionDataCheck(dataStructure, selectedInputArray, imageGeomPath, outputGeomName, performInPlace, + outputArrayName); } //------------------------------------------------------------------------------ @@ -204,79 +125,13 @@ Result<> ITKMaximumProjectionImageFilter::executeImpl(DataStructure& dataStructu auto imageGeomPath = filterArgs.value(k_InputImageGeomPath_Key); auto selectedInputArray = filterArgs.value(k_InputImageDataPath_Key); auto outputArrayName = filterArgs.value(k_OutputImageArrayName_Key); - DataPath outputArrayPath = selectedInputArray.replaceName(outputArrayName); - - auto preformInPlace = filterArgs.value(k_RemoveOriginalGeometry_Key); - - if(!preformInPlace) - { - const auto& originalGeometry = dataStructure.getDataRefAs(imageGeomPath); - - imageGeomPath = DataPath({filterArgs.value(k_OutputImageGeomName_Key)}); - outputArrayPath = imageGeomPath.createChildPath(originalGeometry.getCellDataPath().getTargetName()).createChildPath(outputArrayName); - } - + auto outputImageGeomName = filterArgs.value(k_OutputImageGeomName_Key); + auto performInPlace = filterArgs.value(k_RemoveOriginalGeometry_Key); auto projectionDimension = filterArgs.value(k_ProjectionDimension_Key); const cxITKMaximumProjectionImageFilter::ITKMaximumProjectionImageFilterFunctor itkFunctor = {projectionDimension}; - Result<> result = {}; - DataType type = dataStructure.getDataAs(selectedInputArray)->getDataType(); - switch(type) - { - case DataType::uint8: { - result = ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, - outputArrayPath, itkFunctor, shouldCancel); - break; - } - case DataType::int16: { - result = ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, - outputArrayPath, itkFunctor, shouldCancel); - break; - } - case DataType::uint16: { - result = ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, - outputArrayPath, itkFunctor, shouldCancel); - break; - } - case DataType::float32: { - result = ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, - outputArrayPath, itkFunctor, shouldCancel); - break; - } - case DataType::int8: - [[fallthrough]]; - case DataType::int32: - [[fallthrough]]; - case DataType::uint32: - [[fallthrough]]; - case DataType::int64: - [[fallthrough]]; - case DataType::uint64: { - [[fallthrough]]; - } - case DataType::float64: { - [[fallthrough]]; - } - case DataType::boolean: { - return MakeErrorResult(-76601, fmt::format("Input {} type is not currently supported. Please reach out to devs if you have a use case.", DataTypeToString(type))); - } - } - if(result.invalid()) - { - return result; - } - - auto& imageGeom = dataStructure.getDataRefAs(imageGeomPath); - auto iArrayTupleShape = dataStructure.getDataAs(outputArrayPath)->getTupleShape(); - - // Update the Image Geometry with the new dimensions - imageGeom.setDimensions({iArrayTupleShape[2], iArrayTupleShape[1], iArrayTupleShape[0]}); - - // Update the AttributeMatrix with the new tuple shape. THIS WILL ALSO CHANGE ANY OTHER DATA ARRAY THAT IS ALSO - // STORED IN THAT ATTRIBUTE MATRIX - dataStructure.getDataAs(outputArrayPath.getParent())->resizeTuples(iArrayTupleShape); - - return {}; + return ProjectionUtilities::RunITKProjectionExecute(dataStructure, selectedInputArray, imageGeomPath, shouldCancel, outputArrayName, + performInPlace, itkFunctor, outputImageGeomName); } } // namespace nx::core diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp index c39f219134..612c56aa92 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMedianProjectionImageFilter.cpp @@ -1,10 +1,7 @@ #include "ITKMedianProjectionImageFilter.hpp" -#include "ITKImageProcessing/Common/ITKArrayHelper.hpp" - #include "simplnx/Common/TypesUtility.hpp" #include "simplnx/DataStructure/IDataArray.hpp" -#include "simplnx/Filter/Actions/CreateImageGeometryAction.hpp" #include "simplnx/Parameters/ArraySelectionParameter.hpp" #include "simplnx/Parameters/BoolParameter.hpp" #include "simplnx/Parameters/DataObjectNameParameter.hpp" diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.cpp index 004bf9e614..8e2daa213f 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKMinimumProjectionImageFilter.cpp @@ -1,10 +1,7 @@ #include "ITKMinimumProjectionImageFilter.hpp" -#include "ITKImageProcessing/Common/ITKArrayHelper.hpp" - #include "simplnx/Common/TypesUtility.hpp" #include "simplnx/DataStructure/IDataArray.hpp" -#include "simplnx/Filter/Actions/CreateImageGeometryAction.hpp" #include "simplnx/Parameters/ArraySelectionParameter.hpp" #include "simplnx/Parameters/BoolParameter.hpp" #include "simplnx/Parameters/DataObjectNameParameter.hpp" @@ -12,6 +9,8 @@ #include "simplnx/Parameters/NumberParameter.hpp" #include "simplnx/Parameters/StringParameter.hpp" +#include "ITKImageProcessing/Common/ProjectionUtils.hpp" + #include using namespace nx::core; @@ -21,18 +20,6 @@ namespace cxITKMinimumProjectionImageFilter using ArrayOptionsType = ITK::ScalarPixelIdTypeList; // VectorPixelIDTypeList; -template -using FilterOutputTypeUI8 = uint8; - -template -using FilterOutputTypeI16 = int16; - -template -using FilterOutputTypeUI16 = uint16; - -template -using FilterOutputTypeF32 = float32; - struct ITKMinimumProjectionImageFilterFunctor { uint32 projectionDimension = 0u; @@ -124,77 +111,11 @@ IFilter::PreflightResult ITKMinimumProjectionImageFilter::preflightImpl(const Da auto selectedInputArray = filterArgs.value(k_InputImageDataPath_Key); auto outputArrayName = filterArgs.value(k_OutputImageArrayName_Key); auto projectionDimension = filterArgs.value(k_ProjectionDimension_Key); - auto preformInPlace = filterArgs.value(k_RemoveOriginalGeometry_Key); + auto performInPlace = filterArgs.value(k_RemoveOriginalGeometry_Key); auto outputGeomName = filterArgs.value(k_OutputImageGeomName_Key); - DataPath outputArrayPath = selectedInputArray.replaceName(outputArrayName); - - Result resultOutputActions; - // The input geometry must be preserved, so we will just copy the needed array into newly created output geometry - if(!preformInPlace) - { - DataPath outputGeomPath({outputGeomName}); - - const auto& originalGeometry = dataStructure.getDataRefAs(imageGeomPath); - - // Make copy of input geometry - resultOutputActions.value().appendAction(std::make_unique( - outputGeomPath, originalGeometry.getDimensions().toContainer(), originalGeometry.getOrigin().toContainer(), - originalGeometry.getSpacing().toContainer(), originalGeometry.getCellDataPath().getTargetName())); - - outputArrayPath = outputGeomPath.createChildPath(originalGeometry.getCellDataPath().getTargetName()).createChildPath(outputArrayName); - } - - Result helperOutputActions = {}; - DataType type = dataStructure.getDataAs(selectedInputArray)->getDataType(); - switch(type) - { - case DataType::uint8: { - helperOutputActions = - ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); - break; - } - case DataType::int16: { - helperOutputActions = - ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); - break; - } - case DataType::uint16: { - helperOutputActions = - ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); - break; - } - case DataType::float32: { - helperOutputActions = - ITK::DataCheck(dataStructure, selectedInputArray, imageGeomPath, outputArrayPath); - break; - } - case DataType::int8: - [[fallthrough]]; - case DataType::int32: - [[fallthrough]]; - case DataType::uint32: - [[fallthrough]]; - case DataType::int64: - [[fallthrough]]; - case DataType::uint64: { - [[fallthrough]]; - } - case DataType::float64: { - [[fallthrough]]; - } - case DataType::boolean: { - return MakePreflightErrorResult(-76610, fmt::format("Input {} type is not currently supported. Please reach out to devs if you have a use case.", DataTypeToString(type))); - } - } - if(helperOutputActions.invalid()) - { - return {std::move(helperOutputActions)}; - } - - // Consolidate actions - resultOutputActions.value().actions.insert(resultOutputActions.value().actions.end(), helperOutputActions.value().actions.begin(), helperOutputActions.value().actions.end()); - return {std::move(resultOutputActions)}; + return ProjectionUtilities::RunITKProjectionDataCheck(dataStructure, selectedInputArray, imageGeomPath, outputGeomName, performInPlace, + outputArrayName); } //------------------------------------------------------------------------------ @@ -204,79 +125,13 @@ Result<> ITKMinimumProjectionImageFilter::executeImpl(DataStructure& dataStructu auto imageGeomPath = filterArgs.value(k_InputImageGeomPath_Key); auto selectedInputArray = filterArgs.value(k_InputImageDataPath_Key); auto outputArrayName = filterArgs.value(k_OutputImageArrayName_Key); - DataPath outputArrayPath = selectedInputArray.replaceName(outputArrayName); - - auto preformInPlace = filterArgs.value(k_RemoveOriginalGeometry_Key); - - if(!preformInPlace) - { - const auto& originalGeometry = dataStructure.getDataRefAs(imageGeomPath); - - imageGeomPath = DataPath({filterArgs.value(k_OutputImageGeomName_Key)}); - outputArrayPath = imageGeomPath.createChildPath(originalGeometry.getCellDataPath().getTargetName()).createChildPath(outputArrayName); - } - + auto outputImageGeomName = filterArgs.value(k_OutputImageGeomName_Key); + auto performInPlace = filterArgs.value(k_RemoveOriginalGeometry_Key); auto projectionDimension = filterArgs.value(k_ProjectionDimension_Key); const cxITKMinimumProjectionImageFilter::ITKMinimumProjectionImageFilterFunctor itkFunctor = {projectionDimension}; - Result<> result = {}; - DataType type = dataStructure.getDataAs(selectedInputArray)->getDataType(); - switch(type) - { - case DataType::uint8: { - result = ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, - outputArrayPath, itkFunctor, shouldCancel); - break; - } - case DataType::int16: { - result = ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, - outputArrayPath, itkFunctor, shouldCancel); - break; - } - case DataType::uint16: { - result = ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, - outputArrayPath, itkFunctor, shouldCancel); - break; - } - case DataType::float32: { - result = ITK::Execute(dataStructure, selectedInputArray, imageGeomPath, - outputArrayPath, itkFunctor, shouldCancel); - break; - } - case DataType::int8: - [[fallthrough]]; - case DataType::int32: - [[fallthrough]]; - case DataType::uint32: - [[fallthrough]]; - case DataType::int64: - [[fallthrough]]; - case DataType::uint64: { - [[fallthrough]]; - } - case DataType::float64: { - [[fallthrough]]; - } - case DataType::boolean: { - return MakeErrorResult(-76601, fmt::format("Input {} type is not currently supported. Please reach out to devs if you have a use case.", DataTypeToString(type))); - } - } - if(result.invalid()) - { - return result; - } - - auto& imageGeom = dataStructure.getDataRefAs(imageGeomPath); - auto iArrayTupleShape = dataStructure.getDataAs(outputArrayPath)->getTupleShape(); - - // Update the Image Geometry with the new dimensions - imageGeom.setDimensions({iArrayTupleShape[2], iArrayTupleShape[1], iArrayTupleShape[0]}); - - // Update the AttributeMatrix with the new tuple shape. THIS WILL ALSO CHANGE ANY OTHER DATA ARRAY THAT IS ALSO - // STORED IN THAT ATTRIBUTE MATRIX - dataStructure.getDataAs(outputArrayPath.getParent())->resizeTuples(iArrayTupleShape); - - return {}; + return ProjectionUtilities::RunITKProjectionExecute(dataStructure, selectedInputArray, imageGeomPath, shouldCancel, outputArrayName, + performInPlace, itkFunctor, outputImageGeomName); } } // namespace nx::core