From 76bcbe598b3c82b36e468941a62fd70f1751cc7c Mon Sep 17 00:00:00 2001 From: Michael Jackson Date: Fri, 26 Jul 2024 13:59:32 -0400 Subject: [PATCH 1/4] Intermediate commit Signed-off-by: Michael Jackson --- .../Common/ReadImageUtils.cpp | 18 +++++- .../Common/ReadImageUtils.hpp | 2 + .../Filters/ITKImageReaderFilter.cpp | 55 ++++++++++++++++++- .../Filters/ITKImageReaderFilter.hpp | 3 + .../Filters/ITKImportImageStackFilter.cpp | 23 +++++++- .../Filters/ITKImportImageStackFilter.hpp | 2 + .../Filters/Algorithms/ConvertData.cpp | 19 +++---- .../Filters/Algorithms/ConvertData.hpp | 1 + .../Parameters/GeneratedFileListParameter.cpp | 2 +- src/simplnx/Utilities/DataArrayUtilities.cpp | 22 ++++---- src/simplnx/Utilities/DataArrayUtilities.hpp | 2 +- 11 files changed, 121 insertions(+), 28 deletions(-) diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ReadImageUtils.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ReadImageUtils.cpp index cb1703b4bb..efd9cde112 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ReadImageUtils.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ReadImageUtils.cpp @@ -1,5 +1,10 @@ #include "ReadImageUtils.hpp" +#include "simplnx/Common/TypesUtility.hpp" +#include "simplnx/Filter/Actions/DeleteDataAction.hpp" + +using namespace nx::core; + namespace cxItkImageReaderFilter { @@ -74,8 +79,19 @@ Result ReadImagePreflight(const std::string& fileName, DataPath i actions.appendAction(std::make_unique(std::move(imageGeomPath), std::move(dims), origin.toContainer(), spacing.toContainer(), cellDataName)); - actions.appendAction(std::make_unique(*numericType, std::move(arrayDims), std::move(cDims), imageGeomPath.createChildPath(cellDataName).createChildPath(arrayName))); + if(imageReaderOptions.ChangeDataType) + { + DataPath tempPath = imageGeomPath.createChildPath(cellDataName).createChildPath("." + arrayName); + actions.appendAction(std::make_unique(ConvertNumericTypeToDataType(imageReaderOptions.ImageDataType), std::move(arrayDims), std::move(cDims), + imageGeomPath.createChildPath(cellDataName).createChildPath(arrayName))); + actions.appendAction(std::make_unique(*numericType, std::move(arrayDims), std::move(cDims), tempPath)); + actions.appendDeferredAction(std::make_unique(tempPath, DeleteDataAction::DeleteType::JustObject)); + } + else + { + actions.appendAction(std::make_unique(*numericType, std::move(arrayDims), std::move(cDims), imageGeomPath.createChildPath(cellDataName).createChildPath(arrayName))); + } } catch(const itk::ExceptionObject& err) { return MakeErrorResult(-55557, fmt::format("ITK exception was thrown while processing input file: {}", err.what())); diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ReadImageUtils.hpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ReadImageUtils.hpp index f9686c2282..b32f5b75fd 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ReadImageUtils.hpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ReadImageUtils.hpp @@ -174,6 +174,8 @@ struct ImageReaderOptions bool OverrideSpacing = false; FloatVec3 Origin; FloatVec3 Spacing; + bool ChangeDataType = false; + NumericType ImageDataType = NumericType::uint8; }; //------------------------------------------------------------------------------ diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImageReaderFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImageReaderFilter.cpp index 51606bd0a9..3a561803b5 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImageReaderFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImageReaderFilter.cpp @@ -1,26 +1,35 @@ #include "ITKImageReaderFilter.hpp" +#include "simplnx/Core/Application.hpp" #include "simplnx/DataStructure/DataPath.hpp" #include "simplnx/DataStructure/DataStore.hpp" #include "simplnx/DataStructure/Geometry/ImageGeom.hpp" #include "simplnx/Filter/Actions/CreateArrayAction.hpp" #include "simplnx/Filter/Actions/UpdateImageGeomAction.hpp" +#include "simplnx/Filter/FilterHandle.hpp" #include "simplnx/Parameters/ArrayCreationParameter.hpp" #include "simplnx/Parameters/BoolParameter.hpp" #include "simplnx/Parameters/DataGroupCreationParameter.hpp" #include "simplnx/Parameters/DataObjectNameParameter.hpp" #include "simplnx/Parameters/FileSystemPathParameter.hpp" +#include "simplnx/Utilities/SIMPLConversion.hpp" #include "ITKImageProcessing/Common/ReadImageUtils.hpp" #include -#include "simplnx/Utilities/SIMPLConversion.hpp" - namespace fs = std::filesystem; using namespace nx::core; +namespace +{ +const Uuid k_SimplnxCorePluginId = *Uuid::FromString("05cc618b-781f-4ac0-b9ac-43f26ce1854f"); +const Uuid k_ConvertDataArrayFilterId = *Uuid::FromString("6dc586cc-59fb-4ee8-90ff-2d3587da12f5"); + +const FilterHandle k_ConvertDataArrayFilterHandle(k_ConvertDataArrayFilterId, k_SimplnxCorePluginId); +} // namespace + namespace nx::core { //------------------------------------------------------------------------------ @@ -73,6 +82,11 @@ Parameters ITKImageReaderFilter::parameters() const params.insert(std::make_unique(k_Spacing_Key, "Spacing (Physical Units)", "Specifies the new spacing values in physical units.", std::vector{1, 1, 1}, std::vector{"X", "Y", "Z"})); + params.insertLinkableParameter(std::make_unique(k_ChangeDataType_Key, "Set Image Data Type", "Set the final created image data type.", false)); + params.insert(std::make_unique(k_ImageDataType_Key, "Output Data Type", "Numeric Type of data to create", NumericType::int32)); + + params.linkParameters(k_ChangeDataType_Key, k_ImageDataType_Key, true); + params.linkParameters(k_ChangeOrigin_Key, k_Origin_Key, std::make_any(true)); params.linkParameters(k_ChangeOrigin_Key, k_CenterOrigin_Key, std::make_any(true)); params.linkParameters(k_ChangeSpacing_Key, k_Spacing_Key, std::make_any(true)); @@ -109,6 +123,8 @@ IFilter::PreflightResult ITKImageReaderFilter::preflightImpl(const DataStructure auto shouldChangeSpacing = filterArgs.value(k_ChangeSpacing_Key); auto origin = filterArgs.value(k_Origin_Key); auto spacing = filterArgs.value(k_Spacing_Key); + auto pChangeDataType = filterArgs.value(k_ChangeDataType_Key); + auto numericType = filterArgs.value(k_ImageDataType_Key); std::string fileNameString = fileName.string(); @@ -119,6 +135,8 @@ IFilter::PreflightResult ITKImageReaderFilter::preflightImpl(const DataStructure imageReaderOptions.OriginAtCenterOfGeometry = shouldCenterOrigin; imageReaderOptions.Origin = FloatVec3(static_cast(origin[0]), static_cast(origin[1]), static_cast(origin[2])); imageReaderOptions.Spacing = FloatVec3(static_cast(spacing[0]), static_cast(spacing[1]), static_cast(spacing[2])); + imageReaderOptions.ChangeDataType = pChangeDataType; + imageReaderOptions.ImageDataType = numericType; Result result = cxItkImageReaderFilter::ReadImagePreflight(fileNameString, imageGeomPath, cellDataName, imageDataArrayName, imageReaderOptions); @@ -138,9 +156,14 @@ Result<> ITKImageReaderFilter::executeImpl(DataStructure& dataStructure, const A // auto shouldChangeSpacing = filterArgs.value(k_ChangeSpacing_Key); auto origin = filterArgs.value(k_Origin_Key); auto spacing = filterArgs.value(k_Spacing_Key); + auto pChangeDataType = filterArgs.value(k_ChangeDataType_Key); + auto numericType = filterArgs.value(k_ImageDataType_Key); DataPath imageDataArrayPath = imageGeometryPath.createChildPath(cellDataName).createChildPath(imageDataArrayName); - + if(pChangeDataType) + { + imageDataArrayPath = imageGeometryPath.createChildPath(cellDataName).createChildPath("." + imageDataArrayName); + } const IDataArray* inputArrayPtr = dataStructure.getDataAs(imageDataArrayPath); if(!inputArrayPtr->getDataFormat().empty()) { @@ -153,6 +176,32 @@ Result<> ITKImageReaderFilter::executeImpl(DataStructure& dataStructure, const A auto result = cxItkImageReaderFilter::ReadImageExecute(fileNameString, dataStructure, imageDataArrayPath, fileNameString); + // Convert the image into the final DataArray + if(pChangeDataType) + { + // First delete the final destination DataArray that is already created. + imageDataArrayPath = imageGeometryPath.createChildPath(cellDataName).createChildPath(imageDataArrayName); + dataStructure.removeData(imageDataArrayPath); + + // Construct the tempDataPath where the image data was read into + DataPath tempDataArrayPath = imageGeometryPath.createChildPath(cellDataName).createChildPath("." + imageDataArrayName); + // Run the "Convert Data Array" Filter to convert the data in the temp path into the final array at imageDataPath + auto* filterListPtr = Application::Instance()->getFilterList(); + auto convertImageGeomFilter = filterListPtr->createFilter(k_ConvertDataArrayFilterHandle); + Arguments args; + args.insertOrAssign("scalar_type_index", std::make_any(numericType)); + args.insertOrAssign("array_to_convert_path", std::make_any(tempDataArrayPath)); + args.insertOrAssign("converted_array_name", std::make_any(imageDataArrayName)); + args.insertOrAssign("delete_original_array", std::make_any(false)); + // This filter put in a deferred delete action for the temp array so we do not have to worry about deleting it. + // Execute the Convert Data Array filter + auto result2 = convertImageGeomFilter->execute(dataStructure, args).result; + if(result2.invalid()) + { + return result2; + } + } + return result; } diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImageReaderFilter.hpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImageReaderFilter.hpp index d15980d988..5588cc6ac7 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImageReaderFilter.hpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImageReaderFilter.hpp @@ -38,6 +38,9 @@ class ITKIMAGEPROCESSING_EXPORT ITKImageReaderFilter : public IFilter static inline constexpr StringLiteral k_ChangeSpacing_Key = "change_spacing"; static inline constexpr StringLiteral k_Spacing_Key = "spacing"; + static inline constexpr StringLiteral k_ChangeDataType_Key = "change_image_data_type"; + static inline constexpr StringLiteral k_ImageDataType_Key = "image_data_type_index"; + /** * @brief Reads SIMPL json and converts it simplnx Arguments. * @param json diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImportImageStackFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImportImageStackFilter.cpp index 3247b6b30e..1fce121fe2 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImportImageStackFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImportImageStackFilter.cpp @@ -337,6 +337,9 @@ Parameters ITKImportImageStackFilter::parameters() const params.insert(std::make_unique(k_Scaling_Key, "Scaling", "The scaling of the 3D volume. For example, 0.1 is one-tenth the original number of pixels. 2.0 is double the number of pixels.", 1.0)); + params.insertLinkableParameter(std::make_unique(k_ChangeDataType_Key, "Set Image Data Type", "Set the final created image data type.", false)); + params.insert(std::make_unique(k_ImageDataType_Key, "Output Data Type", "Numeric Type of data to create", NumericType::int32)); + params.insertSeparator(Parameters::Separator{"Input File List"}); params.insert( std::make_unique(k_InputFileListInfo_Key, "Input File List", "The list of 2D image files to be read in to a 3D volume", GeneratedFileListParameter::ValueType{})); @@ -348,6 +351,7 @@ Parameters ITKImportImageStackFilter::parameters() const params.linkParameters(k_ConvertToGrayScale_Key, k_ColorWeights_Key, true); params.linkParameters(k_ScaleImages_Key, k_Scaling_Key, true); + params.linkParameters(k_ChangeDataType_Key, k_ImageDataType_Key, true); return params; } @@ -374,6 +378,9 @@ IFilter::PreflightResult ITKImportImageStackFilter::preflightImpl(const DataStru auto pScaleImagesValue = filterArgs.value(k_ScaleImages_Key); auto pScalingValue = filterArgs.value(k_Scaling_Key); + auto pChangeDataType = filterArgs.value(k_ChangeDataType_Key); + auto numericType = filterArgs.value(k_ImageDataType_Key); + PreflightResult preflightResult; nx::core::Result resultOutputActions = {}; std::vector preflightUpdatedValues; @@ -403,6 +410,8 @@ IFilter::PreflightResult ITKImportImageStackFilter::preflightImpl(const DataStru imageReaderArgs.insertOrAssign(ITKImageReaderFilter::k_CellDataName_Key, std::make_any(cellDataName)); imageReaderArgs.insertOrAssign(ITKImageReaderFilter::k_ImageDataArrayPath_Key, std::make_any(pImageDataArrayNameValue)); imageReaderArgs.insertOrAssign(ITKImageReaderFilter::k_FileName_Key, std::make_any(files.at(0))); + imageReaderArgs.insertOrAssign(ITKImageReaderFilter::k_ChangeDataType_Key, std::make_any(pChangeDataType)); + imageReaderArgs.insertOrAssign(ITKImageReaderFilter::k_ImageDataType_Key, std::make_any(numericType)); const ITKImageReaderFilter imageReader; PreflightResult imageReaderResult = imageReader.preflight(dataStructure, imageReaderArgs, messageHandler, shouldCancel); @@ -453,7 +462,19 @@ IFilter::PreflightResult ITKImportImageStackFilter::preflightImpl(const DataStru nx::core::DataTypeToString(createArrayActionPtr->type()))); } - if(pConvertToGrayScaleValue) + if(pChangeDataType && !pConvertToGrayScaleValue && createArrayActionPtr->componentDims().at(0) != 1) + { + return MakePreflightErrorResult( + -23506, fmt::format("Changing the array type requires the input image data to be a scalar value OR the image data can be RGB but you must also select 'Convert to Grayscale'", + nx::core::DataTypeToString(createArrayActionPtr->type()))); + } + + if(pChangeDataType) + { + auto action = std::make_unique(ConvertNumericTypeToDataType(numericType), arrayDims, std::vector{1ULL}, imageDataPath); + resultOutputActions.value().appendAction(std::move(action)); + } + else if(pConvertToGrayScaleValue) { auto* filterListPtr = Application::Instance()->getFilterList(); if(!filterListPtr->containsPlugin(k_SimplnxCorePluginId)) diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImportImageStackFilter.hpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImportImageStackFilter.hpp index f6fd3553fb..2ec23a3f59 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImportImageStackFilter.hpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImportImageStackFilter.hpp @@ -35,6 +35,8 @@ class ITKIMAGEPROCESSING_EXPORT ITKImportImageStackFilter : public IFilter static inline constexpr StringLiteral k_ColorWeights_Key = "color_weights"; static inline constexpr StringLiteral k_ScaleImages_Key = "scale_images"; static inline constexpr StringLiteral k_Scaling_Key = "scaling"; + static inline constexpr StringLiteral k_ChangeDataType_Key = "change_image_data_type"; + static inline constexpr StringLiteral k_ImageDataType_Key = "image_data_type_index"; /** * @brief Reads SIMPL json and converts it simplnx Arguments. * @param json diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ConvertData.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ConvertData.cpp index c9bddeec00..d3899c002f 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ConvertData.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ConvertData.cpp @@ -8,12 +8,12 @@ using namespace nx::core; namespace Detail { -template +template class ConvertDataAlg { public: - using InputStoreType = AbstractDataStore; - using OutputStoreType = AbstractDataStore; + using InputStoreType = AbstractDataStore; + using OutputStoreType = AbstractDataStore; ConvertDataAlg(InputStoreType& inputStore, OutputStoreType& outputStore) : m_InputStore(inputStore) @@ -23,31 +23,30 @@ class ConvertDataAlg void convert(size_t start, size_t end) const { - // std::cout << "\tConvertDataAlg: " << start << " to " << end << std::endl; for(size_t v = start; v < end; ++v) { - // std::cout << "\tConvertDataAlg: index " << v << std::endl; - - if constexpr(std::is_same::value) + if constexpr(std::is_same::value) { // inputArray and destination arrays have the same type m_OutputStore.setValue(v, m_InputStore.getValue(v)); } - else if constexpr(std::is_same::value) + else if constexpr(std::is_same::value) { // inputArray array is a boolean array m_OutputStore.setValue(v, (m_InputStore.getValue(v) ? 1 : 0)); } - else if constexpr(std::is_same::value) + else if constexpr(std::is_same::value) { // Destination array is a boolean array m_OutputStore.setValue(v, (m_InputStore.getValue(v) != 0)); } + else { // All other cases - m_OutputStore.setValue(v, static_cast(m_InputStore.getValue(v))); + OutputType sourceValue = static_cast(m_InputStore.getValue(v)); + m_OutputStore.setValue(v, sourceValue); } } } diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ConvertData.hpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ConvertData.hpp index 03b89f891b..a345575f11 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ConvertData.hpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ConvertData.hpp @@ -14,6 +14,7 @@ struct SIMPLNXCORE_EXPORT ConvertDataInputValues DataType ScalarType; DataPath SelectedArrayPath; DataPath OutputArrayName; + bool RescaleValues = false; }; /** diff --git a/src/simplnx/Parameters/GeneratedFileListParameter.cpp b/src/simplnx/Parameters/GeneratedFileListParameter.cpp index dad5c625be..d46fd877aa 100644 --- a/src/simplnx/Parameters/GeneratedFileListParameter.cpp +++ b/src/simplnx/Parameters/GeneratedFileListParameter.cpp @@ -164,7 +164,7 @@ Result<> GeneratedFileListParameter::validate(const std::any& valueRef) const { if(!fs::exists(currentFilePath)) { - errors.push_back({-4003, fmt::format("FILE DOES NOT EXIST: '{}'", currentFilePath)}); + errors.push_back({-4003, fmt::format("{}FILE DOES NOT EXIST: '{}'", prefix, currentFilePath)}); } } diff --git a/src/simplnx/Utilities/DataArrayUtilities.cpp b/src/simplnx/Utilities/DataArrayUtilities.cpp index cb60da8782..331a2f9569 100644 --- a/src/simplnx/Utilities/DataArrayUtilities.cpp +++ b/src/simplnx/Utilities/DataArrayUtilities.cpp @@ -302,27 +302,27 @@ bool ConvertIDataArray(const std::shared_ptr& dataArray, const std:: switch(dataType) { case DataType::int8: - return ConvertDataArray(std::dynamic_pointer_cast>(dataArray), dataFormat); + return ConvertDataArrayDataStore(std::dynamic_pointer_cast>(dataArray), dataFormat); case DataType::int16: - return ConvertDataArray(std::dynamic_pointer_cast>(dataArray), dataFormat); + return ConvertDataArrayDataStore(std::dynamic_pointer_cast>(dataArray), dataFormat); case DataType::int32: - return ConvertDataArray(std::dynamic_pointer_cast>(dataArray), dataFormat); + return ConvertDataArrayDataStore(std::dynamic_pointer_cast>(dataArray), dataFormat); case DataType::int64: - return ConvertDataArray(std::dynamic_pointer_cast>(dataArray), dataFormat); + return ConvertDataArrayDataStore(std::dynamic_pointer_cast>(dataArray), dataFormat); case DataType::uint8: - return ConvertDataArray(std::dynamic_pointer_cast>(dataArray), dataFormat); + return ConvertDataArrayDataStore(std::dynamic_pointer_cast>(dataArray), dataFormat); case DataType::uint16: - return ConvertDataArray(std::dynamic_pointer_cast>(dataArray), dataFormat); + return ConvertDataArrayDataStore(std::dynamic_pointer_cast>(dataArray), dataFormat); case DataType::uint32: - return ConvertDataArray(std::dynamic_pointer_cast>(dataArray), dataFormat); + return ConvertDataArrayDataStore(std::dynamic_pointer_cast>(dataArray), dataFormat); case DataType::uint64: - return ConvertDataArray(std::dynamic_pointer_cast>(dataArray), dataFormat); + return ConvertDataArrayDataStore(std::dynamic_pointer_cast>(dataArray), dataFormat); case DataType::boolean: - return ConvertDataArray(std::dynamic_pointer_cast>(dataArray), dataFormat); + return ConvertDataArrayDataStore(std::dynamic_pointer_cast>(dataArray), dataFormat); case DataType::float32: - return ConvertDataArray(std::dynamic_pointer_cast>(dataArray), dataFormat); + return ConvertDataArrayDataStore(std::dynamic_pointer_cast>(dataArray), dataFormat); case DataType::float64: - return ConvertDataArray(std::dynamic_pointer_cast>(dataArray), dataFormat); + return ConvertDataArrayDataStore(std::dynamic_pointer_cast>(dataArray), dataFormat); default: return false; } diff --git a/src/simplnx/Utilities/DataArrayUtilities.hpp b/src/simplnx/Utilities/DataArrayUtilities.hpp index 9bf725454d..4765686a52 100644 --- a/src/simplnx/Utilities/DataArrayUtilities.hpp +++ b/src/simplnx/Utilities/DataArrayUtilities.hpp @@ -488,7 +488,7 @@ std::shared_ptr> ConvertDataStore(const AbstractDataStore -bool ConvertDataArray(const std::shared_ptr> dataArray, const std::string& dataFormat) +bool ConvertDataArrayDataStore(const std::shared_ptr> dataArray, const std::string& dataFormat) { if(dataArray == nullptr) { From ae215f5ec5f538d7f48bcb3125cb3b4cb57924c5 Mon Sep 17 00:00:00 2001 From: nyoungbq Date: Wed, 31 Jul 2024 16:25:50 -0400 Subject: [PATCH 2/4] Functioning ITK Image Reader multi option read in (Image Stack to come) --- .../Common/ITKArrayHelper.hpp | 61 ++++++++++++++++-- .../Common/ReadImageUtils.cpp | 7 +-- .../Common/ReadImageUtils.hpp | 19 +++++- .../Filters/ITKImageReaderFilter.cpp | 63 +++++++------------ .../Filters/ITKImportImageStackFilter.cpp | 11 ++-- 5 files changed, 107 insertions(+), 54 deletions(-) diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ITKArrayHelper.hpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ITKArrayHelper.hpp index 796154cb2e..e3baba6a5f 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ITKArrayHelper.hpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ITKArrayHelper.hpp @@ -27,9 +27,7 @@ #include #include -namespace nx::core -{ -namespace ITK +namespace nx::core::ITK { struct ImageGeomData { @@ -346,6 +344,62 @@ DataStore> ConvertImageToDataStore(itk::Image +concept NotBoolT = !std::is_same_v; + +template +Result<> ConvertImageToDataStore(AbstractDataStore& dataStore, itk::Image& image) +{ + using ImageType = itk::Image; + using T = UnderlyingType_t; + typename ImageType::SizeType imageSize = image.GetLargestPossibleRegion().GetSize(); + std::vector tDims(imageSize.rbegin(), imageSize.rend()); + std::vector cDims = GetComponentDimensions(); + if constexpr(Dimension == 2) + { + tDims.insert(tDims.begin(), 1); + } + typename ImageType::PixelContainer* pixelContainer = image.GetPixelContainer(); + + // ITK use the global new allocator + auto* rawBufferPtr = reinterpret_cast(pixelContainer->GetBufferPointer()); + pixelContainer->ContainerManageMemoryOff(); + if constexpr(std::is_same_v) + { + std::unique_ptr newData(rawBufferPtr); + dataStore = DataStore(std::move(newData), std::move(tDims), std::move(cDims)); + } + else + { + std::unique_ptr newData = std::make_unique(sizeof(NewStoreT) * pixelContainer->Size()); + if constexpr(!std::is_signed_v && !std::is_signed_v) // bool would slip through, but it is disallowed + { + constexpr auto destMaxV = static_cast(std::numeric_limits::max()); + constexpr auto originMaxV = std::numeric_limits::max(); + std::transform(rawBufferPtr, rawBufferPtr + pixelContainer->Size(), newData.get(), [](auto value) { + float64 ratio = static_cast(value) / originMaxV; + return static_cast(ratio * destMaxV); + }); + } + + dataStore = DataStore(std::move(newData), std::move(tDims), std::move(cDims)); + } + + return {}; +} + +struct ConvertImageToDatastoreFunctor +{ + template + Result<> operator()(DataStructure& dataStructure, const DataPath& arrayPath, Args&&... args) + { + auto& dataArray = dataStructure.getDataRefAs>(arrayPath); + auto& dataStore = dataArray.template getIDataStoreRefAs>(); + + return ConvertImageToDataStore(dataStore, std::forward(args)...); + } +}; + // Could replace with class type non-type template parameters in C++20 template @@ -827,5 +881,4 @@ Result> Execute(DataStr return MakeErrorResult(-222, exception.GetDescription()); } } -} // namespace ITK } // namespace nx::core diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ReadImageUtils.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ReadImageUtils.cpp index efd9cde112..f583efb6dd 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ReadImageUtils.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ReadImageUtils.cpp @@ -82,11 +82,8 @@ Result ReadImagePreflight(const std::string& fileName, DataPath i if(imageReaderOptions.ChangeDataType) { - DataPath tempPath = imageGeomPath.createChildPath(cellDataName).createChildPath("." + arrayName); - actions.appendAction(std::make_unique(ConvertNumericTypeToDataType(imageReaderOptions.ImageDataType), std::move(arrayDims), std::move(cDims), - imageGeomPath.createChildPath(cellDataName).createChildPath(arrayName))); - actions.appendAction(std::make_unique(*numericType, std::move(arrayDims), std::move(cDims), tempPath)); - actions.appendDeferredAction(std::make_unique(tempPath, DeleteDataAction::DeleteType::JustObject)); + actions.appendAction( + std::make_unique(imageReaderOptions.ImageDataType, std::move(arrayDims), std::move(cDims), imageGeomPath.createChildPath(cellDataName).createChildPath(arrayName))); } else { diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ReadImageUtils.hpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ReadImageUtils.hpp index b32f5b75fd..e69a5fc827 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ReadImageUtils.hpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ReadImageUtils.hpp @@ -2,6 +2,7 @@ #include "simplnx/Common/Result.hpp" #include "simplnx/Common/Types.hpp" +#include "simplnx/Utilities/FilterUtilities.hpp" #include "simplnx/Filter/Actions/CreateImageGeometryAction.hpp" #include "ITKImageProcessing/Common/ITKArrayHelper.hpp" @@ -49,6 +50,22 @@ struct ReadImageIntoArrayFunctor return {}; } + + //------------------------------------------------------------------------------ + template + Result<> operator()(DataStructure& dataStructure, const std::string& filePath, const DataPath& arrayPath, const DataType& dataType) const + { + using ImageType = itk::Image; + using ReaderType = itk::ImageFileReader; + + typename ReaderType::Pointer reader = ReaderType::New(); + reader->SetFileName(filePath); + + reader->Update(); + typename ImageType::Pointer outputImage = reader->GetOutput(); + + return ExecuteNeighborFunction(ITK::ConvertImageToDatastoreFunctor{}, dataType, dataStructure, arrayPath, *outputImage);; + } }; //------------------------------------------------------------------------------ @@ -175,7 +192,7 @@ struct ImageReaderOptions FloatVec3 Origin; FloatVec3 Spacing; bool ChangeDataType = false; - NumericType ImageDataType = NumericType::uint8; + DataType ImageDataType = DataType::uint8; }; //------------------------------------------------------------------------------ diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImageReaderFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImageReaderFilter.cpp index 3a561803b5..b8cf05f53e 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImageReaderFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImageReaderFilter.cpp @@ -7,7 +7,6 @@ #include "simplnx/Filter/Actions/CreateArrayAction.hpp" #include "simplnx/Filter/Actions/UpdateImageGeomAction.hpp" #include "simplnx/Filter/FilterHandle.hpp" -#include "simplnx/Parameters/ArrayCreationParameter.hpp" #include "simplnx/Parameters/BoolParameter.hpp" #include "simplnx/Parameters/DataGroupCreationParameter.hpp" #include "simplnx/Parameters/DataObjectNameParameter.hpp" @@ -24,10 +23,19 @@ using namespace nx::core; namespace { -const Uuid k_SimplnxCorePluginId = *Uuid::FromString("05cc618b-781f-4ac0-b9ac-43f26ce1854f"); -const Uuid k_ConvertDataArrayFilterId = *Uuid::FromString("6dc586cc-59fb-4ee8-90ff-2d3587da12f5"); - -const FilterHandle k_ConvertDataArrayFilterHandle(k_ConvertDataArrayFilterId, k_SimplnxCorePluginId); +DataType ConvertChoiceToDataType(ChoicesParameter::ValueType choice) +{ + switch(choice) + { + case 0: + return DataType::uint8; + case 1: + return DataType::uint16; + case 2: + return DataType::uint32; + } + return DataType::uint8; +} } // namespace namespace nx::core @@ -83,7 +91,8 @@ Parameters ITKImageReaderFilter::parameters() const std::vector{"X", "Y", "Z"})); params.insertLinkableParameter(std::make_unique(k_ChangeDataType_Key, "Set Image Data Type", "Set the final created image data type.", false)); - params.insert(std::make_unique(k_ImageDataType_Key, "Output Data Type", "Numeric Type of data to create", NumericType::int32)); + params.insert(std::make_unique(k_ImageDataType_Key, "Output Data Type", "Numeric Type of data to create", 0ULL, + ChoicesParameter::Choices{"uint8", "uint16", "uint32"})); // Sequence Dependent DO NOT REORDER params.linkParameters(k_ChangeDataType_Key, k_ImageDataType_Key, true); @@ -124,7 +133,7 @@ IFilter::PreflightResult ITKImageReaderFilter::preflightImpl(const DataStructure auto origin = filterArgs.value(k_Origin_Key); auto spacing = filterArgs.value(k_Spacing_Key); auto pChangeDataType = filterArgs.value(k_ChangeDataType_Key); - auto numericType = filterArgs.value(k_ImageDataType_Key); + auto choiceType = filterArgs.value(k_ImageDataType_Key); std::string fileNameString = fileName.string(); @@ -136,7 +145,7 @@ IFilter::PreflightResult ITKImageReaderFilter::preflightImpl(const DataStructure imageReaderOptions.Origin = FloatVec3(static_cast(origin[0]), static_cast(origin[1]), static_cast(origin[2])); imageReaderOptions.Spacing = FloatVec3(static_cast(spacing[0]), static_cast(spacing[1]), static_cast(spacing[2])); imageReaderOptions.ChangeDataType = pChangeDataType; - imageReaderOptions.ImageDataType = numericType; + imageReaderOptions.ImageDataType = ConvertChoiceToDataType(choiceType); Result result = cxItkImageReaderFilter::ReadImagePreflight(fileNameString, imageGeomPath, cellDataName, imageDataArrayName, imageReaderOptions); @@ -157,13 +166,9 @@ Result<> ITKImageReaderFilter::executeImpl(DataStructure& dataStructure, const A auto origin = filterArgs.value(k_Origin_Key); auto spacing = filterArgs.value(k_Spacing_Key); auto pChangeDataType = filterArgs.value(k_ChangeDataType_Key); - auto numericType = filterArgs.value(k_ImageDataType_Key); + auto newDataType = ConvertChoiceToDataType(filterArgs.value(k_ImageDataType_Key)); DataPath imageDataArrayPath = imageGeometryPath.createChildPath(cellDataName).createChildPath(imageDataArrayName); - if(pChangeDataType) - { - imageDataArrayPath = imageGeometryPath.createChildPath(cellDataName).createChildPath("." + imageDataArrayName); - } const IDataArray* inputArrayPtr = dataStructure.getDataAs(imageDataArrayPath); if(!inputArrayPtr->getDataFormat().empty()) { @@ -172,34 +177,14 @@ Result<> ITKImageReaderFilter::executeImpl(DataStructure& dataStructure, const A std::string fileNameString = fileName.string(); - ImageGeom& imageGeom = dataStructure.getDataRefAs(imageGeometryPath); - - auto result = cxItkImageReaderFilter::ReadImageExecute(fileNameString, dataStructure, imageDataArrayPath, fileNameString); - - // Convert the image into the final DataArray + Result<> result = {}; if(pChangeDataType) { - // First delete the final destination DataArray that is already created. - imageDataArrayPath = imageGeometryPath.createChildPath(cellDataName).createChildPath(imageDataArrayName); - dataStructure.removeData(imageDataArrayPath); - - // Construct the tempDataPath where the image data was read into - DataPath tempDataArrayPath = imageGeometryPath.createChildPath(cellDataName).createChildPath("." + imageDataArrayName); - // Run the "Convert Data Array" Filter to convert the data in the temp path into the final array at imageDataPath - auto* filterListPtr = Application::Instance()->getFilterList(); - auto convertImageGeomFilter = filterListPtr->createFilter(k_ConvertDataArrayFilterHandle); - Arguments args; - args.insertOrAssign("scalar_type_index", std::make_any(numericType)); - args.insertOrAssign("array_to_convert_path", std::make_any(tempDataArrayPath)); - args.insertOrAssign("converted_array_name", std::make_any(imageDataArrayName)); - args.insertOrAssign("delete_original_array", std::make_any(false)); - // This filter put in a deferred delete action for the temp array so we do not have to worry about deleting it. - // Execute the Convert Data Array filter - auto result2 = convertImageGeomFilter->execute(dataStructure, args).result; - if(result2.invalid()) - { - return result2; - } + result = cxItkImageReaderFilter::ReadImageExecute(fileNameString, dataStructure, fileNameString, imageDataArrayPath, newDataType); + } + else + { + result = cxItkImageReaderFilter::ReadImageExecute(fileNameString, dataStructure, imageDataArrayPath, fileNameString); } return result; diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImportImageStackFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImportImageStackFilter.cpp index 1fce121fe2..3a73343cb2 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImportImageStackFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImportImageStackFilter.cpp @@ -338,7 +338,8 @@ Parameters ITKImportImageStackFilter::parameters() const "The scaling of the 3D volume. For example, 0.1 is one-tenth the original number of pixels. 2.0 is double the number of pixels.", 1.0)); params.insertLinkableParameter(std::make_unique(k_ChangeDataType_Key, "Set Image Data Type", "Set the final created image data type.", false)); - params.insert(std::make_unique(k_ImageDataType_Key, "Output Data Type", "Numeric Type of data to create", NumericType::int32)); + params.insert(std::make_unique(k_ImageDataType_Key, "Output Data Type", "Numeric Type of data to create", 0ULL, + ChoicesParameter::Choices{"uint8", "uint16", "uint32"})); // Sequence Dependent DO NOT REORDER params.insertSeparator(Parameters::Separator{"Input File List"}); params.insert( @@ -379,7 +380,7 @@ IFilter::PreflightResult ITKImportImageStackFilter::preflightImpl(const DataStru auto pScalingValue = filterArgs.value(k_Scaling_Key); auto pChangeDataType = filterArgs.value(k_ChangeDataType_Key); - auto numericType = filterArgs.value(k_ImageDataType_Key); + auto numericType = filterArgs.value(k_ImageDataType_Key); PreflightResult preflightResult; nx::core::Result resultOutputActions = {}; @@ -411,7 +412,7 @@ IFilter::PreflightResult ITKImportImageStackFilter::preflightImpl(const DataStru imageReaderArgs.insertOrAssign(ITKImageReaderFilter::k_ImageDataArrayPath_Key, std::make_any(pImageDataArrayNameValue)); imageReaderArgs.insertOrAssign(ITKImageReaderFilter::k_FileName_Key, std::make_any(files.at(0))); imageReaderArgs.insertOrAssign(ITKImageReaderFilter::k_ChangeDataType_Key, std::make_any(pChangeDataType)); - imageReaderArgs.insertOrAssign(ITKImageReaderFilter::k_ImageDataType_Key, std::make_any(numericType)); + imageReaderArgs.insertOrAssign(ITKImageReaderFilter::k_ImageDataType_Key, std::make_any(numericType)); const ITKImageReaderFilter imageReader; PreflightResult imageReaderResult = imageReader.preflight(dataStructure, imageReaderArgs, messageHandler, shouldCancel); @@ -471,8 +472,8 @@ IFilter::PreflightResult ITKImportImageStackFilter::preflightImpl(const DataStru if(pChangeDataType) { - auto action = std::make_unique(ConvertNumericTypeToDataType(numericType), arrayDims, std::vector{1ULL}, imageDataPath); - resultOutputActions.value().appendAction(std::move(action)); +// auto action = std::make_unique(ConvertNumericTypeToDataType(numericType), arrayDims, std::vector{1ULL}, imageDataPath); +// resultOutputActions.value().appendAction(std::move(action)); } else if(pConvertToGrayScaleValue) { From 66bc5cb36907b86b881ef28ade6bb2c8ae372046 Mon Sep 17 00:00:00 2001 From: nyoungbq Date: Fri, 2 Aug 2024 18:20:16 -0400 Subject: [PATCH 3/4] Fix conversion on Stack reader and Image reader --- .../Common/ITKArrayHelper.cpp | 14 ++ .../Common/ITKArrayHelper.hpp | 55 +++++-- .../Common/ReadImageUtils.cpp | 2 +- .../Common/ReadImageUtils.hpp | 11 +- .../Filters/ITKImageReaderFilter.cpp | 21 +-- .../Filters/ITKImportImageStackFilter.cpp | 150 +++++++++++------- 6 files changed, 161 insertions(+), 92 deletions(-) diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ITKArrayHelper.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ITKArrayHelper.cpp index 707fe34b05..d43ef391f3 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ITKArrayHelper.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ITKArrayHelper.cpp @@ -6,6 +6,20 @@ using namespace nx::core; +DataType ITK::detail::ConvertChoiceToDataType(types::usize choice) +{ + switch(choice) + { + case 0: + return DataType::uint8; + case 1: + return DataType::uint16; + case 2: + return DataType::uint32; + } + return DataType::uint8; +} + bool ITK::DoTuplesMatch(const IDataStore& dataStore, const ImageGeom& imageGeom) { return imageGeom.getNumberOfCells() == dataStore.getNumberOfTuples(); diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ITKArrayHelper.hpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ITKArrayHelper.hpp index e3baba6a5f..d98190317e 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ITKArrayHelper.hpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ITKArrayHelper.hpp @@ -29,6 +29,45 @@ namespace nx::core::ITK { +namespace detail +{ +template +struct TypeConversionValidateFunctor +{ + template + bool operator()() + { + if constexpr(std::is_same_v) + { + // This won't actually fail, but it prevents an unnecessary copy + return false; + } + if constexpr(std::is_signed_v || std::is_signed_v) + { + return false; + } + if constexpr(std::is_same_v || std::is_same_v) + { + return false; + } + + // Currently only works on uint8, uint16, or uint32 + return true; + } +}; + +struct PreflightTypeConversionValidateFunctor +{ + template + bool operator()(const DataType& destType) + { + return ExecuteNeighborFunction(TypeConversionValidateFunctor{}, destType); + } +}; + +DataType ConvertChoiceToDataType(usize choice); +} // namespace detail + struct ImageGeomData { SizeVec3 dims{}; @@ -344,11 +383,11 @@ DataStore> ConvertImageToDataStore(itk::Image +template concept NotBoolT = !std::is_same_v; template -Result<> ConvertImageToDataStore(AbstractDataStore& dataStore, itk::Image& image) +Result<> ConvertImageToDataStore(DataStore& dataStore, itk::Image& image) { using ImageType = itk::Image; using T = UnderlyingType_t; @@ -366,23 +405,19 @@ Result<> ConvertImageToDataStore(AbstractDataStore& dataStore, itk::I pixelContainer->ContainerManageMemoryOff(); if constexpr(std::is_same_v) { - std::unique_ptr newData(rawBufferPtr); - dataStore = DataStore(std::move(newData), std::move(tDims), std::move(cDims)); + std::copy(rawBufferPtr, rawBufferPtr + pixelContainer->Size(), dataStore.data()); } else { - std::unique_ptr newData = std::make_unique(sizeof(NewStoreT) * pixelContainer->Size()); if constexpr(!std::is_signed_v && !std::is_signed_v) // bool would slip through, but it is disallowed { constexpr auto destMaxV = static_cast(std::numeric_limits::max()); constexpr auto originMaxV = std::numeric_limits::max(); - std::transform(rawBufferPtr, rawBufferPtr + pixelContainer->Size(), newData.get(), [](auto value) { + std::transform(rawBufferPtr, rawBufferPtr + pixelContainer->Size(), dataStore.data(), [](auto value) { float64 ratio = static_cast(value) / originMaxV; return static_cast(ratio * destMaxV); }); } - - dataStore = DataStore(std::move(newData), std::move(tDims), std::move(cDims)); } return {}; @@ -394,7 +429,7 @@ struct ConvertImageToDatastoreFunctor Result<> operator()(DataStructure& dataStructure, const DataPath& arrayPath, Args&&... args) { auto& dataArray = dataStructure.getDataRefAs>(arrayPath); - auto& dataStore = dataArray.template getIDataStoreRefAs>(); + DataStore& dataStore = dataArray.template getIDataStoreRefAs>(); return ConvertImageToDataStore(dataStore, std::forward(args)...); } @@ -881,4 +916,4 @@ Result> Execute(DataStr return MakeErrorResult(-222, exception.GetDescription()); } } -} // namespace nx::core +} // namespace nx::core::ITK diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ReadImageUtils.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ReadImageUtils.cpp index f583efb6dd..ad673618e5 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ReadImageUtils.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ReadImageUtils.cpp @@ -80,7 +80,7 @@ Result ReadImagePreflight(const std::string& fileName, DataPath i actions.appendAction(std::make_unique(std::move(imageGeomPath), std::move(dims), origin.toContainer(), spacing.toContainer(), cellDataName)); - if(imageReaderOptions.ChangeDataType) + if(imageReaderOptions.ChangeDataType && ExecuteNeighborFunction(ITK::detail::PreflightTypeConversionValidateFunctor{}, *numericType, imageReaderOptions.ImageDataType)) { actions.appendAction( std::make_unique(imageReaderOptions.ImageDataType, std::move(arrayDims), std::move(cDims), imageGeomPath.createChildPath(cellDataName).createChildPath(arrayName))); diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ReadImageUtils.hpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ReadImageUtils.hpp index e69a5fc827..15c5b83839 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ReadImageUtils.hpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Common/ReadImageUtils.hpp @@ -2,8 +2,8 @@ #include "simplnx/Common/Result.hpp" #include "simplnx/Common/Types.hpp" -#include "simplnx/Utilities/FilterUtilities.hpp" #include "simplnx/Filter/Actions/CreateImageGeometryAction.hpp" +#include "simplnx/Utilities/FilterUtilities.hpp" #include "ITKImageProcessing/Common/ITKArrayHelper.hpp" @@ -58,13 +58,20 @@ struct ReadImageIntoArrayFunctor using ImageType = itk::Image; using ReaderType = itk::ImageFileReader; + if(!ExecuteNeighborFunction(ITK::detail::TypeConversionValidateFunctor::ValueType>{}, dataType)) + { + // Not valid for conversion executing overload + return operator()(dataStructure, arrayPath, filePath); + } + typename ReaderType::Pointer reader = ReaderType::New(); reader->SetFileName(filePath); reader->Update(); typename ImageType::Pointer outputImage = reader->GetOutput(); - return ExecuteNeighborFunction(ITK::ConvertImageToDatastoreFunctor{}, dataType, dataStructure, arrayPath, *outputImage);; + return ExecuteNeighborFunction(ITK::ConvertImageToDatastoreFunctor{}, dataType, dataStructure, arrayPath, *outputImage); + ; } }; diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImageReaderFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImageReaderFilter.cpp index b8cf05f53e..f5ca3c511c 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImageReaderFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImageReaderFilter.cpp @@ -21,23 +21,6 @@ namespace fs = std::filesystem; using namespace nx::core; -namespace -{ -DataType ConvertChoiceToDataType(ChoicesParameter::ValueType choice) -{ - switch(choice) - { - case 0: - return DataType::uint8; - case 1: - return DataType::uint16; - case 2: - return DataType::uint32; - } - return DataType::uint8; -} -} // namespace - namespace nx::core { //------------------------------------------------------------------------------ @@ -145,7 +128,7 @@ IFilter::PreflightResult ITKImageReaderFilter::preflightImpl(const DataStructure imageReaderOptions.Origin = FloatVec3(static_cast(origin[0]), static_cast(origin[1]), static_cast(origin[2])); imageReaderOptions.Spacing = FloatVec3(static_cast(spacing[0]), static_cast(spacing[1]), static_cast(spacing[2])); imageReaderOptions.ChangeDataType = pChangeDataType; - imageReaderOptions.ImageDataType = ConvertChoiceToDataType(choiceType); + imageReaderOptions.ImageDataType = ITK::detail::ConvertChoiceToDataType(choiceType); Result result = cxItkImageReaderFilter::ReadImagePreflight(fileNameString, imageGeomPath, cellDataName, imageDataArrayName, imageReaderOptions); @@ -166,7 +149,7 @@ Result<> ITKImageReaderFilter::executeImpl(DataStructure& dataStructure, const A auto origin = filterArgs.value(k_Origin_Key); auto spacing = filterArgs.value(k_Spacing_Key); auto pChangeDataType = filterArgs.value(k_ChangeDataType_Key); - auto newDataType = ConvertChoiceToDataType(filterArgs.value(k_ImageDataType_Key)); + auto newDataType = ITK::detail::ConvertChoiceToDataType(filterArgs.value(k_ImageDataType_Key)); DataPath imageDataArrayPath = imageGeometryPath.createChildPath(cellDataName).createChildPath(imageDataArrayName); const IDataArray* inputArrayPtr = dataStructure.getDataAs(imageDataArrayPath); diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImportImageStackFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImportImageStackFilter.cpp index 3a73343cb2..245129ea8f 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImportImageStackFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImportImageStackFilter.cpp @@ -15,6 +15,7 @@ #include "simplnx/Parameters/DataObjectNameParameter.hpp" #include "simplnx/Parameters/GeneratedFileListParameter.hpp" #include "simplnx/Parameters/VectorParameter.hpp" +#include "simplnx/Utilities/FilterUtilities.hpp" #include #include @@ -133,7 +134,7 @@ namespace cxITKImportImageStackFilter template Result<> ReadImageStack(DataStructure& dataStructure, const DataPath& imageGeomPath, const std::string& cellDataName, const std::string& imageArrayName, const std::vector& files, ChoicesParameter::ValueType transformType, bool convertToGrayscale, const VectorFloat32Parameter::ValueType& luminosityValues, bool resample, float32 scalingFactor, - const IFilter::MessageHandler& messageHandler, const std::atomic_bool& shouldCancel) + bool changeDataType, ChoicesParameter::ValueType destType, const IFilter::MessageHandler& messageHandler, const std::atomic_bool& shouldCancel) { auto& imageGeom = dataStructure.getDataRefAs(imageGeomPath); DataPath imageDataPath = imageGeomPath.createChildPath(cellDataName).createChildPath(imageArrayName); @@ -172,6 +173,8 @@ Result<> ReadImageStack(DataStructure& dataStructure, const DataPath& imageGeomP args.insertOrAssign(ITKImageReaderFilter::k_CellDataName_Key, std::make_any(cellDataName)); args.insertOrAssign(ITKImageReaderFilter::k_ImageDataArrayPath_Key, std::make_any(imageArrayName)); args.insertOrAssign(ITKImageReaderFilter::k_FileName_Key, std::make_any(filePath)); + args.insertOrAssign(ITKImageReaderFilter::k_ChangeDataType_Key, std::make_any(changeDataType)); + args.insertOrAssign(ITKImageReaderFilter::k_ImageDataType_Key, std::make_any(destType)); auto executeResult = imageReader.execute(importedDataStructure, args); if(executeResult.result.invalid()) @@ -470,12 +473,7 @@ IFilter::PreflightResult ITKImportImageStackFilter::preflightImpl(const DataStru nx::core::DataTypeToString(createArrayActionPtr->type()))); } - if(pChangeDataType) - { -// auto action = std::make_unique(ConvertNumericTypeToDataType(numericType), arrayDims, std::vector{1ULL}, imageDataPath); -// resultOutputActions.value().appendAction(std::move(action)); - } - else if(pConvertToGrayScaleValue) + if(pConvertToGrayScaleValue) { auto* filterListPtr = Application::Instance()->getFilterList(); if(!filterListPtr->containsPlugin(k_SimplnxCorePluginId)) @@ -514,6 +512,9 @@ Result<> ITKImportImageStackFilter::executeImpl(DataStructure& dataStructure, co auto pScaleImagesValue = filterArgs.value(k_ScaleImages_Key); auto pScalingValue = filterArgs.value(k_Scaling_Key); + auto changeDataType = filterArgs.value(k_ChangeDataType_Key); + auto destType = filterArgs.value(k_ImageDataType_Key); + // const DataPath imageDataPath = imageGeomPath.createChildPath(cellDataName).createChildPath(imageDataName); std::vector files = inputFileListInfo.generate(); @@ -531,62 +532,91 @@ Result<> ITKImportImageStackFilter::executeImpl(DataStructure& dataStructure, co { return MakeErrorResult(-4, fmt::format("Unsupported pixel component: {}", imageIO->GetComponentTypeAsString(component))); } + Result<> readResult; - switch(*numericType) + if(changeDataType && + ExecuteNeighborFunction(nx::core::ITK::detail::PreflightTypeConversionValidateFunctor{}, ConvertNumericTypeToDataType(*numericType), ITK::detail::ConvertChoiceToDataType(destType))) { - case NumericType::uint8: { - readResult = cxITKImportImageStackFilter::ReadImageStack(dataStructure, imageGeomPath, cellDataName, imageDataName, files, imageTransformValue, convertToGrayScaleValue, colorWeightsValue, - pScaleImagesValue, pScalingValue, messageHandler, shouldCancel); - break; - } - case NumericType::int8: { - readResult = cxITKImportImageStackFilter::ReadImageStack(dataStructure, imageGeomPath, cellDataName, imageDataName, files, imageTransformValue, convertToGrayScaleValue, colorWeightsValue, - pScaleImagesValue, pScalingValue, messageHandler, shouldCancel); - break; - } - case NumericType::uint16: { - readResult = cxITKImportImageStackFilter::ReadImageStack(dataStructure, imageGeomPath, cellDataName, imageDataName, files, imageTransformValue, convertToGrayScaleValue, colorWeightsValue, - pScaleImagesValue, pScalingValue, messageHandler, shouldCancel); - break; - } - case NumericType::int16: { - readResult = cxITKImportImageStackFilter::ReadImageStack(dataStructure, imageGeomPath, cellDataName, imageDataName, files, imageTransformValue, convertToGrayScaleValue, colorWeightsValue, - pScaleImagesValue, pScalingValue, messageHandler, shouldCancel); - break; - } - case NumericType::uint32: { - readResult = cxITKImportImageStackFilter::ReadImageStack(dataStructure, imageGeomPath, cellDataName, imageDataName, files, imageTransformValue, convertToGrayScaleValue, colorWeightsValue, - pScaleImagesValue, pScalingValue, messageHandler, shouldCancel); - break; - } - case NumericType::int32: { - readResult = cxITKImportImageStackFilter::ReadImageStack(dataStructure, imageGeomPath, cellDataName, imageDataName, files, imageTransformValue, convertToGrayScaleValue, colorWeightsValue, - pScaleImagesValue, pScalingValue, messageHandler, shouldCancel); - break; - } - case NumericType::uint64: { - readResult = cxITKImportImageStackFilter::ReadImageStack(dataStructure, imageGeomPath, cellDataName, imageDataName, files, imageTransformValue, convertToGrayScaleValue, colorWeightsValue, - pScaleImagesValue, pScalingValue, messageHandler, shouldCancel); - break; - } - case NumericType::int64: { - readResult = cxITKImportImageStackFilter::ReadImageStack(dataStructure, imageGeomPath, cellDataName, imageDataName, files, imageTransformValue, convertToGrayScaleValue, colorWeightsValue, - pScaleImagesValue, pScalingValue, messageHandler, shouldCancel); - break; - } - case NumericType::float32: { - readResult = cxITKImportImageStackFilter::ReadImageStack(dataStructure, imageGeomPath, cellDataName, imageDataName, files, imageTransformValue, convertToGrayScaleValue, colorWeightsValue, - pScaleImagesValue, pScalingValue, messageHandler, shouldCancel); - break; - } - case NumericType::float64: { - readResult = cxITKImportImageStackFilter::ReadImageStack(dataStructure, imageGeomPath, cellDataName, imageDataName, files, imageTransformValue, convertToGrayScaleValue, colorWeightsValue, - pScaleImagesValue, pScalingValue, messageHandler, shouldCancel); - break; - } - default: { - throw std::runtime_error("Unsupported array type"); + switch(ITK::detail::ConvertChoiceToDataType(destType)) + { + case DataType::uint8: { + readResult = cxITKImportImageStackFilter::ReadImageStack(dataStructure, imageGeomPath, cellDataName, imageDataName, files, imageTransformValue, convertToGrayScaleValue, colorWeightsValue, + pScaleImagesValue, pScalingValue, changeDataType, destType, messageHandler, shouldCancel); + break; + } + case DataType::uint16: { + readResult = cxITKImportImageStackFilter::ReadImageStack(dataStructure, imageGeomPath, cellDataName, imageDataName, files, imageTransformValue, convertToGrayScaleValue, + colorWeightsValue, pScaleImagesValue, pScalingValue, changeDataType, destType, messageHandler, shouldCancel); + break; + } + case DataType::uint32: { + readResult = cxITKImportImageStackFilter::ReadImageStack(dataStructure, imageGeomPath, cellDataName, imageDataName, files, imageTransformValue, convertToGrayScaleValue, + colorWeightsValue, pScaleImagesValue, pScalingValue, changeDataType, destType, messageHandler, shouldCancel); + break; + } + default: { + throw std::runtime_error("Unsupported Conversion type"); + } + } } + else + { + switch(*numericType) + { + case NumericType::uint8: { + readResult = cxITKImportImageStackFilter::ReadImageStack(dataStructure, imageGeomPath, cellDataName, imageDataName, files, imageTransformValue, convertToGrayScaleValue, colorWeightsValue, + pScaleImagesValue, pScalingValue, changeDataType, destType, messageHandler, shouldCancel); + break; + } + case NumericType::int8: { + readResult = cxITKImportImageStackFilter::ReadImageStack(dataStructure, imageGeomPath, cellDataName, imageDataName, files, imageTransformValue, convertToGrayScaleValue, colorWeightsValue, + pScaleImagesValue, pScalingValue, changeDataType, destType, messageHandler, shouldCancel); + break; + } + case NumericType::uint16: { + readResult = cxITKImportImageStackFilter::ReadImageStack(dataStructure, imageGeomPath, cellDataName, imageDataName, files, imageTransformValue, convertToGrayScaleValue, + colorWeightsValue, pScaleImagesValue, pScalingValue, changeDataType, destType, messageHandler, shouldCancel); + break; + } + case NumericType::int16: { + readResult = cxITKImportImageStackFilter::ReadImageStack(dataStructure, imageGeomPath, cellDataName, imageDataName, files, imageTransformValue, convertToGrayScaleValue, colorWeightsValue, + pScaleImagesValue, pScalingValue, changeDataType, destType, messageHandler, shouldCancel); + break; + } + case NumericType::uint32: { + readResult = cxITKImportImageStackFilter::ReadImageStack(dataStructure, imageGeomPath, cellDataName, imageDataName, files, imageTransformValue, convertToGrayScaleValue, + colorWeightsValue, pScaleImagesValue, pScalingValue, changeDataType, destType, messageHandler, shouldCancel); + break; + } + case NumericType::int32: { + readResult = cxITKImportImageStackFilter::ReadImageStack(dataStructure, imageGeomPath, cellDataName, imageDataName, files, imageTransformValue, convertToGrayScaleValue, colorWeightsValue, + pScaleImagesValue, pScalingValue, changeDataType, destType, messageHandler, shouldCancel); + break; + } + case NumericType::uint64: { + readResult = cxITKImportImageStackFilter::ReadImageStack(dataStructure, imageGeomPath, cellDataName, imageDataName, files, imageTransformValue, convertToGrayScaleValue, + colorWeightsValue, pScaleImagesValue, pScalingValue, changeDataType, destType, messageHandler, shouldCancel); + break; + } + case NumericType::int64: { + readResult = cxITKImportImageStackFilter::ReadImageStack(dataStructure, imageGeomPath, cellDataName, imageDataName, files, imageTransformValue, convertToGrayScaleValue, colorWeightsValue, + pScaleImagesValue, pScalingValue, changeDataType, destType, messageHandler, shouldCancel); + break; + } + case NumericType::float32: { + readResult = cxITKImportImageStackFilter::ReadImageStack(dataStructure, imageGeomPath, cellDataName, imageDataName, files, imageTransformValue, convertToGrayScaleValue, + colorWeightsValue, pScaleImagesValue, pScalingValue, changeDataType, destType, messageHandler, shouldCancel); + break; + } + case NumericType::float64: { + readResult = cxITKImportImageStackFilter::ReadImageStack(dataStructure, imageGeomPath, cellDataName, imageDataName, files, imageTransformValue, convertToGrayScaleValue, + colorWeightsValue, pScaleImagesValue, pScalingValue, changeDataType, destType, messageHandler, shouldCancel); + break; + } + default: { + throw std::runtime_error("Unsupported array type"); + } + } } return readResult; From cbedb9262e90bc8dca270075f53b3d4dcbfba69b Mon Sep 17 00:00:00 2001 From: nyoungbq Date: Tue, 6 Aug 2024 09:07:31 -0400 Subject: [PATCH 4/4] Added conversion to fiji montage as well --- .../Filters/Algorithms/ITKImportFijiMontage.cpp | 16 ++++++++++++---- .../Filters/Algorithms/ITKImportFijiMontage.hpp | 2 ++ .../Filters/ITKImageReaderFilter.cpp | 4 ++-- .../Filters/ITKImportFijiMontageFilter.cpp | 13 +++++++++++++ .../Filters/ITKImportFijiMontageFilter.hpp | 2 ++ 5 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/Algorithms/ITKImportFijiMontage.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/Algorithms/ITKImportFijiMontage.cpp index 2b5d62daf7..27fa38d188 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/Algorithms/ITKImportFijiMontage.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/Algorithms/ITKImportFijiMontage.cpp @@ -1,6 +1,5 @@ #include "ITKImportFijiMontage.hpp" -#include "ITKImageProcessing/Common/ITKArrayHelper.hpp" #include "ITKImageProcessing/Common/ReadImageUtils.hpp" #include "ITKImageProcessing/Filters/ITKImageReaderFilter.hpp" @@ -201,7 +200,7 @@ class IOHandler // Ensure that we are dealing with in-core memory ONLY const IDataArray* inputArrayPtr = m_DataStructure.getDataAs(imageDataPath); - if(inputArrayPtr->getDataFormat() != "") + if(!inputArrayPtr->getDataFormat().empty()) { return MakeErrorResult(-9999, fmt::format("Input Array '{}' utilizes out-of-core data. This is not supported within ITK filters.", imageDataPath.toString())); } @@ -213,8 +212,17 @@ class IOHandler image->setSpacing(FloatVec3(1.0f, 1.0f, 1.0f)); // Use ITKUtils to read the image into the DataStructure - Result<> imageReaderResult = - cxItkImageReaderFilter::ReadImageExecute(bound.Filepath.string(), m_DataStructure, imageDataPath, bound.Filepath.string()); + Result<> imageReaderResult; + if(m_InputValues->changeDataType) + { + imageReaderResult = cxItkImageReaderFilter::ReadImageExecute(bound.Filepath.string(), m_DataStructure, bound.Filepath.string(), + imageDataPath, m_InputValues->destType); + } + else + { + imageReaderResult = + cxItkImageReaderFilter::ReadImageExecute(bound.Filepath.string(), m_DataStructure, imageDataPath, bound.Filepath.string()); + } if(imageReaderResult.invalid()) { for(const auto& error : imageReaderResult.errors()) diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/Algorithms/ITKImportFijiMontage.hpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/Algorithms/ITKImportFijiMontage.hpp index 0a6ea33d17..9bb63d8491 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/Algorithms/ITKImportFijiMontage.hpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/Algorithms/ITKImportFijiMontage.hpp @@ -18,6 +18,8 @@ struct ITKIMAGEPROCESSING_EXPORT ITKImportFijiMontageInputValues bool changeOrigin = false; bool convertToGrayScale = false; bool parentDataGroup = false; + bool changeDataType = false; + DataType destType = DataType::uint8; fs::path inputFilePath = {}; IGeometry::LengthUnit lengthUnit = IGeometry::LengthUnit::Micrometer; std::vector origin = {}; diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImageReaderFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImageReaderFilter.cpp index f5ca3c511c..aeee4a7ba2 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImageReaderFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImageReaderFilter.cpp @@ -116,7 +116,7 @@ IFilter::PreflightResult ITKImageReaderFilter::preflightImpl(const DataStructure auto origin = filterArgs.value(k_Origin_Key); auto spacing = filterArgs.value(k_Spacing_Key); auto pChangeDataType = filterArgs.value(k_ChangeDataType_Key); - auto choiceType = filterArgs.value(k_ImageDataType_Key); + auto pChoiceType = filterArgs.value(k_ImageDataType_Key); std::string fileNameString = fileName.string(); @@ -128,7 +128,7 @@ IFilter::PreflightResult ITKImageReaderFilter::preflightImpl(const DataStructure imageReaderOptions.Origin = FloatVec3(static_cast(origin[0]), static_cast(origin[1]), static_cast(origin[2])); imageReaderOptions.Spacing = FloatVec3(static_cast(spacing[0]), static_cast(spacing[1]), static_cast(spacing[2])); imageReaderOptions.ChangeDataType = pChangeDataType; - imageReaderOptions.ImageDataType = ITK::detail::ConvertChoiceToDataType(choiceType); + imageReaderOptions.ImageDataType = ITK::detail::ConvertChoiceToDataType(pChoiceType); Result result = cxItkImageReaderFilter::ReadImagePreflight(fileNameString, imageGeomPath, cellDataName, imageDataArrayName, imageReaderOptions); diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImportFijiMontageFilter.cpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImportFijiMontageFilter.cpp index 09c3967cc6..7a995cae4d 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImportFijiMontageFilter.cpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImportFijiMontageFilter.cpp @@ -2,6 +2,7 @@ #include "Algorithms/ITKImportFijiMontage.hpp" +#include "ITKImageProcessing/Common/ITKArrayHelper.hpp" #include "ITKImageProcessing/Filters/ITKImageReaderFilter.hpp" #include "simplnx/Core/Application.hpp" @@ -84,6 +85,9 @@ Parameters ITKImportFijiMontageFilter::parameters() const std::make_unique(k_ConvertToGrayScale_Key, "Convert To GrayScale", "The filter will show an error if the images are already in grayscale format", false)); params.insert(std::make_unique(k_ColorWeights_Key, "Color Weighting", "The luminosity values for the conversion", std::vector{0.2125f, 0.7154f, 0.0721f}, std::vector(3))); + params.insertLinkableParameter(std::make_unique(k_ChangeDataType_Key, "Set Image Data Type", "Set the final created image data type.", false)); + params.insert(std::make_unique(k_ImageDataType_Key, "Output Data Type", "Numeric Type of data to create", 0ULL, + ChoicesParameter::Choices{"uint8", "uint16", "uint32"})); // Sequence Dependent DO NOT REORDER params.insertLinkableParameter(std::make_unique(k_ParentDataGroup_Key, "Parent Imported Images Under a DataGroup", "Create a new DataGroup to hold the imported images", true)); params.insertSeparator(Parameters::Separator{"Output Data Object(s)"}); @@ -93,6 +97,7 @@ Parameters ITKImportFijiMontageFilter::parameters() const params.insert(std::make_unique(k_ImageDataArrayName_Key, "Image DataArray Name", "The name of the import image data", "Image")); // Associate the Linkable Parameter(s) to the children parameters that they control + params.linkParameters(k_ChangeDataType_Key, k_ImageDataType_Key, true); params.linkParameters(k_ChangeOrigin_Key, k_Origin_Key, true); params.linkParameters(k_ConvertToGrayScale_Key, k_ColorWeights_Key, true); params.linkParameters(k_ParentDataGroup_Key, k_DataGroupName_Key, true); @@ -120,6 +125,8 @@ IFilter::PreflightResult ITKImportFijiMontageFilter::preflightImpl(const DataStr auto pDataContainerPathValue = filterArgs.value(k_DataContainerPath_Key); auto pCellAttributeMatrixNameValue = filterArgs.value(k_CellAttributeMatrixName_Key); auto pImageDataArrayNameValue = filterArgs.value(k_ImageDataArrayName_Key); + auto pChangeDataType = filterArgs.value(k_ChangeDataType_Key); + auto pChoiceType = filterArgs.value(k_ImageDataType_Key); PreflightResult preflightResult; nx::core::Result resultOutputActions = {}; @@ -132,6 +139,8 @@ IFilter::PreflightResult ITKImportFijiMontageFilter::preflightImpl(const DataStr inputValues.inputFilePath = pInputFileValue; inputValues.origin = pOriginValue; inputValues.imagePrefix = pDataContainerPathValue; + inputValues.changeDataType = pChangeDataType; + inputValues.destType = ITK::detail::ConvertChoiceToDataType(pChoiceType); // Read from the file if the input file has changed or the input file's time stamp is out of date. if(pInputFileValue != s_HeaderCache[m_InstanceId].inputFile || s_HeaderCache[m_InstanceId].timeStamp < fs::last_write_time(pInputFileValue) || s_HeaderCache[m_InstanceId].valuesChanged(inputValues)) @@ -175,6 +184,8 @@ IFilter::PreflightResult ITKImportFijiMontageFilter::preflightImpl(const DataStr imageImportArgs.insertOrAssign(ITKImageReaderFilter::k_ImageGeometryPath_Key, std::make_any(imageDataProxy.getParent().getParent())); imageImportArgs.insertOrAssign(ITKImageReaderFilter::k_CellDataName_Key, std::make_any(imageDataProxy.getParent().getTargetName())); imageImportArgs.insertOrAssign(ITKImageReaderFilter::k_ImageDataArrayPath_Key, std::make_any(imageDataProxy.getTargetName())); + imageImportArgs.insertOrAssign(ITKImageReaderFilter::k_ChangeDataType_Key, std::make_any(pChangeDataType)); + imageImportArgs.insertOrAssign(ITKImageReaderFilter::k_ImageDataType_Key, std::make_any(pChoiceType)); auto result = imageImportFilter.preflight(dataStructure, imageImportArgs, messageHandler, shouldCancel); if(result.outputActions.invalid()) @@ -230,6 +241,8 @@ Result<> ITKImportFijiMontageFilter::executeImpl(DataStructure& dataStructure, c inputValues.imagePrefix = filterArgs.value(k_DataContainerPath_Key); inputValues.cellAMName = filterArgs.value(k_CellAttributeMatrixName_Key); inputValues.imageDataArrayName = filterArgs.value(k_ImageDataArrayName_Key); + inputValues.changeDataType = filterArgs.value(k_ChangeDataType_Key); + inputValues.destType = ITK::detail::ConvertChoiceToDataType(filterArgs.value(k_ImageDataType_Key)); ITKImportFijiMontage(dataStructure, messageHandler, shouldCancel, &inputValues, s_HeaderCache.find(m_InstanceId)->second)(); diff --git a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImportFijiMontageFilter.hpp b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImportFijiMontageFilter.hpp index b356cdd365..31d89f64ad 100644 --- a/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImportFijiMontageFilter.hpp +++ b/src/Plugins/ITKImageProcessing/src/ITKImageProcessing/Filters/ITKImportFijiMontageFilter.hpp @@ -34,6 +34,8 @@ class ITKIMAGEPROCESSING_EXPORT ITKImportFijiMontageFilter : public IFilter static inline constexpr StringLiteral k_LengthUnit_Key = "length_unit_index"; static inline constexpr StringLiteral k_ChangeOrigin_Key = "change_origin"; static inline constexpr StringLiteral k_Origin_Key = "origin"; + static inline constexpr StringLiteral k_ChangeDataType_Key = "change_image_data_type"; + static inline constexpr StringLiteral k_ImageDataType_Key = "image_data_type_index"; static inline constexpr StringLiteral k_ParentDataGroup_Key = "parent_data_group"; static inline constexpr StringLiteral k_ConvertToGrayScale_Key = "convert_to_gray_scale"; static inline constexpr StringLiteral k_ColorWeights_Key = "color_weights";