static HalfHermetianImageType::Pointer GetLowpassOperator(FloatImageType::Pointer norm01_lowres, FloatImageType::Pointer p_image, const PrecisionType scaler) { /* * Make dirac-delta impulse response filter for convolving with the high-resolution image The operator A should represent the characteristics of the measurement device as it takes measurements at lower resolutions. For example, in MRI as resolution is decreased, larger anatomical regions are included in each measurement, thus giving a smoother image as if the high resolution image were passed through a low-pass-filter. p_image below represents the smoothing convolution filter that is applied to a high-resolution image to best represent the low-resolution image sampling. In the case of no downsampling p_image is simply a perfect dirac-delta function. Convolution in the spatial-domain is multiplication in the frequency domain. In the case were some downsampling is present between the lowresolution and the highresolution images, we need the operator A to represent a low-pass filter that optimally models the lower sampling rate. The low-pass filter is accomplished in the frequency domain by zeroing-out frequency components that are not representable in the frequency domain of the low-resolution image. */ HalfHermetianImageType::Pointer testA_fhp = A_fhp(p_image,norm01_lowres.GetPointer()); FloatImageType::Pointer testAtA = At_fhp(testA_fhp,norm01_lowres->GetLargestPossibleRegion().GetSize()[0]%2 == 1, p_image.GetPointer()); HalfHermetianImageType::Pointer AtAhat = GetForwardFFT(testAtA); return opIC(AtAhat,AtAhat,'*',scaler); // A is the linear measurement operator }
void QmitkBasicImageProcessing::StartButtonClicked() { if(!m_SelectedImageNode->GetNode()) return; this->BusyCursorOn(); mitk::Image::Pointer newImage; try { newImage = dynamic_cast<mitk::Image*>(m_SelectedImageNode->GetNode()->GetData()); } catch ( std::exception &e ) { QString exceptionString = "An error occured during image loading:\n"; exceptionString.append( e.what() ); QMessageBox::warning( NULL, "Basic Image Processing", exceptionString , QMessageBox::Ok, QMessageBox::NoButton ); this->BusyCursorOff(); return; } // check if input image is valid, casting does not throw exception when casting from 'NULL-Object' if ( (! newImage) || (newImage->IsInitialized() == false) ) { this->BusyCursorOff(); QMessageBox::warning( NULL, "Basic Image Processing", "Input image is broken or not initialized. Returning.", QMessageBox::Ok, QMessageBox::NoButton ); return; } // check if operation is done on 4D a image time step if(newImage->GetDimension() > 3) { mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); timeSelector->SetInput(newImage); timeSelector->SetTimeNr( ((QmitkSliderNavigatorWidget*)m_Controls->sliceNavigatorTime)->GetPos() ); timeSelector->Update(); newImage = timeSelector->GetOutput(); } // check if image or vector image ImageType::Pointer itkImage = ImageType::New(); VectorImageType::Pointer itkVecImage = VectorImageType::New(); int isVectorImage = newImage->GetPixelType().GetNumberOfComponents(); if(isVectorImage > 1) { CastToItkImage( newImage, itkVecImage ); } else { CastToItkImage( newImage, itkImage ); } std::stringstream nameAddition(""); int param1 = m_Controls->sbParam1->value(); int param2 = m_Controls->sbParam2->value(); double dparam1 = m_Controls->dsbParam1->value(); double dparam2 = m_Controls->dsbParam2->value(); double dparam3 = m_Controls->dsbParam3->value(); try{ switch (m_SelectedAction) { case GAUSSIAN: { GaussianFilterType::Pointer gaussianFilter = GaussianFilterType::New(); gaussianFilter->SetInput( itkImage ); gaussianFilter->SetVariance( param1 ); gaussianFilter->UpdateLargestPossibleRegion(); newImage = mitk::ImportItkImage(gaussianFilter->GetOutput())->Clone(); nameAddition << "_Gaussian_var_" << param1; std::cout << "Gaussian filtering successful." << std::endl; break; } case MEDIAN: { MedianFilterType::Pointer medianFilter = MedianFilterType::New(); MedianFilterType::InputSizeType size; size.Fill(param1); medianFilter->SetRadius( size ); medianFilter->SetInput(itkImage); medianFilter->UpdateLargestPossibleRegion(); newImage = mitk::ImportItkImage(medianFilter->GetOutput())->Clone(); nameAddition << "_Median_radius_" << param1; std::cout << "Median Filtering successful." << std::endl; break; } case TOTALVARIATION: { if(isVectorImage > 1) { VectorTotalVariationFilterType::Pointer TVFilter = VectorTotalVariationFilterType::New(); TVFilter->SetInput( itkVecImage.GetPointer() ); TVFilter->SetNumberIterations(param1); TVFilter->SetLambda(double(param2)/1000.); TVFilter->UpdateLargestPossibleRegion(); newImage = mitk::ImportItkImage(TVFilter->GetOutput())->Clone(); } else { ImagePTypeToFloatPTypeCasterType::Pointer floatCaster = ImagePTypeToFloatPTypeCasterType::New(); floatCaster->SetInput( itkImage ); floatCaster->Update(); FloatImageType::Pointer fImage = floatCaster->GetOutput(); TotalVariationFilterType::Pointer TVFilter = TotalVariationFilterType::New(); TVFilter->SetInput( fImage.GetPointer() ); TVFilter->SetNumberIterations(param1); TVFilter->SetLambda(double(param2)/1000.); TVFilter->UpdateLargestPossibleRegion(); newImage = mitk::ImportItkImage(TVFilter->GetOutput())->Clone(); } nameAddition << "_TV_Iter_" << param1 << "_L_" << param2; std::cout << "Total Variation Filtering successful." << std::endl; break; } case DILATION: { BallType binaryBall; binaryBall.SetRadius( param1 ); binaryBall.CreateStructuringElement(); DilationFilterType::Pointer dilationFilter = DilationFilterType::New(); dilationFilter->SetInput( itkImage ); dilationFilter->SetKernel( binaryBall ); dilationFilter->UpdateLargestPossibleRegion(); newImage = mitk::ImportItkImage(dilationFilter->GetOutput())->Clone(); nameAddition << "_Dilated_by_" << param1; std::cout << "Dilation successful." << std::endl; break; } case EROSION: { BallType binaryBall; binaryBall.SetRadius( param1 ); binaryBall.CreateStructuringElement(); ErosionFilterType::Pointer erosionFilter = ErosionFilterType::New(); erosionFilter->SetInput( itkImage ); erosionFilter->SetKernel( binaryBall ); erosionFilter->UpdateLargestPossibleRegion(); newImage = mitk::ImportItkImage(erosionFilter->GetOutput())->Clone(); nameAddition << "_Eroded_by_" << param1; std::cout << "Erosion successful." << std::endl; break; } case OPENING: { BallType binaryBall; binaryBall.SetRadius( param1 ); binaryBall.CreateStructuringElement(); OpeningFilterType::Pointer openFilter = OpeningFilterType::New(); openFilter->SetInput( itkImage ); openFilter->SetKernel( binaryBall ); openFilter->UpdateLargestPossibleRegion(); newImage = mitk::ImportItkImage(openFilter->GetOutput())->Clone(); nameAddition << "_Opened_by_" << param1; std::cout << "Opening successful." << std::endl; break; } case CLOSING: { BallType binaryBall; binaryBall.SetRadius( param1 ); binaryBall.CreateStructuringElement(); ClosingFilterType::Pointer closeFilter = ClosingFilterType::New(); closeFilter->SetInput( itkImage ); closeFilter->SetKernel( binaryBall ); closeFilter->UpdateLargestPossibleRegion(); newImage = mitk::ImportItkImage(closeFilter->GetOutput())->Clone(); nameAddition << "_Closed_by_" << param1; std::cout << "Closing successful." << std::endl; break; } case GRADIENT: { GradientFilterType::Pointer gradientFilter = GradientFilterType::New(); gradientFilter->SetInput( itkImage ); gradientFilter->SetSigma( param1 ); gradientFilter->UpdateLargestPossibleRegion(); newImage = mitk::ImportItkImage(gradientFilter->GetOutput())->Clone(); nameAddition << "_Gradient_sigma_" << param1; std::cout << "Gradient calculation successful." << std::endl; break; } case LAPLACIAN: { // the laplace filter requires a float type image as input, we need to cast the itkImage // to correct type ImagePTypeToFloatPTypeCasterType::Pointer caster = ImagePTypeToFloatPTypeCasterType::New(); caster->SetInput( itkImage ); caster->Update(); FloatImageType::Pointer fImage = caster->GetOutput(); LaplacianFilterType::Pointer laplacianFilter = LaplacianFilterType::New(); laplacianFilter->SetInput( fImage ); laplacianFilter->UpdateLargestPossibleRegion(); newImage = mitk::ImportItkImage(laplacianFilter->GetOutput())->Clone(); nameAddition << "_Second_Derivative"; std::cout << "Laplacian filtering successful." << std::endl; break; } case SOBEL: { // the sobel filter requires a float type image as input, we need to cast the itkImage // to correct type ImagePTypeToFloatPTypeCasterType::Pointer caster = ImagePTypeToFloatPTypeCasterType::New(); caster->SetInput( itkImage ); caster->Update(); FloatImageType::Pointer fImage = caster->GetOutput(); SobelFilterType::Pointer sobelFilter = SobelFilterType::New(); sobelFilter->SetInput( fImage ); sobelFilter->UpdateLargestPossibleRegion(); newImage = mitk::ImportItkImage(sobelFilter->GetOutput())->Clone(); nameAddition << "_Sobel"; std::cout << "Edge Detection successful." << std::endl; break; } case THRESHOLD: { ThresholdFilterType::Pointer thFilter = ThresholdFilterType::New(); thFilter->SetLowerThreshold(param1 < param2 ? param1 : param2); thFilter->SetUpperThreshold(param2 > param1 ? param2 : param1); thFilter->SetInsideValue(1); thFilter->SetOutsideValue(0); thFilter->SetInput(itkImage); thFilter->UpdateLargestPossibleRegion(); newImage = mitk::ImportItkImage(thFilter->GetOutput())->Clone(); nameAddition << "_Threshold"; std::cout << "Thresholding successful." << std::endl; break; } case INVERSION: { InversionFilterType::Pointer invFilter = InversionFilterType::New(); mitk::ScalarType min = newImage->GetScalarValueMin(); mitk::ScalarType max = newImage->GetScalarValueMax(); invFilter->SetMaximum( max + min ); invFilter->SetInput(itkImage); invFilter->UpdateLargestPossibleRegion(); newImage = mitk::ImportItkImage(invFilter->GetOutput())->Clone(); nameAddition << "_Inverted"; std::cout << "Image inversion successful." << std::endl; break; } case DOWNSAMPLING: { ResampleImageFilterType::Pointer downsampler = ResampleImageFilterType::New(); downsampler->SetInput( itkImage ); NearestInterpolatorType::Pointer interpolator = NearestInterpolatorType::New(); downsampler->SetInterpolator( interpolator ); downsampler->SetDefaultPixelValue( 0 ); ResampleImageFilterType::SpacingType spacing = itkImage->GetSpacing(); spacing *= (double) param1; downsampler->SetOutputSpacing( spacing ); downsampler->SetOutputOrigin( itkImage->GetOrigin() ); downsampler->SetOutputDirection( itkImage->GetDirection() ); ResampleImageFilterType::SizeType size = itkImage->GetLargestPossibleRegion().GetSize(); for ( int i = 0; i < 3; ++i ) { size[i] /= param1; } downsampler->SetSize( size ); downsampler->UpdateLargestPossibleRegion(); newImage = mitk::ImportItkImage(downsampler->GetOutput())->Clone(); nameAddition << "_Downsampled_by_" << param1; std::cout << "Downsampling successful." << std::endl; break; } case FLIPPING: { FlipImageFilterType::Pointer flipper = FlipImageFilterType::New(); flipper->SetInput( itkImage ); itk::FixedArray<bool, 3> flipAxes; for(int i=0; i<3; ++i) { if(i == param1) { flipAxes[i] = true; } else { flipAxes[i] = false; } } flipper->SetFlipAxes(flipAxes); flipper->UpdateLargestPossibleRegion(); newImage = mitk::ImportItkImage(flipper->GetOutput())->Clone(); std::cout << "Image flipping successful." << std::endl; break; } case RESAMPLING: { std::string selectedInterpolator; ResampleImageFilterType::Pointer resampler = ResampleImageFilterType::New(); switch (m_SelectedInterpolation) { case LINEAR: { LinearInterpolatorType::Pointer interpolator = LinearInterpolatorType::New(); resampler->SetInterpolator(interpolator); selectedInterpolator = "Linear"; break; } case NEAREST: { NearestInterpolatorType::Pointer interpolator = NearestInterpolatorType::New(); resampler->SetInterpolator(interpolator); selectedInterpolator = "Nearest"; break; } default: { LinearInterpolatorType::Pointer interpolator = LinearInterpolatorType::New(); resampler->SetInterpolator(interpolator); selectedInterpolator = "Linear"; break; } } resampler->SetInput( itkImage ); resampler->SetOutputOrigin( itkImage->GetOrigin() ); ImageType::SizeType input_size = itkImage->GetLargestPossibleRegion().GetSize(); ImageType::SpacingType input_spacing = itkImage->GetSpacing(); ImageType::SizeType output_size; ImageType::SpacingType output_spacing; output_size[0] = input_size[0] * (input_spacing[0] / dparam1); output_size[1] = input_size[1] * (input_spacing[1] / dparam2); output_size[2] = input_size[2] * (input_spacing[2] / dparam3); output_spacing [0] = dparam1; output_spacing [1] = dparam2; output_spacing [2] = dparam3; resampler->SetSize( output_size ); resampler->SetOutputSpacing( output_spacing ); resampler->SetOutputDirection( itkImage->GetDirection() ); resampler->UpdateLargestPossibleRegion(); ImageType::Pointer resampledImage = resampler->GetOutput(); newImage = mitk::ImportItkImage( resampledImage ); nameAddition << "_Resampled_" << selectedInterpolator; std::cout << "Resampling successful." << std::endl; break; } case RESCALE: { FloatImageType::Pointer floatImage = FloatImageType::New(); CastToItkImage( newImage, floatImage ); itk::RescaleIntensityImageFilter<FloatImageType,FloatImageType>::Pointer filter = itk::RescaleIntensityImageFilter<FloatImageType,FloatImageType>::New(); filter->SetInput(0, floatImage); filter->SetOutputMinimum(dparam1); filter->SetOutputMaximum(dparam2); filter->Update(); floatImage = filter->GetOutput(); newImage = mitk::Image::New(); newImage->InitializeByItk(floatImage.GetPointer()); newImage->SetVolume(floatImage->GetBufferPointer()); nameAddition << "_Rescaled"; std::cout << "Rescaling successful." << std::endl; break; } default: this->BusyCursorOff(); return; } } catch (...) { this->BusyCursorOff(); QMessageBox::warning(NULL, "Warning", "Problem when applying filter operation. Check your input..."); return; } newImage->DisconnectPipeline(); // adjust level/window to new image mitk::LevelWindow levelwindow; levelwindow.SetAuto( newImage ); mitk::LevelWindowProperty::Pointer levWinProp = mitk::LevelWindowProperty::New(); levWinProp->SetLevelWindow( levelwindow ); // compose new image name std::string name = m_SelectedImageNode->GetNode()->GetName(); if (name.find(".pic.gz") == name.size() -7 ) { name = name.substr(0,name.size() -7); } name.append( nameAddition.str() ); // create final result MITK data storage node mitk::DataNode::Pointer result = mitk::DataNode::New(); result->SetProperty( "levelwindow", levWinProp ); result->SetProperty( "name", mitk::StringProperty::New( name.c_str() ) ); result->SetData( newImage ); // for vector images, a different mapper is needed if(isVectorImage > 1) { mitk::VectorImageMapper2D::Pointer mapper = mitk::VectorImageMapper2D::New(); result->SetMapper(1,mapper); } // reset GUI to ease further processing // this->ResetOneImageOpPanel(); // add new image to data storage and set as active to ease further processing GetDefaultDataStorage()->Add( result, m_SelectedImageNode->GetNode() ); if ( m_Controls->cbHideOrig->isChecked() == true ) m_SelectedImageNode->GetNode()->SetProperty( "visible", mitk::BoolProperty::New(false) ); // TODO!! m_Controls->m_ImageSelector1->SetSelectedNode(result); // show the results mitk::RenderingManager::GetInstance()->RequestUpdateAll(); this->BusyCursorOff(); }
/* OPWEIGHTEDL2: Solves weighted L2 regularized inverse problems. Minimizes the cost function X* = argmin_X ||A(X)-b_FC||_2^2 + lambda ||W |D(X)| ||_2^2 where X* = recovered image A = linear measurement operator b_FC = (noisy) measurements % W = diagonal weight matrix built from the edge mask |D(X)| = gradient magnitude at each pixel Inputs: A = function handle representing the forward model/measurement operator At = function handle representing the backwards model/ the transpose of the measurment operator. (e.g. if A is a downsampling, At is a upsampling) b_FC = a vector of measurements; should match the dimensions of A(X) lambda = regularization parameter that balances data fidelity and smoothness. set lambda high for more smoothing. siz = output image size, e.g. siz = [512,512] Niter = is the number of iterations; should be ~100-500 Output: X = high-resolution output image cost = array of cost function value vs. iteration Define AtA fourier mask PrecisionType lambda, uvec ind_samples, frowvec res, int Niter, double tol, PrecisionType gam, FloatImageType::Pointer& X, frowvec& cost, frowvec& resvec) */ FloatImageType::Pointer OpWeightedL2(FloatImageType::Pointer norm01_lowres, FloatImageType::Pointer edgemask) { const PrecisionType lambda = 1e-3F ; constexpr int Niter = 100; const PrecisionType tol = 1e-8F ; const PrecisionType gam = 1.0F ; //typedef itk::VectorMagnitudeImageFilter<CVImageType, FloatImageType> GMType; //The optimal filter for modeling the measurement operator is low pass filter in this case // NOTE: That the A operator is a projection operator, so A^{T}A = A, That is to say that applying // the A^{T} to A results in A. FloatImageType::Pointer p_image = GetDiracDeltaImage(edgemask); // Precompute //Make high-res coefficients const HalfHermetianImageType::Pointer b_FC = GetAFP_of_b(norm01_lowres, edgemask); //TODO: too many copies of Atb here. FloatImageType::Pointer Atb = At_fhp(b_FC, edgemask->GetLargestPossibleRegion().GetSize()[0]%2 == 1, edgemask.GetPointer()); FloatImageType::Pointer TwoAtb = MakeTwoAtb(Atb); FloatImageType::Pointer X = DeepImageCopy<FloatImageType>(Atb); Atb = nullptr; //Save memory here CVImageType::Pointer DX = GetGradient(X); CVImageType::Pointer L = CreateEmptyImage<CVImageType>(DX); CVImageType::Pointer Y = CreateEmptyImage<CVImageType>(DX); //CVImageType::Pointer WDX = CreateEmptyImage<CVImageType>(DX); CVImageType::Pointer residue = CreateEmptyImage<CVImageType>(DX); CVImageType::Pointer YminusL = CreateEmptyImage<CVImageType>(DX); FloatImageType::Pointer tempValue=CreateEmptyImage<FloatImageType>(DX); std::vector<PrecisionType> resvec(Niter,0); std::vector<PrecisionType> cost(Niter,0); #ifdef USE_WRITE_DEGUBBING itk::ComplexToModulusImageFilter<HalfHermetianImageType,FloatImageType>::Pointer cpx2abs = itk::ComplexToModulusImageFilter<HalfHermetianImageType,FloatImageType>::New(); #endif CVImageType::Pointer gradIm = GetGradient(p_image); FloatImageType::Pointer divIm = GetDivergence(gradIm); HalfHermetianImageType::Pointer DtDhat = GetForwardFFT(divIm); // TODO: ALL SAME TO HERE! typedef HalfHermetianImageType::PixelType FCType; HalfHermetianImageType::Pointer TwoTimesAtAhatPlusLamGamDtDhat = CreateEmptyImage<HalfHermetianImageType>(DtDhat); { HalfHermetianImageType::Pointer TwoTimesAtAhat = GetLowpassOperator(norm01_lowres,p_image, 2.0F); TwoTimesAtAhatPlusLamGamDtDhat = opIC(TwoTimesAtAhatPlusLamGamDtDhat,FCType(lambda*gam),'*',DtDhat); //TODO: Make This an inverse! TwoTimesAtAhatPlusLamGamDtDhat = opII(TwoTimesAtAhatPlusLamGamDtDhat,TwoTimesAtAhat,'+',TwoTimesAtAhatPlusLamGamDtDhat); } p_image = nullptr; //Save memory const bool edgemask_ActualXDimensionIsOdd = edgemask->GetLargestPossibleRegion().GetSize()[0] % 2 == 1; CVImageType::Pointer InvTwoMuPlusGamma = ComputeInvTwoMuPlusGamma(edgemask,gam); //FloatImageType::Pointer SqrtMu = ComputeSqrtMu(edgemask); #define USE_BLAS_WRAPPERS #ifdef USE_BLAS_WRAPPERS #else typedef itk::AddImageFilter<CVImageType,CVImageType> CVImageAdder; CVImageAdder::Pointer dxPlusL = CVImageAdder::New(); #endif itk::TimeProbe tp; tp.Start(); HalfHermetianImageType::Pointer tempRatioFC = CreateEmptyImage<HalfHermetianImageType>(DtDhat); for (size_t i=0; i < Niter; ++i) { std::cout << "Iteration : " << i << std::endl; #ifdef USE_BLAS_WRAPPERS //Z = 1.0*L+DX AddAllElements(DX,1.0F,L,DX,gam);//DX destroyed CVImageType::Pointer & Z = DX; #else //Z = opII(Z,DX,'+',L); dxPlusL->SetInput1(DX); dxPlusL->SetInput2(L); dxPlusL->SetInPlace(true); dxPlusL->Update(); CVImageType::Pointer Z=dxPlusL->GetOutput(); MultiplyCVByScalar(Z,gam); #endif #ifdef USE_BLAS_WRAPPERS //Y=InvTwoMuPlusGamm.*Z MultiplyVectors(Y,InvTwoMuPlusGamma,Z); #else Y = opII(Y,Z,'*',InvTwoMuPlusGamma); #endif // X Subprob // Numerator = 2*Atb+lambda*gam*SRdiv(Y-L)) #ifdef USE_BLAS_WRAPPERS //YminusL = 1.0F* SRdiv( -1.0F*L + Y) Duplicate(Y,YminusL); AddAllElements(YminusL,-1.0F,L,YminusL,1.0F); #else YminusL=opII(YminusL,Y,'-',L); #endif FloatImageType::Pointer tempNumerator=GetDivergence(YminusL); #ifdef USE_BLAS_WRAPPERS //lambd*gam*tempNumerator+TwoAtb Duplicate(TwoAtb,tempValue); AddAllElements(tempValue,lambda*gam,tempNumerator,tempValue,1.0F); HalfHermetianImageType::Pointer tempNumeratorFC = GetForwardFFT(tempValue); #else tempNumerator=opIC(tempNumerator,lambda*gam,'*',tempNumerator); tempNumerator=opII(tempNumerator,TwoAtb,'+',tempNumerator); HalfHermetianImageType::Pointer tempNumeratorFC = GetForwardFFT(tempNumerator); #endif //KEEP tempRatioFC = opII_scalar(tempRatioFC,tempNumeratorFC,'/',TwoTimesAtAhatPlusLamGamDtDhat); X = GetInverseFFT(tempRatioFC,edgemask_ActualXDimensionIsOdd,1.0); //TODO: Determine scale factor here. X // should be on same dynamic range as b DX = GetGradient(X); residue = opII(residue, DX, '-', Y); //TODO: Implement math graph output here L = opII(L,L,'+',residue); // resvec[i] = 0; //TODO: Figure out the math for here if ( i > 900000 ) { tp.Stop(); std::cout << " Only iterations " << tp.GetTotal() << tp.GetUnit() << std::endl; return X; } if( i > 99 ) //HACK: Cutting this function short { return X; } //WDX = opII_CVmult(WDX,SqrtMu,'*',DX); //diff = opII(diff,A_fhp(X,norm01_lowres.GetPointer()),'-',b_FC); // //cost[i] = 0; //TODO: Need to figure out math for here } return X; }
static HalfHermetianImageType::Pointer GetAFP_of_b(FloatImageType::Pointer norm01_lowres, FloatImageType::Pointer edgemask) { FloatImageType::Pointer upsampledB = IdentityResampleByFFT(norm01_lowres, edgemask.GetPointer()); HalfHermetianImageType::Pointer b_FC = A_fhp(upsampledB, norm01_lowres.GetPointer()); return b_FC; }
bool AcceptMatch(VertexDescriptorType target, VertexDescriptorType source, float& computedEnergy) const override { itk::Index<2> targetPixel = ITKHelpers::CreateIndex(target); itk::ImageRegion<2> targetRegion = ITKHelpers::GetRegionInRadiusAroundPixel(targetPixel, HalfWidth); itk::Index<2> sourcePixel = ITKHelpers::CreateIndex(source); itk::ImageRegion<2> sourceRegion = ITKHelpers::GetRegionInRadiusAroundPixel(sourcePixel, HalfWidth); typedef itk::Image<float, 2> FloatImageType; typedef itk::VectorMagnitudeImageFilter<TImage, FloatImageType> VectorMagnitudeFilterType; typename VectorMagnitudeFilterType::Pointer magnitudeFilter = VectorMagnitudeFilterType::New(); magnitudeFilter->SetInput(Image); magnitudeFilter->Update(); std::vector<itk::Offset<2> > validOffsets = MaskImage->GetValidOffsetsInRegion(targetRegion); FloatImageType::Pointer sourceImage = FloatImageType::New(); // sourceImage->SetRegions(ITKHelpers::CornerRegion(sourceRegion.GetSize())); // sourceImage->Allocate(); ITKHelpers::ExtractRegion(magnitudeFilter->GetOutput(), sourceRegion, sourceImage.GetPointer()); FloatImageType::Pointer targetImage = FloatImageType::New(); // sourceImage->SetRegions(ITKHelpers::CornerRegion(targetRegion.GetSize())); // sourceImage->Allocate(); ITKHelpers::ExtractRegion(magnitudeFilter->GetOutput(), targetRegion, targetImage.GetPointer()); std::vector<itk::Index<2> > validIndices = ITKHelpers::OffsetsToIndices(validOffsets); VarianceFunctor varianceFunctor; AverageFunctor averageFunctor; /////////// Target region ////////// std::vector<FloatImageType::PixelType> validPixelsTargetRegion = ITKHelpers::GetPixelValues(targetImage.GetPointer(), validIndices); typename TypeTraits<FloatImageType::PixelType>::LargerType targetMean = averageFunctor(validPixelsTargetRegion); typename TypeTraits<FloatImageType::PixelType>::LargerType targetStandardDeviation = sqrt(varianceFunctor(validPixelsTargetRegion)); typedef itk::AddImageFilter <FloatImageType, FloatImageType, FloatImageType> AddImageFilterType; AddImageFilterType::Pointer targetAddImageFilter = AddImageFilterType::New(); targetAddImageFilter->SetInput(targetImage); targetAddImageFilter->SetConstant2(-1.0f * targetMean); targetAddImageFilter->Update(); typedef itk::MultiplyImageFilter<FloatImageType, FloatImageType, FloatImageType> MultiplyImageFilterType; MultiplyImageFilterType::Pointer targetMultiplyImageFilter = MultiplyImageFilterType::New(); targetMultiplyImageFilter->SetInput(targetImage); targetMultiplyImageFilter->SetConstant(1.0f/targetStandardDeviation); targetMultiplyImageFilter->Update(); /////////// Source region ////////// std::vector<FloatImageType::PixelType> validPixelsSourceRegion = ITKHelpers::GetPixelValues(sourceImage.GetPointer(), validIndices); typename TypeTraits<FloatImageType::PixelType>::LargerType sourceMean = averageFunctor(validPixelsSourceRegion); typename TypeTraits<FloatImageType::PixelType>::LargerType sourceStandardDeviation = sqrt(varianceFunctor(validPixelsSourceRegion)); AddImageFilterType::Pointer sourceAddImageFilter = AddImageFilterType::New(); sourceAddImageFilter->SetInput(sourceImage); sourceAddImageFilter->SetConstant2(-1.0f * sourceMean); sourceAddImageFilter->Update(); MultiplyImageFilterType::Pointer sourceMultiplyImageFilter = MultiplyImageFilterType::New(); sourceMultiplyImageFilter->SetInput(sourceImage); sourceMultiplyImageFilter->SetConstant(1.0f/sourceStandardDeviation); sourceMultiplyImageFilter->Update(); // Initialize computedEnergy = 0.0f; for(std::vector<itk::Index<2> >::const_iterator iter = validIndices.begin(); iter != validIndices.end(); ++iter) { computedEnergy += (sourceMultiplyImageFilter->GetOutput()->GetPixel(*iter) * targetMultiplyImageFilter->GetOutput()->GetPixel(*iter)); } computedEnergy /= static_cast<float>(validIndices.size()); if(computedEnergy < Threshold) { std::cout << this->VisitorName << ": Match accepted (" << computedEnergy << " is less than " << Threshold << ")" << std::endl << std::endl; return true; } else { std::cout << this->VisitorName << ": Match rejected (" << computedEnergy << " is greater than " << Threshold << ")" << std::endl << std::endl; return false; } };