void FiniteDiffOdfMaximaExtractionFilter< PixelType, ShOrder, NrOdfDirections>
::ThreadedGenerateData( const OutputImageRegionType& outputRegionForThread, ThreadIdType threadID )
{
    typename CoefficientImageType::Pointer ShCoeffImage = static_cast< CoefficientImageType* >( this->ProcessObject::GetInput(0) );

    ImageRegionConstIterator< CoefficientImageType > cit(ShCoeffImage, outputRegionForThread );

    OdfType odf;
    while( !cit.IsAtEnd() )
    {
        typename CoefficientImageType::IndexType index = cit.GetIndex();
        if (m_MaskImage->GetPixel(index)==0)
        {
            ++cit;
            continue;
        }

        CoefficientPixelType c = cit.Get();

        // calculate ODF
        double max = 0;
        odf.Fill(0.0);
        for (int i=0; i<NrOdfDirections; i++)
        {
            for (int j=0; j<m_NumCoeffs; j++)
                odf[i] += c[j]*m_ShBasis(i,j);
            if (odf[i]>max)
                max = odf[i];
        }
        if (max<0.0001)
        {
            ++cit;
            continue;
        }

        std::vector< DirectionType > candidates, peaks, temp;
        peaks.clear();
        max *= m_PeakThreshold;                         // relative threshold
        FindCandidatePeaks(odf, max, candidates);       // find all local maxima
        candidates = MeanShiftClustering(candidates);   // cluster maxima

        vnl_matrix< double > shBasis, sphCoords;
        Cart2Sph(candidates, sphCoords);                // convert candidate peaks to spherical angles
        shBasis = CalcShBasis(sphCoords);            // evaluate spherical harmonics at each peak
        max = 0.0;
        for (unsigned int i=0; i<candidates.size(); i++)         // scale peaks according to ODF value
        {
            double val = 0;
            for (int j=0; j<m_NumCoeffs; j++)
                val += c[j]*shBasis(i,j);
            if (val>max)
                max = val;
            peaks.push_back(candidates[i]*val);
        }
        std::sort( peaks.begin(), peaks.end(), CompareVectors );  // sort peaks

        // kick out directions to close to a larger direction (too far away to cluster but too close to keep)
        unsigned int m = peaks.size();
        if ( m>m_DirectionImageContainer->Size() )
            m = m_DirectionImageContainer->Size();
        for (unsigned int i=0; i<m; i++)
        {
            DirectionType v1 = peaks.at(i);
            double val = v1.magnitude();
            if (val<max*m_PeakThreshold || val<m_AbsolutePeakThreshold)
                break;

            bool flag = true;
            for (unsigned int j=0; j<peaks.size(); j++)
                if (i!=j)
                {
                    DirectionType v2 = peaks.at(j);
                    double val2 = v2.magnitude();
                    double angle = fabs(dot_product(v1,v2)/(val*val2));
                    if (angle>m_AngularThreshold && val<val2)
                    {
                        flag = false;
                        break;
                    }
                }

            if (flag)
                temp.push_back(v1);
        }
        peaks = temp;

        // fill output image
        unsigned int num = peaks.size();
        if ( num>m_DirectionImageContainer->Size() )
            num = m_DirectionImageContainer->Size();
        for (unsigned int i=0; i<num; i++)
        {
            vnl_vector<double> dir = peaks.at(i);

            ItkDirectionImage::Pointer img = m_DirectionImageContainer->GetElement(i);

            switch (m_NormalizationMethod)
            {
            case NO_NORM:
                break;
            case SINGLE_VEC_NORM:
                dir.normalize();
                break;
            case MAX_VEC_NORM:
                dir /= max;
                break;
            }

            dir = m_MaskImage->GetDirection()*dir;
            itk::Vector< float, 3 > pixel;
            pixel.SetElement(0, -dir[0]);
            pixel.SetElement(1, dir[1]);
            pixel.SetElement(2, dir[2]);
            img->SetPixel(index, pixel);
        }
        m_NumDirectionsImage->SetPixel(index, num);
        ++cit;
    }
    MITK_INFO << "Thread " << threadID << " finished extraction";
}
void FiniteDiffOdfMaximaExtractionFilter< PixelType, ShOrder, NrOdfDirections>
::BeforeThreadedGenerateData()
{
    typename CoefficientImageType::Pointer ShCoeffImage = static_cast< CoefficientImageType* >( this->ProcessObject::GetInput(0) );
    itk::Vector<double,3> spacing = ShCoeffImage->GetSpacing();
    double minSpacing = spacing[0];
    if (spacing[1]<minSpacing)
        minSpacing = spacing[1];
    if (spacing[2]<minSpacing)
        minSpacing = spacing[2];

    mitk::Point3D origin = ShCoeffImage->GetOrigin();
    itk::Matrix<double, 3, 3> direction = ShCoeffImage->GetDirection();
    ImageRegion<3> imageRegion = ShCoeffImage->GetLargestPossibleRegion();

    if (m_MaskImage.IsNotNull())
    {
        origin = m_MaskImage->GetOrigin();
        direction = m_MaskImage->GetDirection();
        imageRegion = m_MaskImage->GetLargestPossibleRegion();
    }

    m_DirectionImageContainer = ItkDirectionImageContainer::New();
    for (unsigned int i=0; i<m_MaxNumPeaks; i++)
    {
        itk::Vector< float, 3 > nullVec; nullVec.Fill(0.0);
        ItkDirectionImage::Pointer img = ItkDirectionImage::New();
        img->SetSpacing( spacing );
        img->SetOrigin( origin );
        img->SetDirection( direction );
        img->SetRegions( imageRegion );
        img->Allocate();
        img->FillBuffer(nullVec);
        m_DirectionImageContainer->InsertElement(m_DirectionImageContainer->Size(), img);
    }
    if (m_MaskImage.IsNull())
    {
        m_MaskImage = ItkUcharImgType::New();
        m_MaskImage->SetSpacing( spacing );
        m_MaskImage->SetOrigin( origin );
        m_MaskImage->SetDirection( direction );
        m_MaskImage->SetRegions( imageRegion );
        m_MaskImage->Allocate();
        m_MaskImage->FillBuffer(1);
    }
    m_NumDirectionsImage = ItkUcharImgType::New();
    m_NumDirectionsImage->SetSpacing( spacing );
    m_NumDirectionsImage->SetOrigin( origin );
    m_NumDirectionsImage->SetDirection( direction );
    m_NumDirectionsImage->SetRegions( imageRegion );
    m_NumDirectionsImage->Allocate();
    m_NumDirectionsImage->FillBuffer(0);

    this->SetNumberOfIndexedOutputs(m_MaxNumPeaks);

    // calculate SH basis
    OdfType odf;
    vnl_matrix_fixed<double, 3, NrOdfDirections>* directions = odf.GetDirections();
    vnl_matrix< double > sphCoords;
    std::vector< DirectionType > dirs;
    for (int i=0; i<NrOdfDirections; i++)
        dirs.push_back(directions->get_column(i));
    Cart2Sph(dirs, sphCoords);                          // convert candidate peaks to spherical angles
    m_ShBasis = CalcShBasis(sphCoords);                // evaluate spherical harmonics at each peak

    MITK_INFO << "Starting finite differences maximum extraction";
    MITK_INFO << "ODF sampling points: " << NrOdfDirections;
    MITK_INFO << "SH order: " << ShOrder;
    MITK_INFO << "Maximum peaks: " << m_MaxNumPeaks;
    MITK_INFO << "Relative threshold: " << m_PeakThreshold;
    MITK_INFO << "Absolute threshold: " << m_AbsolutePeakThreshold;
    MITK_INFO << "Clustering threshold: " << m_ClusteringThreshold;
    MITK_INFO << "Angular threshold: " << m_AngularThreshold;
}
void FiniteDiffOdfMaximaExtractionFilter< PixelType, ShOrder, NrOdfDirections>
::AfterThreadedGenerateData()
{
    MITK_INFO << "Generating vector field";
    vtkSmartPointer<vtkCellArray> m_VtkCellArray = vtkSmartPointer<vtkCellArray>::New();
    vtkSmartPointer<vtkPoints>    m_VtkPoints = vtkSmartPointer<vtkPoints>::New();

    typename CoefficientImageType::Pointer ShCoeffImage = static_cast< CoefficientImageType* >( this->ProcessObject::GetInput(0) );
    ImageRegionConstIterator< CoefficientImageType > cit(ShCoeffImage, ShCoeffImage->GetLargestPossibleRegion() );

    mitk::Vector3D spacing = ShCoeffImage->GetSpacing();
    double minSpacing = spacing[0];
    if (spacing[1]<minSpacing)
        minSpacing = spacing[1];
    if (spacing[2]<minSpacing)
        minSpacing = spacing[2];

    int maxProgress = ShCoeffImage->GetLargestPossibleRegion().GetSize()[0]*ShCoeffImage->GetLargestPossibleRegion().GetSize()[1]*ShCoeffImage->GetLargestPossibleRegion().GetSize()[2];
    boost::progress_display disp(maxProgress);

    while( !cit.IsAtEnd() )
    {
        ++disp;

        typename CoefficientImageType::IndexType index = cit.GetIndex();
        if (m_MaskImage->GetPixel(index)==0)
        {
            ++cit;
            continue;
        }

        for (unsigned int i=0; i<m_DirectionImageContainer->Size(); i++)
        {
            ItkDirectionImage::Pointer img = m_DirectionImageContainer->GetElement(i);
            itk::Vector< float, 3 > pixel = img->GetPixel(index);
            DirectionType dir; dir[0] = pixel[0]; dir[1] = pixel[1]; dir[2] = pixel[2];

            vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New();
            itk::ContinuousIndex<double, 3> center;
            center[0] = index[0];
            center[1] = index[1];
            center[2] = index[2];
            itk::Point<double> worldCenter;
            m_MaskImage->TransformContinuousIndexToPhysicalPoint( center, worldCenter );

            itk::Point<double> worldStart;
            worldStart[0] = worldCenter[0]-dir[0]/2 * minSpacing;
            worldStart[1] = worldCenter[1]-dir[1]/2 * minSpacing;
            worldStart[2] = worldCenter[2]-dir[2]/2 * minSpacing;
            vtkIdType id = m_VtkPoints->InsertNextPoint(worldStart.GetDataPointer());
            container->GetPointIds()->InsertNextId(id);
            itk::Point<double> worldEnd;
            worldEnd[0] = worldCenter[0]+dir[0]/2 * minSpacing;
            worldEnd[1] = worldCenter[1]+dir[1]/2 * minSpacing;
            worldEnd[2] = worldCenter[2]+dir[2]/2 * minSpacing;
            id = m_VtkPoints->InsertNextPoint(worldEnd.GetDataPointer());
            container->GetPointIds()->InsertNextId(id);
            m_VtkCellArray->InsertNextCell(container);
        }
        ++cit;
    }

    vtkSmartPointer<vtkPolyData> directionsPolyData = vtkSmartPointer<vtkPolyData>::New();
    directionsPolyData->SetPoints(m_VtkPoints);
    directionsPolyData->SetLines(m_VtkCellArray);
    m_OutputFiberBundle = mitk::FiberBundle::New(directionsPolyData);

    for (unsigned int i=0; i<m_DirectionImageContainer->Size(); i++)
    {
        ItkDirectionImage::Pointer img = m_DirectionImageContainer->GetElement(i);
        this->SetNthOutput(i, img);
    }
}
Exemplo n.º 4
0
void DwiPhantomGenerationFilter< TOutputScalarType >
::GenerateData()
{
    if (m_NoiseVariance < 0)
        m_NoiseVariance = 0.001;

    if (!m_SimulateBaseline)
    {
        MITK_INFO << "Baseline image values are set to default. Noise variance value is treated as SNR!";
        if (m_NoiseVariance <= 0)
            m_NoiseVariance = 0.0001;
        if (m_NoiseVariance>99)
            m_NoiseVariance = 0;
        else
        {
            m_NoiseVariance = m_DefaultBaseline/(m_NoiseVariance*m_SignalScale);
            m_NoiseVariance *= m_NoiseVariance;
        }
    }

    m_RandGen = Statistics::MersenneTwisterRandomVariateGenerator::New();
    m_RandGen->SetSeed();

    typename OutputImageType::Pointer outImage = OutputImageType::New();
    outImage->SetSpacing( m_Spacing );
    outImage->SetOrigin( m_Origin );
    outImage->SetDirection( m_DirectionMatrix );
    outImage->SetLargestPossibleRegion( m_ImageRegion );
    outImage->SetBufferedRegion( m_ImageRegion );
    outImage->SetRequestedRegion( m_ImageRegion );
    outImage->SetVectorLength(m_GradientList.size());
    outImage->Allocate();
    typename OutputImageType::PixelType pix;
    pix.SetSize(m_GradientList.size());
    pix.Fill(0.0);
    outImage->FillBuffer(pix);
    this->SetNthOutput (0, outImage);

    double minSpacing = m_Spacing[0];
    if (m_Spacing[1]<minSpacing)
        minSpacing = m_Spacing[1];
    if (m_Spacing[2]<minSpacing)
        minSpacing = m_Spacing[2];

    m_DirectionImageContainer = ItkDirectionImageContainer::New();
    for (int i=0; i<m_SignalRegions.size(); i++)
    {
        itk::Vector< float, 3 > nullVec; nullVec.Fill(0.0);
        ItkDirectionImage::Pointer img = ItkDirectionImage::New();
        img->SetSpacing( m_Spacing );
        img->SetOrigin( m_Origin );
        img->SetDirection( m_DirectionMatrix );
        img->SetRegions( m_ImageRegion );
        img->Allocate();
        img->FillBuffer(nullVec);
        m_DirectionImageContainer->InsertElement(m_DirectionImageContainer->Size(), img);
    }
    m_NumDirectionsImage = ItkUcharImgType::New();
    m_NumDirectionsImage->SetSpacing( m_Spacing );
    m_NumDirectionsImage->SetOrigin( m_Origin );
    m_NumDirectionsImage->SetDirection( m_DirectionMatrix );
    m_NumDirectionsImage->SetRegions( m_ImageRegion );
    m_NumDirectionsImage->Allocate();
    m_NumDirectionsImage->FillBuffer(0);

    m_SNRImage = ItkFloatImgType::New();
    m_SNRImage->SetSpacing( m_Spacing );
    m_SNRImage->SetOrigin( m_Origin );
    m_SNRImage->SetDirection( m_DirectionMatrix );
    m_SNRImage->SetRegions( m_ImageRegion );
    m_SNRImage->Allocate();
    m_SNRImage->FillBuffer(0);

    vtkSmartPointer<vtkCellArray> m_VtkCellArray = vtkSmartPointer<vtkCellArray>::New();
    vtkSmartPointer<vtkPoints>    m_VtkPoints = vtkSmartPointer<vtkPoints>::New();

    m_BaselineImages = 0;
    for( unsigned int i=0; i<m_GradientList.size(); i++)
        if (m_GradientList[i].GetNorm()<=0.0001)
            m_BaselineImages++;

    typedef ImageRegionIterator<OutputImageType>      IteratorOutputType;
    IteratorOutputType it (outImage, m_ImageRegion);

    // isotropic tensor
    itk::DiffusionTensor3D<float> isoTensor;
    isoTensor.Fill(0);
    float e1 = m_GreyMatterAdc;
    float e2 = m_GreyMatterAdc;
    float e3 = m_GreyMatterAdc;
    isoTensor.SetElement(0,e1);
    isoTensor.SetElement(3,e2);
    isoTensor.SetElement(5,e3);
    m_MaxBaseline = GetTensorL2Norm(isoTensor);

    GenerateTensors();

    // simulate measurement
    m_MeanBaseline = 0;
    double noiseStdev = sqrt(m_NoiseVariance);
    while(!it.IsAtEnd())
    {
        pix = it.Get();
        typename OutputImageType::IndexType index = it.GetIndex();

        int numDirs = 0;
        for (int i=0; i<m_SignalRegions.size(); i++)
        {
            ItkUcharImgType::Pointer region = m_SignalRegions.at(i);

            if (region->GetPixel(index)!=0)
            {
                numDirs++;
                pix += SimulateMeasurement(m_TensorList[i], m_TensorWeight[i]);

                // set direction image pixel
                ItkDirectionImage::Pointer img = m_DirectionImageContainer->GetElement(i);
                itk::Vector< float, 3 > pixel = img->GetPixel(index);
                vnl_vector_fixed<double, 3> dir = m_TensorDirection.at(i);
                dir.normalize();
                dir *= m_TensorWeight.at(i);
                pixel.SetElement(0, dir[0]);
                pixel.SetElement(1, dir[1]);
                pixel.SetElement(2, dir[2]);
                img->SetPixel(index, pixel);

                vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New();
                itk::ContinuousIndex<double, 3> center;
                center[0] = index[0];
                center[1] = index[1];
                center[2] = index[2];
                itk::Point<double> worldCenter;
                outImage->TransformContinuousIndexToPhysicalPoint( center, worldCenter );
                itk::Point<double> worldStart;
                worldStart[0] = worldCenter[0]-dir[0]/2 * minSpacing;
                worldStart[1] = worldCenter[1]-dir[1]/2 * minSpacing;
                worldStart[2] = worldCenter[2]-dir[2]/2 * minSpacing;
                vtkIdType id = m_VtkPoints->InsertNextPoint(worldStart.GetDataPointer());
                container->GetPointIds()->InsertNextId(id);
                itk::Point<double> worldEnd;
                worldEnd[0] = worldCenter[0]+dir[0]/2 * minSpacing;
                worldEnd[1] = worldCenter[1]+dir[1]/2 * minSpacing;
                worldEnd[2] = worldCenter[2]+dir[2]/2 * minSpacing;
                id = m_VtkPoints->InsertNextPoint(worldEnd.GetDataPointer());
                container->GetPointIds()->InsertNextId(id);
                m_VtkCellArray->InsertNextCell(container);
            }
        }

        if (numDirs>1)
        {
            for (int i=0; i<m_GradientList.size(); i++)
                pix[i] /= numDirs;
        }
        else if (numDirs==0)
        {
            if (m_SimulateBaseline)
                pix = SimulateMeasurement(isoTensor, 1.0);
            else
                pix.Fill(0.0);
        }

        m_MeanBaseline += pix[0];
        it.Set(pix);
        m_NumDirectionsImage->SetPixel(index, numDirs);
        if (m_NoiseVariance>0)
            m_SNRImage->SetPixel(index, pix[0]/(noiseStdev*m_SignalScale));
        ++it;
    }
    m_MeanBaseline /= m_ImageRegion.GetNumberOfPixels();
    if (m_NoiseVariance>0)
        MITK_INFO << "Mean SNR: " << m_MeanBaseline/(noiseStdev*m_SignalScale);
    else
        MITK_INFO << "No noise added";

    // add rician noise
    it.GoToBegin();
    while(!it.IsAtEnd())
    {
        pix = it.Get();
        AddNoise(pix);
        it.Set(pix);
        ++it;
    }

    // generate fiber bundle
    vtkSmartPointer<vtkPolyData> directionsPolyData = vtkSmartPointer<vtkPolyData>::New();
    directionsPolyData->SetPoints(m_VtkPoints);
    directionsPolyData->SetLines(m_VtkCellArray);
    m_OutputFiberBundle = mitk::FiberBundleX::New(directionsPolyData);
}