Skip to content

Commit

Permalink
Functioning ITK Image Reader multi option read in (Image Stack to come)
Browse files Browse the repository at this point in the history
  • Loading branch information
nyoungbq committed Aug 2, 2024
1 parent 555111f commit 5e20b28
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,7 @@
#include <type_traits>
#include <vector>

namespace nx::core
{
namespace ITK
namespace nx::core::ITK
{
struct ImageGeomData
{
Expand Down Expand Up @@ -346,6 +344,62 @@ DataStore<UnderlyingType_t<PixelT>> ConvertImageToDataStore(itk::Image<PixelT, D
return dataStore;
}

template<typename T>
concept NotBoolT = !std::is_same_v<T, bool>;

template <NotBoolT NewStoreT, class PixelT, uint32 Dimension>
Result<> ConvertImageToDataStore(AbstractDataStore<NewStoreT>& dataStore, itk::Image<PixelT, Dimension>& image)
{
using ImageType = itk::Image<PixelT, Dimension>;
using T = UnderlyingType_t<PixelT>;
typename ImageType::SizeType imageSize = image.GetLargestPossibleRegion().GetSize();
std::vector<usize> tDims(imageSize.rbegin(), imageSize.rend());
std::vector<usize> cDims = GetComponentDimensions<PixelT>();
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<T*>(pixelContainer->GetBufferPointer());
pixelContainer->ContainerManageMemoryOff();
if constexpr(std::is_same_v<NewStoreT, T>)
{
std::unique_ptr<T[]> newData(rawBufferPtr);
dataStore = DataStore<T>(std::move(newData), std::move(tDims), std::move(cDims));
}
else
{
std::unique_ptr<NewStoreT[]> newData = std::make_unique<NewStoreT[]>(sizeof(NewStoreT) * pixelContainer->Size());
if constexpr(!std::is_signed_v<NewStoreT> && !std::is_signed_v<T>) // bool would slip through, but it is disallowed
{
constexpr auto destMaxV = static_cast<float64>(std::numeric_limits<NewStoreT>::max());
constexpr auto originMaxV = std::numeric_limits<T>::max();
std::transform(rawBufferPtr, rawBufferPtr + pixelContainer->Size(), newData.get(), [](auto value) {
float64 ratio = static_cast<float64>(value) / originMaxV;
return static_cast<NewStoreT>(ratio * destMaxV);
});
}

dataStore = DataStore<NewStoreT>(std::move(newData), std::move(tDims), std::move(cDims));
}

return {};
}

struct ConvertImageToDatastoreFunctor
{
template <typename T, class... Args>
Result<> operator()(DataStructure& dataStructure, const DataPath& arrayPath, Args&&... args)
{
auto& dataArray = dataStructure.getDataRefAs<DataArray<T>>(arrayPath);
auto& dataStore = dataArray.template getIDataStoreRefAs<DataStore<T>>();

return ConvertImageToDataStore(dataStore, std::forward<Args>(args)...);
}
};

// Could replace with class type non-type template parameters in C++20

template <bool UseScalarV, bool UseVectorV, bool UseRgbRgbaV>
Expand Down Expand Up @@ -827,5 +881,4 @@ Result<detail::ITKFilterFunctorResult_t<FilterCreationFunctorT>> Execute(DataStr
return MakeErrorResult<ResultT>(-222, exception.GetDescription());
}
}
} // namespace ITK
} // namespace nx::core
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,8 @@ Result<OutputActions> ReadImagePreflight(const std::string& fileName, DataPath i

if(imageReaderOptions.ChangeDataType)
{
DataPath tempPath = imageGeomPath.createChildPath(cellDataName).createChildPath("." + arrayName);
actions.appendAction(std::make_unique<CreateArrayAction>(ConvertNumericTypeToDataType(imageReaderOptions.ImageDataType), std::move(arrayDims), std::move(cDims),
imageGeomPath.createChildPath(cellDataName).createChildPath(arrayName)));
actions.appendAction(std::make_unique<CreateArrayAction>(*numericType, std::move(arrayDims), std::move(cDims), tempPath));
actions.appendDeferredAction(std::make_unique<DeleteDataAction>(tempPath, DeleteDataAction::DeleteType::JustObject));
actions.appendAction(
std::make_unique<CreateArrayAction>(imageReaderOptions.ImageDataType, std::move(arrayDims), std::move(cDims), imageGeomPath.createChildPath(cellDataName).createChildPath(arrayName)));
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -49,6 +50,22 @@ struct ReadImageIntoArrayFunctor

return {};
}

//------------------------------------------------------------------------------
template <class PixelT, uint32 Dimension>
Result<> operator()(DataStructure& dataStructure, const std::string& filePath, const DataPath& arrayPath, const DataType& dataType) const
{
using ImageType = itk::Image<PixelT, Dimension>;
using ReaderType = itk::ImageFileReader<ImageType>;

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);;
}
};

