void parseDimensionToTemplate(MatlabImportFilter::Pointer matlabImport, MatlabExportFilter::Pointer matlabExport) { // retrieve pointers to the inputs that we are going to need here typedef MatlabImportFilter::MatlabInputPointer MatlabInputPointer; MatlabInputPointer inX = matlabImport->GetRegisteredInput("X"); // dimension of points mwSize Nx = mxGetN(inX->pm); // parse the dimension value switch (Nx) { case 2: parseTransformType<TScalarType, 2>(matlabImport, matlabExport); break; case 3: parseTransformType<TScalarType, 3>(matlabImport, matlabExport); break; default: mexErrMsgTxt("Input points can only have dimensions 2 or 3"); break; } // exit function return; }
void parseTransformType(MatlabImportFilter::Pointer matlabImport, MatlabExportFilter::Pointer matlabExport) { // retrieve pointers to the inputs that we are going to need here typedef MatlabImportFilter::MatlabInputPointer MatlabInputPointer; MatlabInputPointer inTRANSFORM = matlabImport->GetRegisteredInput("TRANSFORM"); // get type of transform char *transform = mxArrayToString(inTRANSFORM->pm); if (transform == NULL) { mexErrMsgTxt("Cannot read TRANSFORM string"); } // kernel transform types typedef itk::ElasticBodySplineKernelTransform<TScalarType, Dimension> ElasticTransformType; typedef itk::ElasticBodyReciprocalSplineKernelTransform<TScalarType, Dimension> ElasticReciprocalTransformType; typedef itk::ThinPlateSplineKernelTransform<TScalarType, Dimension> TpsTransformType; typedef itk::ThinPlateR2LogRSplineKernelTransform<TScalarType, Dimension> TpsR2LogRTransformType; typedef itk::VolumeSplineKernelTransform<TScalarType, Dimension> VolumeTransformType; // select transform function if (!strcmp(transform, "elastic")) { runKernelTransform<TScalarType, Dimension, ElasticTransformType>(matlabImport, matlabExport); } else if (!strcmp(transform, "elasticr")) { runKernelTransform<TScalarType, Dimension, ElasticReciprocalTransformType>(matlabImport, matlabExport); } else if (!strcmp(transform, "tps")) { runKernelTransform<TScalarType, Dimension, TpsTransformType>(matlabImport, matlabExport); } else if (!strcmp(transform, "tpsr2")) { runKernelTransform<TScalarType, Dimension, TpsR2LogRTransformType>(matlabImport, matlabExport); } else if (!strcmp(transform, "volume")) { runKernelTransform<TScalarType, Dimension, VolumeTransformType>(matlabImport, matlabExport); } else if (!strcmp(transform, "bspline")) { runBSplineTransform<TScalarType, Dimension>(matlabImport, matlabExport); } else if (!strcmp(transform, "")) { std::cout << "Implemented transform types: elastic, elasticr, tps, tpsr2, volume, bspline" << std::endl; return; } else { mexErrMsgTxt("Transform not implemented"); } // exit function return; }
// parseInputTypeToTemplate() void parseInputTypeToTemplate(MatlabImportFilter::Pointer matlabImport, MatlabExportFilter::Pointer matlabExport) { // retrieve pointers to the inputs that we are going to need here typedef MatlabImportFilter::MatlabInputPointer MatlabInputPointer; MatlabInputPointer inX = matlabImport->GetRegisteredInput("X"); MatlabInputPointer inY = matlabImport->GetRegisteredInput("Y"); MatlabInputPointer inXI = matlabImport->GetRegisteredInput("XI"); // point coordinate type mxClassID pointCoordClassId = mxGetClassID(inX->pm); // check that all point coordinates have the same type (it simplifies // things with templates) if ((pointCoordClassId != mxGetClassID(inY->pm)) | (pointCoordClassId != mxGetClassID(inXI->pm))) { mexErrMsgTxt("Input arguments X, Y and XI must have the same type"); } // swith input point type switch(pointCoordClassId) { case mxDOUBLE_CLASS: parseDimensionToTemplate<double>(matlabImport, matlabExport); break; case mxSINGLE_CLASS: parseDimensionToTemplate<float>(matlabImport, matlabExport); break; case mxUNKNOWN_CLASS: mexErrMsgTxt("Point coordinates have unknown type"); break; default: mexErrMsgTxt("Point coordinates can only be of type single or double"); break; } // exit function return; }
void runKernelTransform(MatlabImportFilter::Pointer matlabImport, MatlabExportFilter::Pointer matlabExport) { // check number of input arguments (the kernel transform syntax // accepts up to 4 arguments only. Thus, we cannot use InputIndexType_MAX) matlabImport->CheckNumberOfArguments(4, 4); // retrieve pointers to the inputs that we are going to need here typedef MatlabImportFilter::MatlabInputPointer MatlabInputPointer; MatlabInputPointer inX = matlabImport->GetRegisteredInput("X"); MatlabInputPointer inY = matlabImport->GetRegisteredInput("Y"); MatlabInputPointer inXI = matlabImport->GetRegisteredInput("XI"); // register the outputs for this function at the export filter typedef MatlabExportFilter::MatlabOutputPointer MatlabOutputPointer; MatlabOutputPointer outYI = matlabExport->RegisterOutput(OUT_YI, "YI"); // get size of input arguments mwSize Mx = mxGetM(inX->pm); // number of source points mwSize Mxi = mxGetM(inXI->pm); // number of points to be warped mwSize ndimxi; // number of dimension of points to be warped const mwSize *dimsxi; // dimensions vector of array of points to be warped // create pointers to input matrices TScalarType *x = (TScalarType *)mxGetData(inX->pm); // source points TScalarType *y = (TScalarType *)mxGetData(inY->pm); // target points TScalarType *xi = (TScalarType *)mxGetData(inXI->pm); // points to be warped if (x == NULL) { mexErrMsgTxt("Cannot get a pointer to input X"); } if (y == NULL) { mexErrMsgTxt("Cannot get a pointer to input Y"); } if (xi == NULL) { mexErrMsgTxt("Cannot get a pointer to input XI"); } // type definitions and variables to store points for the kernel transform typedef typename TransformType::PointSetType PointSetType; typename PointSetType::Pointer fixedPointSet = PointSetType::New(); typename PointSetType::Pointer movingPointSet = PointSetType::New(); typename PointSetType::Pointer toWarpPointSet = PointSetType::New(); typedef typename PointSetType::PointsContainer PointsContainer; typename PointsContainer::Pointer fixedPointContainer = PointsContainer::New(); typename PointsContainer::Pointer movingPointContainer = PointsContainer::New(); typedef typename PointSetType::PointType PointType; PointType fixedPoint; PointType movingPoint; PointType toWarpPoint; PointType warpedPoint; // duplicate the input x and y matrices to PointSet format so that // we can pass it to the ITK function mwSize pointId=0; for (mwSize row=0; row < Mx; ++row) { for (mwSize col=0; col < (mwSize)Dimension; ++col) { fixedPoint[CAST2MWSIZE(col)] = y[Mx * col + row]; movingPoint[CAST2MWSIZE(col)] = x[Mx * col + row]; } fixedPointContainer->InsertElement(pointId, fixedPoint); movingPointContainer->InsertElement(pointId, movingPoint); ++pointId; } fixedPointSet->SetPoints(fixedPointContainer); movingPointSet->SetPoints(movingPointContainer); // compute the transform typename TransformType::Pointer transform; transform = TransformType::New(); transform->SetSourceLandmarks(movingPointSet); transform->SetTargetLandmarks(fixedPointSet); transform->ComputeWMatrix(); // create output vector and pointer to populate it ndimxi = mxGetNumberOfDimensions(inXI->pm); dimsxi = mxGetDimensions(inXI->pm); std::vector<mwSize> size; for (mwIndex i = 0; i < ndimxi; ++i) { size.push_back(dimsxi[i]); } TScalarType *yi = matlabExport->AllocateNDArrayInMatlab<TScalarType>(outYI, size); // transform points for (mwSize row=0; row < Mxi; ++row) { for (mwSize col=0; col < (mwSize)Dimension; ++col) { toWarpPoint[CAST2MWSIZE(col)] = xi[Mxi * col + row]; } warpedPoint = transform->TransformPoint(toWarpPoint); for (mwSize col=0; col < (mwSize)Dimension; ++col) { yi[Mxi * col + row] = warpedPoint[CAST2MWSIZE(col)]; } } // exit function return; }
void runBSplineTransform(MatlabImportFilter::Pointer matlabImport, MatlabExportFilter::Pointer matlabExport) { // retrieve pointers to the inputs that we are going to need here typedef MatlabImportFilter::MatlabInputPointer MatlabInputPointer; MatlabInputPointer inX = matlabImport->GetRegisteredInput("X"); MatlabInputPointer inY = matlabImport->GetRegisteredInput("Y"); MatlabInputPointer inXI = matlabImport->GetRegisteredInput("XI"); MatlabInputPointer inORDER = matlabImport->GetRegisteredInput("ORDER"); MatlabInputPointer inLEVELS = matlabImport->GetRegisteredInput("LEVELS"); // register the output for this function at the export filter typedef MatlabExportFilter::MatlabOutputPointer MatlabOutputPointer; MatlabOutputPointer outYI = matlabExport->RegisterOutput(OUT_YI, "YI"); // spline order (input argument): default or user-provided unsigned int splineOrder = matlabImport->ReadScalarFromMatlab<unsigned int>(inORDER, 3); // number of levels (input argument): default or user-provided unsigned int numOfLevels = matlabImport->ReadScalarFromMatlab<unsigned int>(inLEVELS, 5); // get size of input arguments mwSize Mx = mxGetM(inX->pm); // number of source points mwSize Mxi = mxGetM(inXI->pm); // number of points to be warped // pointers to input matrices TScalarType *x = (TScalarType *)mxGetData(inX->pm); // source points TScalarType *y = (TScalarType *)mxGetData(inY->pm); // target points TScalarType *xi = (TScalarType *)mxGetData(inXI->pm); // points to be warped if (x == NULL) { mexErrMsgTxt("Cannot get a pointer to input X"); } if (y == NULL) { mexErrMsgTxt("Cannot get a pointer to input Y"); } if (xi == NULL) { mexErrMsgTxt("Cannot get a pointer to input XI"); } // type definitions for the BSPline transform typedef itk::Vector<TScalarType, Dimension> DataType; typedef itk::PointSet<DataType, Dimension> PointSetType; typedef itk::Image<DataType, Dimension> ImageType; typedef typename itk::BSplineScatteredDataPointSetToImageFilter<PointSetType, ImageType> TransformType; // variables to store the input points typename PointSetType::Pointer pointSet = PointSetType::New(); typename PointSetType::PointType xParam; DataType v; // v = y-x, i.e. displacement vector between source and // target landmark // init variables to contain the limits of a bounding box that // contains all the points typename ImageType::PointType orig, term; for (mwSize col=0; col < (mwSize)Dimension; ++col) { orig[CAST2MWSIZE(col)] = std::numeric_limits<TScalarType>::max(); term[CAST2MWSIZE(col)] = std::numeric_limits<TScalarType>::min(); } // find bounding box limits for (mwSize row=0; row < Mx; ++row) { for (mwSize col=0; col < (mwSize)Dimension; ++col) { orig[CAST2MWSIZE(col)] = std::min((TScalarType)orig[CAST2MWSIZE(col)], x[Mx * col + row]); term[CAST2MWSIZE(col)] = std::max((TScalarType)term[CAST2MWSIZE(col)], x[Mx * col + row]); orig[CAST2MWSIZE(col)] = std::min((TScalarType)orig[CAST2MWSIZE(col)], y[Mx * col + row]); term[CAST2MWSIZE(col)] = std::max((TScalarType)term[CAST2MWSIZE(col)], y[Mx * col + row]); } } for (mwSize row=0; row < Mxi; ++row) { for (mwSize col=0; col < (mwSize)Dimension; ++col) { orig[CAST2MWSIZE(col)] = std::min((TScalarType)orig[CAST2MWSIZE(col)], xi[Mxi * col + row]); term[CAST2MWSIZE(col)] = std::max((TScalarType)term[CAST2MWSIZE(col)], xi[Mxi * col + row]); } } // compute length of each size of the bounding box DataType len = term - orig; TScalarType lenmax = std::numeric_limits<TScalarType>::min(); for (mwSize col=0; col < (mwSize)Dimension; ++col) { lenmax = std::max(lenmax, len[CAST2MWSIZE(col)]); } // duplicate the input x and y matrices to PointSet format so that // we can pass it to the ITK function // // we also translate and scale all points so that the bounding box // fits within the domain [0, 1] x [0, 1] x [0,1]. We need to do // this because the BSpline function requires the parametric domain // to be within [0, 1] x [0, 1] x [0,1] for (mwSize row=0; row < Mx; ++row) { for (mwSize col=0; col < (mwSize)Dimension; ++col) { v[CAST2MWSIZE(col)] = (y[Mx * col + row] - x[Mx * col + row]) / lenmax; xParam[CAST2MWSIZE(col)] = (x[Mx * col + row] - orig[CAST2MWSIZE(col)]) / lenmax; } pointSet->SetPoint(row, xParam); pointSet->SetPointData(row, v); } // instantiate and set-up transform typename TransformType::Pointer transform = TransformType::New(); transform->SetGenerateOutputImage(false); transform->SetInput(pointSet); transform->SetSplineOrder(splineOrder); typename TransformType::ArrayType ncps ; ncps.Fill(splineOrder + 1); transform->SetNumberOfControlPoints(ncps); transform->SetNumberOfLevels(numOfLevels); // note that closedim, spacing, sz and orig are all refered to the // parametric domain, i.e. the domain of x and xi typename TransformType::ArrayType closedim; typename ImageType::SpacingType spacing; typename ImageType::SizeType sz; // the parametric domain is not periodic in any dimension closedim.Fill(0); // as we are not creating the image, we don't need to provide a // sensible number of voxels. But size has to be at least 2 voxels // to avoid a run-time error sz.Fill(2); // because the parameterization is in [0, 1] x [0, 1] x [0,1], and // we have only size = 2 voxels in every dimension, the spacing will // be 1.0 / (2 - 1) = 1.0 spacing.Fill(1.0); // because of the reparameterization, the origin we have to pass to // the transform is not the origin of the real points, but the // origin of the [0, 1] x [0, 1] x [0,1] bounding box typename ImageType::PointType origZero; origZero.Fill(0.0); transform->SetCloseDimension(closedim); transform->SetSize(sz); transform->SetSpacing(spacing); transform->SetOrigin(origZero); // run transform transform->Update(); // create output vector and pointer to populate it mwSize ndimxi = mxGetNumberOfDimensions(inXI->pm); const mwSize *dimsxi = mxGetDimensions(inXI->pm); std::vector<mwSize> size; for (mwIndex i = 0; i < ndimxi; ++i) { size.push_back(dimsxi[i]); } TScalarType *yi = matlabExport->AllocateNDArrayInMatlab<TScalarType>(outYI, size); // from ITK v4.x, we need to instantiate a function to evaluate // points of the B-spline, as the Evaluate() method has been removed // from the TransformType #if ITK_VERSION_MAJOR>=4 // Note: in the following, we have to use TCoordRep=double, because // ITK gives a compilation error of an abstract class not having // been implemented. Otherwise, we would use // TCoordRep=TScalar=float, as in the rest of this program typedef typename itk::BSplineControlPointImageFunction<ImageType, double> EvalFunctionType; typename EvalFunctionType::Pointer function = EvalFunctionType::New(); function->SetSplineOrder(splineOrder); function->SetOrigin(origZero); function->SetSpacing(spacing); function->SetSize(sz); function->SetInputImage(transform->GetPhiLattice()); #endif // sample the warp field DataType vi; // warp field sample typename PointSetType::PointType xiParam; // sampling coordinates for (mwSize row=0; row < Mxi; ++row) { for (mwSize col=0; col < (mwSize)Dimension; ++col) { xiParam[CAST2MWSIZE(col)] = (xi[Mxi * col + row] - orig[CAST2MWSIZE(col)]) / lenmax; } #if ITK_VERSION_MAJOR<4 transform->Evaluate(xiParam, vi); #else vi = function->Evaluate(xiParam); #endif for (mwSize col=0; col < (mwSize)Dimension; ++col) { yi[Mxi * col + row] = xi[Mxi * col + row] + vi[CAST2MWSIZE(col)] * lenmax; } } // exit function return; }