diff --git a/Modules/MatchPointRegistration/CMakeLists.txt b/Modules/MatchPointRegistration/CMakeLists.txt index 577f222225..4be5284265 100644 --- a/Modules/MatchPointRegistration/CMakeLists.txt +++ b/Modules/MatchPointRegistration/CMakeLists.txt @@ -1,29 +1,29 @@ mitk_create_module( INCLUDE_DIRS PUBLIC algorithms PRIVATE src/Helper src/Rendering - DEPENDS MitkCore MitkSceneSerializationBase + DEPENDS MitkCore MitkSceneSerializationBase MitkMultilabel PACKAGE_DEPENDS PUBLIC MatchPoint PRIVATE VTK|ImagingGeneral+ImagingHybrid ) if(TARGET ${MODULE_TARGET}) set(ALG_PROFILE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/algorithms) include(${MatchPoint_SOURCE_DIR}/CMake/mapFunctionCreateAlgorithmProfile.cmake) file(GLOB ALG_PROFILE_FILES LIST_DIRECTORIES false RELATIVE ${ALG_PROFILE_DIR} "${ALG_PROFILE_DIR}/*.profile") foreach(profile_file ${ALG_PROFILE_FILES}) get_filename_component(profile_name ${profile_file} NAME_WE) message(STATUS "Generate MDRA profile ${profile_name} (from ${profile_file})") CREATE_ALGORITHM_PROFILE(${profile_name} ${ALG_PROFILE_DIR}/${profile_file}) endforeach() add_subdirectory(autoload/IO) add_subdirectory(deployment) if(BUILD_TESTING) add_subdirectory(Testing) endif() add_subdirectory(cmdapps) endif() diff --git a/Modules/MatchPointRegistration/src/Helper/mitkImageMappingHelper.cpp b/Modules/MatchPointRegistration/src/Helper/mitkImageMappingHelper.cpp index 494f35049c..fdf8b80dda 100644 --- a/Modules/MatchPointRegistration/src/Helper/mitkImageMappingHelper.cpp +++ b/Modules/MatchPointRegistration/src/Helper/mitkImageMappingHelper.cpp @@ -1,389 +1,444 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include #include #include #include #include #include #include #include +#include #include "mapRegistration.h" #include "mitkImageMappingHelper.h" #include "mitkRegistrationHelper.h" template typename ::itk::InterpolateImageFunction< TImage >::Pointer generateInterpolator(mitk::ImageMappingInterpolator::Type interpolatorType) { typedef ::itk::InterpolateImageFunction< TImage > BaseInterpolatorType; typename BaseInterpolatorType::Pointer result; switch (interpolatorType) { case mitk::ImageMappingInterpolator::NearestNeighbor: { result = ::itk::NearestNeighborInterpolateImageFunction::New(); break; } case mitk::ImageMappingInterpolator::BSpline_3: { typename ::itk::BSplineInterpolateImageFunction::Pointer spInterpolator = ::itk::BSplineInterpolateImageFunction::New(); spInterpolator->SetSplineOrder(3); result = spInterpolator; break; } case mitk::ImageMappingInterpolator::WSinc_Hamming: { result = ::itk::WindowedSincInterpolateImageFunction::New(); break; } case mitk::ImageMappingInterpolator::WSinc_Welch: { result = ::itk::WindowedSincInterpolateImageFunction >::New(); break; } default: { result = ::itk::LinearInterpolateImageFunction::New(); break; } } return result; }; template void doMITKMap(const ::itk::Image* input, mitk::ImageMappingHelper::ResultImageType::Pointer& result, const mitk::ImageMappingHelper::RegistrationType*& registration, bool throwOnOutOfInputAreaError, const double& paddingValue, const mitk::ImageMappingHelper::ResultImageGeometryType*& resultGeometry, bool throwOnMappingError, const double& errorValue, mitk::ImageMappingInterpolator::Type interpolatorType) { typedef ::map::core::Registration ConcreteRegistrationType; typedef ::map::core::ImageMappingTask, ::itk::Image > MappingTaskType; typename MappingTaskType::Pointer spTask = MappingTaskType::New(); typedef typename MappingTaskType::ResultImageDescriptorType ResultImageDescriptorType; typename ResultImageDescriptorType::Pointer resultDescriptor; //check if image and result geometry fits the passed registration ///////////////////////////////////////////////////////////////// if (registration->getMovingDimensions()!=VImageDimension) { map::core::OStringStream str; str << "Dimension of MITK image ("<getMovingDimensions()<<")."; throw mitk::AccessByItkException(str.str()); } if (registration->getTargetDimensions()!=VImageDimension) { map::core::OStringStream str; str << "Dimension of MITK image ("<getTargetDimensions()<<")."; throw mitk::AccessByItkException(str.str()); } const ConcreteRegistrationType* castedReg = dynamic_cast(registration); if (registration->getTargetDimensions()==2 && resultGeometry) { mitk::ImageMappingHelper::ResultImageGeometryType::BoundsArrayType bounds = resultGeometry->GetBounds(); if (bounds[4]!=0 || bounds[5]!=0) { //array "bounds" is constructed as [min Dim1, max Dim1, min Dim2, max Dim2, min Dim3, max Dim3] //therfore [4] and [5] must be 0 map::core::OStringStream str; str << "Dimension of defined result geometry does not equal the target dimension of the registration object ("<getTargetDimensions()<<")."; throw mitk::AccessByItkException(str.str()); } } //check/create resultDescriptor ///////////////////////// if (resultGeometry) { resultDescriptor = ResultImageDescriptorType::New(); typename ResultImageDescriptorType::PointType origin; typename ResultImageDescriptorType::SizeType size; typename ResultImageDescriptorType::SpacingType fieldSpacing; typename ResultImageDescriptorType::DirectionType matrix; mitk::ImageMappingHelper::ResultImageGeometryType::BoundsArrayType geoBounds = resultGeometry->GetBounds(); mitk::Vector3D geoSpacing = resultGeometry->GetSpacing(); mitk::Point3D geoOrigin = resultGeometry->GetOrigin(); mitk::AffineTransform3D::MatrixType geoMatrix = resultGeometry->GetIndexToWorldTransform()->GetMatrix(); for (unsigned int i = 0; i(geoOrigin[i]); fieldSpacing[i] = static_cast(geoSpacing[i]); size[i] = static_cast(geoBounds[(2*i)+1]-geoBounds[2*i])*fieldSpacing[i]; } //Matrix extraction matrix.SetIdentity(); unsigned int i; unsigned int j; /// \warning 2D MITK images could have a 3D rotation, since they have a 3x3 geometry matrix. /// If it is only a rotation around the transversal plane normal, it can be express with a 2x2 matrix. /// In this case, the ITK image conservs this information and is identical to the MITK image! /// If the MITK image contains any other rotation, the ITK image will have no rotation at all. /// Spacing is of course conserved in both cases. // the following loop devides by spacing now to normalize columns. // counterpart of InitializeByItk in mitkImage.h line 372 of revision 15092. // Check if information is lost if ( VImageDimension == 2) { if ( ( geoMatrix[0][2] != 0) || ( geoMatrix[1][2] != 0) || ( geoMatrix[2][0] != 0) || ( geoMatrix[2][1] != 0) || (( geoMatrix[2][2] != 1) && ( geoMatrix[2][2] != -1) )) { // The 2D MITK image contains 3D rotation information. // This cannot be expressed in a 2D ITK image, so the ITK image will have no rotation } else { // The 2D MITK image can be converted to an 2D ITK image without information loss! for ( i=0; i < 2; ++i) { for( j=0; j < 2; ++j ) { matrix[i][j] = geoMatrix[i][j]/fieldSpacing[j]; } } } } else if (VImageDimension == 3) { // Normal 3D image. Conversion possible without problem! for ( i=0; i < 3; ++i) { for( j=0; j < 3; ++j ) { matrix[i][j] = geoMatrix[i][j]/fieldSpacing[j]; } } } else { assert(0); throw mitk::AccessByItkException("Usage of resultGeometry for 2D images is not yet implemented."); /**@TODO Implement extraction of 2D-Rotation-Matrix out of 3D-Rotation-Matrix * to cover this case as well. * matrix = extract2DRotationMatrix(resultGeometry)*/ } resultDescriptor->setOrigin(origin); resultDescriptor->setSize(size); resultDescriptor->setSpacing(fieldSpacing); resultDescriptor->setDirection(matrix); } //do the mapping ///////////////////////// typedef ::itk::InterpolateImageFunction< ::itk::Image > BaseInterpolatorType; typename BaseInterpolatorType::Pointer interpolator = generateInterpolator< ::itk::Image >(interpolatorType); assert(interpolator.IsNotNull()); spTask->setImageInterpolator(interpolator); spTask->setInputImage(input); spTask->setRegistration(castedReg); spTask->setResultImageDescriptor(resultDescriptor); spTask->setThrowOnMappingError(throwOnMappingError); spTask->setErrorValue(errorValue); spTask->setThrowOnPaddingError(throwOnOutOfInputAreaError); spTask->setPaddingValue(paddingValue); spTask->execute(); mitk::CastToMitkImage<>(spTask->getResultImage(),result); } + +/**Helper function to ensure the mapping of all time steps of an image.*/ +void doMapTimesteps(const mitk::ImageMappingHelper::InputImageType* input, mitk::Image* result, const mitk::ImageMappingHelper::RegistrationType* registration, bool throwOnOutOfInputAreaError,double paddingValue, const mitk::ImageMappingHelper::ResultImageGeometryType* resultGeometry, bool throwOnMappingError, double errorValue, mitk::ImageMappingInterpolator::Type interpolatorType) +{ + for (unsigned int i = 0; iGetTimeSteps(); ++i) + { + mitk::ImageTimeSelector::Pointer imageTimeSelector = mitk::ImageTimeSelector::New(); + imageTimeSelector->SetInput(input); + imageTimeSelector->SetTimeNr(i); + imageTimeSelector->UpdateLargestPossibleRegion(); + + mitk::ImageMappingHelper::InputImageType::Pointer timeStepInput = imageTimeSelector->GetOutput(); + mitk::ImageMappingHelper::ResultImageType::Pointer timeStepResult; + AccessByItk_n(timeStepInput, doMITKMap, (timeStepResult, registration, throwOnOutOfInputAreaError, paddingValue, resultGeometry, throwOnMappingError, errorValue, interpolatorType)); + mitk::ImageReadAccessor readAccess(timeStepResult); + result->SetVolume(readAccess.GetData(), i); + } +} + +mitk::TimeGeometry::Pointer CreateResultTimeGeometry(const mitk::ImageMappingHelper::InputImageType* input, const mitk::ImageMappingHelper::ResultImageGeometryType* resultGeometry) +{ + mitk::TimeGeometry::ConstPointer timeGeometry = input->GetTimeGeometry(); + mitk::TimeGeometry::Pointer mappedTimeGeometry = timeGeometry->Clone(); + + for (unsigned int i = 0; i < input->GetTimeSteps(); ++i) + { + mitk::ImageMappingHelper::ResultImageGeometryType::Pointer mappedGeometry = resultGeometry->Clone(); + mappedTimeGeometry->SetTimeStepGeometry(mappedGeometry, i); + } + return mappedTimeGeometry; +} + mitk::ImageMappingHelper::ResultImageType::Pointer mitk::ImageMappingHelper::map(const InputImageType* input, const RegistrationType* registration, bool throwOnOutOfInputAreaError, const double& paddingValue, const ResultImageGeometryType* resultGeometry, bool throwOnMappingError, const double& errorValue, mitk::ImageMappingInterpolator::Type interpolatorType) { if (!registration) { mitkThrow() << "Cannot map image. Passed registration wrapper pointer is nullptr."; } if (!input) { mitkThrow() << "Cannot map image. Passed image pointer is nullptr."; } ResultImageType::Pointer result; - if(input->GetTimeSteps()==1) - { //map the image and done - AccessByItk_n(input, doMITKMap, (result, registration, throwOnOutOfInputAreaError, paddingValue, resultGeometry, throwOnMappingError, errorValue, interpolatorType)); + auto inputLabelSetImage = dynamic_cast(input); + + if (nullptr == inputLabelSetImage) + { + if (input->GetTimeSteps() == 1) + { //map the image and done + AccessByItk_n(input, doMITKMap, (result, registration, throwOnOutOfInputAreaError, paddingValue, resultGeometry, throwOnMappingError, errorValue, interpolatorType)); + } + else + { //map every time step and compose + + auto mappedTimeGeometry = CreateResultTimeGeometry(input, resultGeometry); + result = mitk::Image::New(); + result->Initialize(input->GetPixelType(), *mappedTimeGeometry, 1, input->GetTimeSteps()); + + doMapTimesteps(input, result, registration, throwOnOutOfInputAreaError, paddingValue, resultGeometry, throwOnMappingError, errorValue, interpolatorType); + } } else - { //map every time step and compose + { + auto resultLabelSetImage = LabelSetImage::New(); - mitk::TimeGeometry::ConstPointer timeGeometry = input->GetTimeGeometry(); - mitk::TimeGeometry::Pointer mappedTimeGeometry = timeGeometry->Clone(); + auto mappedTimeGeometry = CreateResultTimeGeometry(input, resultGeometry); - for (unsigned int i = 0; iGetTimeSteps(); ++i) - { - ResultImageGeometryType::Pointer mappedGeometry = resultGeometry->Clone(); - mappedTimeGeometry->SetTimeStepGeometry(mappedGeometry,i); - } + auto resultTemplate = mitk::Image::New(); + resultTemplate->Initialize(input->GetPixelType(), *mappedTimeGeometry, 1, input->GetTimeSteps()); + + resultLabelSetImage->Initialize(resultTemplate); - result = mitk::Image::New(); - result->Initialize(input->GetPixelType(),*mappedTimeGeometry, 1, input->GetTimeSteps()); + auto cloneInput = inputLabelSetImage->Clone(); + //We need to clone the LabelSetImage due to its illposed design. It is state full + //and we have to iterate through all layers as active layers to ensure the content + //via realy stored (directly working with the layer images does not work with the + //active layer. The clone wastes rescources but is the easiest and safest way to + //ensure 1) correct mapping 2) avoid race conditions with other parts of the + //application because we would change the state of the input. + //This whole code block should be reworked as soon as T28525 is done. - for (unsigned int i = 0; iGetTimeSteps(); ++i) + for (unsigned int layerID = 0; layerID < inputLabelSetImage->GetNumberOfLayers(); ++layerID) { - mitk::ImageTimeSelector::Pointer imageTimeSelector = mitk::ImageTimeSelector::New(); - imageTimeSelector->SetInput(input); - imageTimeSelector->SetTimeNr(i); - imageTimeSelector->UpdateLargestPossibleRegion(); - - InputImageType::Pointer timeStepInput = imageTimeSelector->GetOutput(); - ResultImageType::Pointer timeStepResult; - AccessByItk_n(timeStepInput, doMITKMap, (timeStepResult, registration, throwOnOutOfInputAreaError, paddingValue, resultGeometry, throwOnMappingError, errorValue, interpolatorType)); - mitk::ImageReadAccessor readAccess(timeStepResult); - result->SetVolume(readAccess.GetData(),i); + if (resultLabelSetImage->GetNumberOfLayers() <= layerID) + { + resultLabelSetImage->AddLayer(); + } + resultLabelSetImage->AddLabelSetToLayer(layerID, inputLabelSetImage->GetLabelSet(layerID)->Clone()); + cloneInput->SetActiveLayer(layerID); + resultLabelSetImage->SetActiveLayer(layerID); + + doMapTimesteps(cloneInput, resultLabelSetImage, registration, throwOnOutOfInputAreaError, paddingValue, resultGeometry, throwOnMappingError, errorValue, mitk::ImageMappingInterpolator::Linear); } + + resultLabelSetImage->SetActiveLayer(inputLabelSetImage->GetActiveLayer()); + resultLabelSetImage->GetLabelSet(inputLabelSetImage->GetActiveLayer())->SetActiveLabel(inputLabelSetImage->GetActiveLabel(inputLabelSetImage->GetActiveLayer())->GetValue()); + result = resultLabelSetImage; } return result; } mitk::ImageMappingHelper::ResultImageType::Pointer mitk::ImageMappingHelper::map(const InputImageType* input, const MITKRegistrationType* registration, bool throwOnOutOfInputAreaError, const double& paddingValue, const ResultImageGeometryType* resultGeometry, bool throwOnMappingError, const double& errorValue, mitk::ImageMappingInterpolator::Type) { if (!registration) { mitkThrow() << "Cannot map image. Passed registration wrapper pointer is nullptr."; } if (!registration->GetRegistration()) { mitkThrow() << "Cannot map image. Passed registration wrapper containes no registration."; } if (!input) { mitkThrow() << "Cannot map image. Passed image pointer is nullptr."; } ResultImageType::Pointer result = map(input, registration->GetRegistration(), throwOnOutOfInputAreaError, paddingValue, resultGeometry, throwOnMappingError, errorValue); return result; } mitk::ImageMappingHelper::ResultImageType::Pointer mitk::ImageMappingHelper:: refineGeometry(const InputImageType* input, const RegistrationType* registration, bool throwOnError) { mitk::ImageMappingHelper::ResultImageType::Pointer result = nullptr; if (!registration) { mitkThrow() << "Cannot refine image geometry. Passed registration pointer is nullptr."; } if (!input) { mitkThrow() << "Cannot refine image geometry. Passed image pointer is nullptr."; } mitk::MITKRegistrationHelper::Affine3DTransformType::Pointer spTransform = mitk::MITKRegistrationHelper::getAffineMatrix(registration,false); if(spTransform.IsNull() && throwOnError) { mitkThrow() << "Cannot refine image geometry. Registration does not contain a suitable direct mapping kernel (3D affine transformation or compatible required)."; } if(spTransform.IsNotNull()) { //copy input image result = input->Clone(); //refine geometries for(unsigned int i = 0; i < result->GetTimeSteps(); ++i) { //refine every time step result->GetGeometry(i)->Compose(spTransform); } result->GetTimeGeometry()->Update(); } return result; } mitk::ImageMappingHelper::ResultImageType::Pointer mitk::ImageMappingHelper:: refineGeometry(const InputImageType* input, const MITKRegistrationType* registration, bool throwOnError) { if (!registration) { mitkThrow() << "Cannot refine image geometry. Passed registration wrapper pointer is nullptr."; } if (!registration->GetRegistration()) { mitkThrow() << "Cannot refine image geometry. Passed registration wrapper containes no registration."; } if (!input) { mitkThrow() << "Cannot refine image geometry. Passed image pointer is nullptr."; } ResultImageType::Pointer result = refineGeometry(input, registration->GetRegistration(), throwOnError); return result; } bool mitk::ImageMappingHelper:: canRefineGeometry(const RegistrationType* registration) { bool result = true; if (!registration) { mitkThrow() << "Cannot check refine capability of registration. Passed registration pointer is nullptr."; } //if the helper does not return null, we can refine the geometry. result = mitk::MITKRegistrationHelper::getAffineMatrix(registration,false).IsNotNull(); return result; } bool mitk::ImageMappingHelper:: canRefineGeometry(const MITKRegistrationType* registration) { if (!registration) { mitkThrow() << "Cannot check refine capability of registration. Passed registration wrapper pointer is nullptr."; } if (!registration->GetRegistration()) { mitkThrow() << "Cannot check refine capability of registration. Passed registration wrapper containes no registration."; } return canRefineGeometry(registration->GetRegistration()); } diff --git a/Modules/MatchPointRegistration/src/Helper/mitkRegistrationHelper.cpp b/Modules/MatchPointRegistration/src/Helper/mitkRegistrationHelper.cpp index b9c95a61ad..18bf7ad70a 100644 --- a/Modules/MatchPointRegistration/src/Helper/mitkRegistrationHelper.cpp +++ b/Modules/MatchPointRegistration/src/Helper/mitkRegistrationHelper.cpp @@ -1,165 +1,164 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkRegistrationHelper.h" #include #include #include #include #include +#include //MatchPoint #include "mapRegistrationKernel.h" namespace mitk { mitk::TNodePredicateDataType::ConstPointer InternalRegNodePredicate = mitk::TNodePredicateDataType::New().GetPointer(); mitk::TNodePredicateDataType::ConstPointer InternalImageNodePredicate = mitk::TNodePredicateDataType::New().GetPointer(); mitk::TNodePredicateDataType::ConstPointer InternalPointSetNodePredicate = mitk::TNodePredicateDataType::New().GetPointer(); MITKRegistrationHelper::Affine3DTransformType::Pointer MITKRegistrationHelper:: getAffineMatrix(const mitk::MAPRegistrationWrapper* wrapper, bool inverseKernel) { Affine3DTransformType::Pointer result = nullptr; if (wrapper) { result = getAffineMatrix(wrapper->GetRegistration(), inverseKernel); } return result; } MITKRegistrationHelper::Affine3DTransformType::Pointer MITKRegistrationHelper:: getAffineMatrix(const RegistrationBaseType* registration, bool inverseKernel) { Affine3DTransformType::Pointer result = nullptr; if (registration && is3D(registration)) { const Registration3DType* pReg = dynamic_cast(registration); if (pReg) { if (inverseKernel) { result = getAffineMatrix(pReg->getInverseMapping()); } else { result = getAffineMatrix(pReg->getDirectMapping()); } } } return result; } MITKRegistrationHelper::Affine3DTransformType::Pointer MITKRegistrationHelper::getAffineMatrix(const RegistrationKernel3DBase& kernel) { Affine3DTransformType::Pointer result = nullptr; typedef ::map::core::RegistrationKernel<3,3> KernelType; const KernelType* pModelKernel = dynamic_cast(&kernel); if (pModelKernel) { KernelType::TransformType::MatrixType matrix; KernelType::TransformType::OutputVectorType offset; if(pModelKernel->getAffineMatrixDecomposition(matrix,offset)) { result = Affine3DTransformType::New(); Affine3DTransformType::MatrixType resultMatrix; Affine3DTransformType::OffsetType resultOffset; /**@TODO If MatchPoint and MITK get same scalar values the casting of matrix and offset values is obsolete and should be removed.*/ //The conversion of matrix and offset is needed //because mitk uses float and MatchPoint currently //double as scalar value. for (unsigned int i=0; i(matrix.GetVnlMatrix().begin()[i]); } resultOffset.CastFrom(offset); //needed because mitk uses float and MatchPoint currently double as scalar value result->SetMatrix(resultMatrix); result->SetOffset(resultOffset); } } return result; } bool MITKRegistrationHelper::is3D(const mitk::MAPRegistrationWrapper* wrapper) { bool result = false; if (wrapper) { result = wrapper->GetMovingDimensions()==3 && wrapper->GetTargetDimensions()==3; } return result; } bool MITKRegistrationHelper::is3D(const RegistrationBaseType* reBase) { bool result = false; if (reBase) { result = reBase->getMovingDimensions()==3 && reBase->getTargetDimensions()==3; } return result; } bool MITKRegistrationHelper::IsRegNode(const mitk::DataNode* node) { if (!node) return false; return InternalRegNodePredicate->CheckNode(node); } NodePredicateBase::ConstPointer MITKRegistrationHelper::RegNodePredicate() { return InternalRegNodePredicate.GetPointer(); } NodePredicateBase::ConstPointer MITKRegistrationHelper::ImageNodePredicate() { return InternalImageNodePredicate.GetPointer(); } NodePredicateBase::ConstPointer MITKRegistrationHelper::PointSetNodePredicate() { return InternalPointSetNodePredicate.GetPointer(); } NodePredicateBase::ConstPointer MITKRegistrationHelper::MaskNodePredicate() { - auto isLabelSetImage = mitk::NodePredicateDataType::New("LabelSetImage"); + auto isLabelSetImage = mitk::TNodePredicateDataType::New(); auto hasBinaryProperty = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); auto isLegacyMask = mitk::NodePredicateAnd::New(ImageNodePredicate(), hasBinaryProperty); - return isLegacyMask.GetPointer(); - //Deactivated due to T27435. Should be reactivated as soon T27435 is fixed - //auto isLabelSetOrLegacyMask = mitk::NodePredicateOr::New(isLabelSetImage, isLegacyMask); - // - //return isLabelSetOrLegacyMask.GetPointer(); + auto isLabelSetOrLegacyMask = mitk::NodePredicateOr::New(isLabelSetImage, isLegacyMask); + + return isLabelSetOrLegacyMask.GetPointer(); } }