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;