Skip to content

Commit

Permalink
feat: wasm transform interface classes
Browse files Browse the repository at this point in the history
  • Loading branch information
thewtex committed Jul 3, 2024
1 parent cf79eca commit 03b5cd6
Show file tree
Hide file tree
Showing 15 changed files with 1,354 additions and 340 deletions.
225 changes: 224 additions & 1 deletion include/itkTransformJSON.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

#include <vector>

#include "itkCompositeTransformIOHelper.h"

#include "glaze/glaze.hpp"

namespace itk
Expand Down Expand Up @@ -96,6 +98,227 @@ namespace itk
* \ingroup WebAssemblyInterface
*/
using TransformListJSON = std::list<TransformJSON>;

template<typename TTransformBase>
auto transformListToTransformListJSON(std::list<typename TTransformBase::ConstPointer> & transformList, bool inMemory) -> TransformListJSON
{
TransformListJSON transformListJSON;

std::string compositeTransformType = transformList.front()->GetTransformTypeAsString();
using TransformBaseType = TTransformBase;
using ParametersValueType = typename TransformBaseType::ParametersValueType;
CompositeTransformIOHelperTemplate<ParametersValueType> helper;

using ConstTransformListType = std::list<typename TransformBaseType::ConstPointer>;
ConstTransformListType usedTransformList = transformList;

//
// if the first transform in the list is a
// composite transform, use its internal list
// instead of the IO
if (compositeTransformType.find("CompositeTransform") != std::string::npos)
{
usedTransformList = helper.GetTransformList(transformList.front().GetPointer());
}

unsigned int count = 0;
typename ConstTransformListType::const_iterator end = usedTransformList.end();
for (typename ConstTransformListType::const_iterator it = usedTransformList.begin(); it != end; ++it)
{
TransformJSON transformJSON;
const TransformBaseType * currentTransform = it->GetPointer();
const std::string transformType = currentTransform->GetTransformTypeAsString();
const std::string delim = "_";
std::vector<std::string> tokens;
size_t start = 0;
size_t end = 0;
while ((end = transformType.find(delim, start)) != std::string::npos)
{
tokens.push_back(transformType.substr(start, end - start));
start = end + delim.length();
}
tokens.push_back(transformType.substr(start));
const std::string pString = tokens[0];
if (pString == "IdentityTransform")
{
transformJSON.transformType.transformParameterization = JSONTransformParameterizationEnum::Identity;
}
else if (pString == "CompositeTransform")
{
transformJSON.transformType.transformParameterization = JSONTransformParameterizationEnum::Composite;
}
else if (pString == "TranslationTransform")
{
transformJSON.transformType.transformParameterization = JSONTransformParameterizationEnum::Translation;
}
else if (pString == "Euler2DTransform")
{
transformJSON.transformType.transformParameterization = JSONTransformParameterizationEnum::Euler2D;
}
else if (pString == "Euler3DTransform")
{
transformJSON.transformType.transformParameterization = JSONTransformParameterizationEnum::Euler3D;
}
else if (pString == "Rigid2DTransform")
{
transformJSON.transformType.transformParameterization = JSONTransformParameterizationEnum::Rigid2D;
}
else if (pString == "Rigid3DPerspectiveTransform")
{
transformJSON.transformType.transformParameterization = JSONTransformParameterizationEnum::Rigid3DPerspective;
}
else if (pString == "VersorRigid3DTransform")
{
transformJSON.transformType.transformParameterization = JSONTransformParameterizationEnum::VersorRigid3D;
}
else if (pString == "Versor")
{
transformJSON.transformType.transformParameterization = JSONTransformParameterizationEnum::Versor;
}
else if (pString == "ScaleLogarithmicTransform")
{
transformJSON.transformType.transformParameterization = JSONTransformParameterizationEnum::ScaleLogarithmic;
}
else if (pString == "ScaleSkewVersor3DTransform")
{
transformJSON.transformType.transformParameterization = JSONTransformParameterizationEnum::ScaleSkewVersor3D;
}
else if (pString == "ScaleTransform")
{
transformJSON.transformType.transformParameterization = JSONTransformParameterizationEnum::Scale;
}
else if (pString == "Similarity2DTransform")
{
transformJSON.transformType.transformParameterization = JSONTransformParameterizationEnum::Similarity2D;
}
else if (pString == "Similarity3DTransform")
{
transformJSON.transformType.transformParameterization = JSONTransformParameterizationEnum::Similarity3D;
}
else if (pString == "QuaternionRigidTransform")
{
transformJSON.transformType.transformParameterization = JSONTransformParameterizationEnum::QuaternionRigid;
}
else if (pString == "AffineTransform")
{
transformJSON.transformType.transformParameterization = JSONTransformParameterizationEnum::Affine;
}
else if (pString == "ScalableAffineTransform")
{
transformJSON.transformType.transformParameterization = JSONTransformParameterizationEnum::ScalableAffine;
}
else if (pString == "AzimuthElevationToCartesianTransform")
{
transformJSON.transformType.transformParameterization =
JSONTransformParameterizationEnum::AzimuthElevationToCartesian;
}
else if (pString == "BSplineTransform")
{
transformJSON.transformType.transformParameterization = JSONTransformParameterizationEnum::BSpline;
}
else if (pString == "BSplineSmoothingOnUpdateDisplacementFieldTransform")
{
transformJSON.transformType.transformParameterization =
JSONTransformParameterizationEnum::BSplineSmoothingOnUpdateDisplacementField;
}
else if (pString == "ConstantVelocityFieldTransform")
{
transformJSON.transformType.transformParameterization = JSONTransformParameterizationEnum::ConstantVelocityField;
}
else if (pString == "DisplacementFieldTransform")
{
transformJSON.transformType.transformParameterization = JSONTransformParameterizationEnum::DisplacementField;
}
else if (pString == "GaussianExponentialDiffeomorphicTransform")
{
transformJSON.transformType.transformParameterization =
JSONTransformParameterizationEnum::GaussianExponentialDiffeomorphic;
}
else if (pString == "GaussianSmoothingOnUpdateDisplacementFieldTransform")
{
transformJSON.transformType.transformParameterization =
JSONTransformParameterizationEnum::GaussianSmoothingOnUpdateDisplacementField;
}
else if (pString == "GaussianSmoothingOnUpdateTimeVaryingVelocityFieldTransform")
{
transformJSON.transformType.transformParameterization =
JSONTransformParameterizationEnum::GaussianSmoothingOnUpdateTimeVaryingVelocityField;
}
else if (pString == "TimeVaryingVelocityFieldTransform")
{
transformJSON.transformType.transformParameterization =
JSONTransformParameterizationEnum::TimeVaryingVelocityField;
}
else if (pString == "VelocityFieldTransform")
{
transformJSON.transformType.transformParameterization = JSONTransformParameterizationEnum::VelocityField;
}
else
{
throw std::logic_error("Unknown transform type: " + pString);
}

constexpr size_t parametersSize = sizeof(ParametersValueType);
if (parametersSize == 4)
{
transformJSON.transformType.parametersValueType = JSONFloatTypesEnum::float32;
}
else if (parametersSize == 8)
{
transformJSON.transformType.parametersValueType = JSONFloatTypesEnum::float64;
}
else
{
throw std::logic_error("Unknown parameters value type");
}

transformJSON.transformType.inputDimension = currentTransform->GetInputSpaceDimension();
transformJSON.transformType.outputDimension = currentTransform->GetOutputSpaceDimension();

transformJSON.numberOfFixedParameters = currentTransform->GetFixedParameters().Size();
transformJSON.numberOfParameters = currentTransform->GetParameters().Size();
transformJSON.name = currentTransform->GetObjectName();
// Todo: needs to be pushed from itk::Transform to itk::TransformBase
// Available in ITK 5.4.1 and later
// https://github.com/InsightSoftwareConsortium/ITK/pull/4734
// transformJSON.inputSpaceName = currentTransform->GetInputSpaceName();
// transformJSON.inputSpaceName = currentTransform->GetOutputSpaceName();
if (inMemory)
{
if (pString == "CompositeTransform")
{
// For composite transforms, we don't store the parameters in memory directly
transformJSON.fixedParameters = "data:application/vnd.itk.address,0:0";
transformJSON.parameters = "data:application/vnd.itk.address,0:0";
}
else
{
std::ostringstream fixedParametersStream;
fixedParametersStream << "data:application/vnd.itk.address,0:";
const auto fixedParametersAddr = reinterpret_cast< size_t >( currentTransform->GetFixedParameters().data_block() );
fixedParametersStream << fixedParametersAddr;
transformJSON.fixedParameters = fixedParametersStream.str();

std::ostringstream parametersStream;
parametersStream << "data:application/vnd.itk.address,0:";
const auto parametersAddr = reinterpret_cast< size_t >( currentTransform->GetParameters().data_block() );
parametersStream << parametersAddr;
transformJSON.parameters = parametersStream.str();
}
}
else
{
transformJSON.fixedParameters = "data:application/vnd.itk.path,data/" + std::to_string(count) + "/fixed-parameters.raw";
transformJSON.parameters = "data:application/vnd.itk.path,data/" + std::to_string(count) + "/parameters.raw";
}

transformListJSON.push_back(transformJSON);
++count;
}

return transformListJSON;
}

} // end namespace itk