//------------------------------------------------------------------------------
Expand Down Expand Up @@ -175,7 +192,7 @@ struct ImageReaderOptions
FloatVec3 Origin;
FloatVec3 Spacing;
bool ChangeDataType = false;
NumericType ImageDataType = NumericType::uint8;
DataType ImageDataType = DataType::uint8;
};

//------------------------------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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
Expand Down Expand Up @@ -83,7 +91,8 @@ Parameters ITKImageReaderFilter::parameters() const
std::vector<std::string>{"X", "Y", "Z"}));

params.insertLinkableParameter(std::make_unique<BoolParameter>(k_ChangeDataType_Key, "Set Image Data Type", "Set the final created image data type.", false));
params.insert(std::make_unique<NumericTypeParameter>(k_ImageDataType_Key, "Output Data Type", "Numeric Type of data to create", NumericType::int32));
params.insert(std::make_unique<ChoicesParameter>(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);

Expand Down Expand Up @@ -124,7 +133,7 @@ IFilter::PreflightResult ITKImageReaderFilter::preflightImpl(const DataStructure
auto origin = filterArgs.value<VectorFloat64Parameter::ValueType>(k_Origin_Key);
auto spacing = filterArgs.value<VectorFloat64Parameter::ValueType>(k_Spacing_Key);
auto pChangeDataType = filterArgs.value<bool>(k_ChangeDataType_Key);
auto numericType = filterArgs.value<NumericType>(k_ImageDataType_Key);
auto choiceType = filterArgs.value<ChoicesParameter::ValueType>(k_ImageDataType_Key);

std::string fileNameString = fileName.string();

Expand All @@ -136,7 +145,7 @@ IFilter::PreflightResult ITKImageReaderFilter::preflightImpl(const DataStructure
imageReaderOptions.Origin = FloatVec3(static_cast<float32>(origin[0]), static_cast<float32>(origin[1]), static_cast<float32>(origin[2]));
imageReaderOptions.Spacing = FloatVec3(static_cast<float32>(spacing[0]), static_cast<float32>(spacing[1]), static_cast<float32>(spacing[2]));
imageReaderOptions.ChangeDataType = pChangeDataType;
imageReaderOptions.ImageDataType = numericType;
imageReaderOptions.ImageDataType = ConvertChoiceToDataType(choiceType);

Result<OutputActions> result = cxItkImageReaderFilter::ReadImagePreflight(fileNameString, imageGeomPath, cellDataName, imageDataArrayName, imageReaderOptions);

Expand All @@ -157,13 +166,9 @@ Result<> ITKImageReaderFilter::executeImpl(DataStructure& dataStructure, const A
auto origin = filterArgs.value<VectorFloat64Parameter::ValueType>(k_Origin_Key);
auto spacing = filterArgs.value<VectorFloat64Parameter::ValueType>(k_Spacing_Key);
auto pChangeDataType = filterArgs.value<bool>(k_ChangeDataType_Key);
auto numericType = filterArgs.value<NumericType>(k_ImageDataType_Key);
auto newDataType = ConvertChoiceToDataType(filterArgs.value<ChoicesParameter::ValueType>(k_ImageDataType_Key));

DataPath imageDataArrayPath = imageGeometryPath.createChildPath(cellDataName).createChildPath(imageDataArrayName);
if(pChangeDataType)
{
imageDataArrayPath = imageGeometryPath.createChildPath(cellDataName).createChildPath("." + imageDataArrayName);
}
const IDataArray* inputArrayPtr = dataStructure.getDataAs<IDataArray>(imageDataArrayPath);
if(!inputArrayPtr->getDataFormat().empty())
{
Expand All @@ -172,34 +177,14 @@ Result<> ITKImageReaderFilter::executeImpl(DataStructure& dataStructure, const A

std::string fileNameString = fileName.string();

ImageGeom& imageGeom = dataStructure.getDataRefAs<ImageGeom>(imageGeometryPath);

auto result = cxItkImageReaderFilter::ReadImageExecute<cxItkImageReaderFilter::ReadImageIntoArrayFunctor>(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<NumericTypeParameter::ValueType>(numericType));
args.insertOrAssign("array_to_convert_path", std::make_any<DataPath>(tempDataArrayPath));
args.insertOrAssign("converted_array_name", std::make_any<std::string>(imageDataArrayName));
args.insertOrAssign("delete_original_array", std::make_any<bool>(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<cxItkImageReaderFilter::ReadImageIntoArrayFunctor>(fileNameString, dataStructure, fileNameString, imageDataArrayPath, newDataType);
}
else
{
result = cxItkImageReaderFilter::ReadImageExecute<cxItkImageReaderFilter::ReadImageIntoArrayFunctor>(fileNameString, dataStructure, imageDataArrayPath, fileNameString);
}

return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<BoolParameter>(k_ChangeDataType_Key, "Set Image Data Type", "Set the final created image data type.", false));
params.insert(std::make_unique<NumericTypeParameter>(k_ImageDataType_Key, "Output Data Type", "Numeric Type of data to create", NumericType::int32));
params.insert(std::make_unique<ChoicesParameter>(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(
Expand Down Expand Up @@ -379,7 +380,7 @@ IFilter::PreflightResult ITKImportImageStackFilter::preflightImpl(const DataStru
auto pScalingValue = filterArgs.value<Float32Parameter::ValueType>(k_Scaling_Key);

auto pChangeDataType = filterArgs.value<bool>(k_ChangeDataType_Key);
auto numericType = filterArgs.value<NumericType>(k_ImageDataType_Key);
auto numericType = filterArgs.value<ChoicesParameter::ValueType>(k_ImageDataType_Key);

PreflightResult preflightResult;
nx::core::Result<OutputActions> resultOutputActions = {};
Expand Down Expand Up @@ -411,7 +412,7 @@ IFilter::PreflightResult ITKImportImageStackFilter::preflightImpl(const DataStru
imageReaderArgs.insertOrAssign(ITKImageReaderFilter::k_ImageDataArrayPath_Key, std::make_any<DataObjectNameParameter::ValueType>(pImageDataArrayNameValue));
imageReaderArgs.insertOrAssign(ITKImageReaderFilter::k_FileName_Key, std::make_any<fs::path>(files.at(0)));
imageReaderArgs.insertOrAssign(ITKImageReaderFilter::k_ChangeDataType_Key, std::make_any<bool>(pChangeDataType));
imageReaderArgs.insertOrAssign(ITKImageReaderFilter::k_ImageDataType_Key, std::make_any<NumericTypeParameter::ValueType>(numericType));
imageReaderArgs.insertOrAssign(ITKImageReaderFilter::k_ImageDataType_Key, std::make_any<ChoicesParameter::ValueType>(numericType));

const ITKImageReaderFilter imageReader;
PreflightResult imageReaderResult = imageReader.preflight(dataStructure, imageReaderArgs, messageHandler, shouldCancel);
Expand Down Expand Up @@ -471,8 +472,8 @@ IFilter::PreflightResult ITKImportImageStackFilter::preflightImpl(const DataStru

if(pChangeDataType)
{
auto action = std::make_unique<CreateArrayAction>(ConvertNumericTypeToDataType(numericType), arrayDims, std::vector<size_t>{1ULL}, imageDataPath);
resultOutputActions.value().appendAction(std::move(action));
// auto action = std::make_unique<CreateArrayAction>(ConvertNumericTypeToDataType(numericType), arrayDims, std::vector<size_t>{1ULL}, imageDataPath);
// resultOutputActions.value().appendAction(std::move(action));
}
else if(pConvertToGrayScaleValue)
{
Expand Down

0 comments on commit 5e20b28

Please sign in to comment.