template <>
Expand Down Expand Up @@ -131,4 +354,4 @@ struct glz::meta<itk::JSONTransformParameterizationEnum> {
);
};

#endif // itkWasmTransformIO_h
#endif // itkTransformJSON_h
92 changes: 92 additions & 0 deletions include/itkTransformToWasmTransformFilter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*=========================================================================
*
* Copyright NumFOCUS
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*=========================================================================*/
#ifndef itkTransformToWasmTransformFilter_h
#define itkTransformToWasmTransformFilter_h

#include "itkProcessObject.h"
#include "itkWasmTransform.h"

#include "itkDataObjectDecorator.h"

namespace itk
{
/**
*\class TransformToWasmTransformFilter
* \brief Convert an Transform to an WasmTransform object.
*
* \ingroup WebAssemblyInterface
*/
template <typename TTransform>
class ITK_TEMPLATE_EXPORT TransformToWasmTransformFilter : public ProcessObject
{
public:
ITK_DISALLOW_COPY_AND_MOVE(TransformToWasmTransformFilter);

/** Standard class type aliases. */
using Self = TransformToWasmTransformFilter;
using Superclass = ProcessObject;
using Pointer = SmartPointer<Self>;
using ConstPointer = SmartPointer<const Self>;

/** Method for creation through the object factory. */
itkNewMacro(Self);

/** Run-time type information (and related methods). */
itkTypeMacro(TransformToWasmTransformFilter, ProcessObject);

using DataObjectIdentifierType = Superclass::DataObjectIdentifierType;
using DataObjectPointerArraySizeType = Superclass::DataObjectPointerArraySizeType;

using TransformType = TTransform;
using WasmTransformType = WasmTransform<TransformType>;

itkSetGetDecoratedObjectInputMacro(Transform, TransformType);

WasmTransformType *
GetOutput();
const WasmTransformType *
GetOutput() const;

WasmTransformType *
GetOutput(unsigned int idx);

protected:
TransformToWasmTransformFilter();
~TransformToWasmTransformFilter() override = default;

ProcessObject::DataObjectPointer
MakeOutput(ProcessObject::DataObjectPointerArraySizeType idx) override;
ProcessObject::DataObjectPointer
MakeOutput(const ProcessObject::DataObjectIdentifierType &) override;

void
GenerateOutputInformation() override
{} // do nothing
void
GenerateData() override;

void
PrintSelf(std::ostream & os, Indent indent) const override;
};
} // end namespace itk

#ifndef ITK_MANUAL_INSTANTIATION
# include "itkTransformToWasmTransformFilter.hxx"
#endif

#endif
Loading

0 comments on commit 03b5cd6

Please sign in to comment.