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 idx3 = cit.GetIndex();
    if (m_MaskImage->GetPixel(idx3)==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> sphCoords;
    CreateDirMatrix(candidates, sphCoords);                // convert candidate peaks to spherical angles
    vnl_matrix< float > shBasis;
    if (m_Toolkit==Toolkit::MRTRIX)
      shBasis = mitk::sh::CalcShBasisForDirections(ShOrder, sphCoords);
    else
      shBasis = mitk::sh::CalcShBasisForDirections(ShOrder, sphCoords, false);

    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_MaxNumPeaks )
      m = m_MaxNumPeaks;
    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;

    itk::Index<4> idx4; idx4[0] = idx3[0]; idx4[1] = idx3[1]; idx4[2] = idx3[2];

    // fill output image
    unsigned int num = peaks.size();
    if ( num>m_MaxNumPeaks )
      num = m_MaxNumPeaks;
    for (unsigned int i=0; i<num; i++)
    {
      DirectionType dir = peaks.at(i);
      switch (m_NormalizationMethod)
      {
      case NO_NORM:
        break;
      case SINGLE_VEC_NORM:
        dir.normalize();
        break;
      case MAX_VEC_NORM:
        dir /= max;
        break;
      }

      if (m_ApplyDirectionMatrix)
        dir = m_MaskImage->GetDirection()*dir;

      if (m_FlipX)
        dir[0] = -dir[0];
      if (m_FlipY)
        dir[1] = -dir[1];
      if (m_FlipZ)
        dir[2] = -dir[2];

      for (unsigned int j = 0; j<3; j++)
      {
        idx4[3] = i*3 + j;
        m_PeakImage->SetPixel(idx4, dir[j]);
      }
    }
    m_NumDirectionsImage->SetPixel(idx3, num);
    ++cit;
  }
  MITK_INFO << "Thread " << threadID << " finished extraction";
}
Пример #2
0
void TractsToVectorImageFilter< PixelType >::GenerateData()
{
  mitk::BaseGeometry::Pointer geometry = m_FiberBundle->GetGeometry();

  // calculate new image parameters
  itk::Vector<double> spacing3;
  itk::Point<double> origin3;
  itk::Matrix<double, 3, 3> direction3;
  ImageRegion<3> imageRegion3;
  if (!m_MaskImage.IsNull())
  {
    spacing3 = m_MaskImage->GetSpacing();
    imageRegion3 = m_MaskImage->GetLargestPossibleRegion();
    origin3 = m_MaskImage->GetOrigin();
    direction3 = m_MaskImage->GetDirection();
  }
  else
  {
    spacing3 = geometry->GetSpacing();
    origin3 = geometry->GetOrigin();
    mitk::BaseGeometry::BoundsArrayType bounds = geometry->GetBounds();
    origin3[0] += bounds.GetElement(0);
    origin3[1] += bounds.GetElement(2);
    origin3[2] += bounds.GetElement(4);

    for (int i=0; i<3; i++)
      for (int j=0; j<3; j++)
        direction3[j][i] = geometry->GetMatrixColumn(i)[j];
    imageRegion3.SetSize(0, geometry->GetExtent(0)+1);
    imageRegion3.SetSize(1, geometry->GetExtent(1)+1);
    imageRegion3.SetSize(2, geometry->GetExtent(2)+1);


    m_MaskImage = ItkUcharImgType::New();
    m_MaskImage->SetSpacing( spacing3 );
    m_MaskImage->SetOrigin( origin3 );
    m_MaskImage->SetDirection( direction3 );
    m_MaskImage->SetRegions( imageRegion3 );
    m_MaskImage->Allocate();
    m_MaskImage->FillBuffer(1);
  }
  OutputImageType::RegionType::SizeType outImageSize = imageRegion3.GetSize();
  m_OutImageSpacing = m_MaskImage->GetSpacing();
  m_ClusteredDirectionsContainer = ContainerType::New();

  // initialize num directions image
  m_NumDirectionsImage = ItkUcharImgType::New();
  m_NumDirectionsImage->SetSpacing( spacing3 );
  m_NumDirectionsImage->SetOrigin( origin3 );
  m_NumDirectionsImage->SetDirection( direction3 );
  m_NumDirectionsImage->SetRegions( imageRegion3 );
  m_NumDirectionsImage->Allocate();
  m_NumDirectionsImage->FillBuffer(0);

  itk::Vector<double, 4> spacing4;
  itk::Point<float, 4> origin4;
  itk::Matrix<double, 4, 4> direction4;
  itk::ImageRegion<4> imageRegion4;

  spacing4[0] = spacing3[0]; spacing4[1] = spacing3[1]; spacing4[2] = spacing3[2]; spacing4[3] = 1;
  origin4[0] = origin3[0]; origin4[1] = origin3[1]; origin4[2] = origin3[2]; origin3[3] = 0;
  for (int r=0; r<3; r++)
    for (int c=0; c<3; c++)
      direction4[r][c] = direction3[r][c];
  direction4[3][3] = 1;
  imageRegion4.SetSize(0, imageRegion3.GetSize()[0]);
  imageRegion4.SetSize(1, imageRegion3.GetSize()[1]);
  imageRegion4.SetSize(2, imageRegion3.GetSize()[2]);
  imageRegion4.SetSize(3, m_MaxNumDirections*3);

  m_DirectionImage = ItkDirectionImageType::New();
  m_DirectionImage->SetSpacing( spacing4 );
  m_DirectionImage->SetOrigin( origin4 );
  m_DirectionImage->SetDirection( direction4 );
  m_DirectionImage->SetRegions( imageRegion4 );
  m_DirectionImage->Allocate();
  m_DirectionImage->FillBuffer(0.0);

  // iterate over all fibers
  vtkSmartPointer<vtkPolyData> fiberPolyData = m_FiberBundle->GetFiberPolyData();
  int numFibers = m_FiberBundle->GetNumFibers();
  m_DirectionsContainer = ContainerType::New();

  VectorContainer< unsigned int, std::vector< double > >::Pointer peakLengths = VectorContainer< unsigned int, std::vector< double > >::New();

  MITK_INFO << "Generating directions from tractogram";
  boost::progress_display disp(numFibers);
  for( int i=0; i<numFibers; i++ )
  {
    ++disp;
    vtkCell* cell = fiberPolyData->GetCell(i);
    int numPoints = cell->GetNumberOfPoints();
    vtkPoints* points = cell->GetPoints();
    if (numPoints<2)
      continue;

    vnl_vector_fixed<double, 3> dir;
    vnl_vector<double> v;

    float fiberWeight = m_FiberBundle->GetFiberWeight(i);

    for( int j=0; j<numPoints-1; j++)
    {
      itk::Point<float, 3> startVertex = mitk::imv::GetItkPoint(points->GetPoint(j));
      itk::Index<3> startIndex;
      itk::ContinuousIndex<float, 3> startIndexCont;
      m_MaskImage->TransformPhysicalPointToIndex(startVertex, startIndex);
      m_MaskImage->TransformPhysicalPointToContinuousIndex(startVertex, startIndexCont);

      itk::Point<float, 3> endVertex = mitk::imv::GetItkPoint(points->GetPoint(j + 1));
      itk::Index<3> endIndex;
      itk::ContinuousIndex<float, 3> endIndexCont;
      m_MaskImage->TransformPhysicalPointToIndex(endVertex, endIndex);
      m_MaskImage->TransformPhysicalPointToContinuousIndex(endVertex, endIndexCont);

      dir[0] = endVertex[0]-startVertex[0];
      dir[1] = endVertex[1]-startVertex[1];
      dir[2] = endVertex[2]-startVertex[2];
      if (dir.is_zero())
        continue;
      dir.normalize();

      std::vector< std::pair< itk::Index<3>, double > > segments = mitk::imv::IntersectImage(spacing3, startIndex, endIndex, startIndexCont, endIndexCont);
      for (std::pair< itk::Index<3>, double > segment : segments)
      {
        if (!m_MaskImage->GetLargestPossibleRegion().IsInside(segment.first) || (!m_OnlyUseMaskGeometry && m_MaskImage->GetPixel(segment.first)==0))
          continue;

        // add direction to container
        unsigned int idx = segment.first[0] + outImageSize[0]*(segment.first[1] + outImageSize[1]*segment.first[2]);
        DirectionContainerType::Pointer dirCont;
        if (m_DirectionsContainer->IndexExists(idx))
        {
          peakLengths->ElementAt(idx).push_back(fiberWeight*segment.second);

          dirCont = m_DirectionsContainer->GetElement(idx);
          if (dirCont.IsNull())
          {
            dirCont = DirectionContainerType::New();
            dirCont->push_back(dir);
            m_DirectionsContainer->InsertElement(idx, dirCont);
          }
          else
            dirCont->push_back(dir);
        }
        else
        {
          dirCont = DirectionContainerType::New();
          dirCont->push_back(dir);
          m_DirectionsContainer->InsertElement(idx, dirCont);

          std::vector< double > lengths; lengths.push_back(fiberWeight*segment.second);
          peakLengths->InsertElement(idx, lengths);
        }
      }

    }
  }

  itk::ImageRegionIterator<ItkUcharImgType> dirIt(m_NumDirectionsImage, m_NumDirectionsImage->GetLargestPossibleRegion());

  MITK_INFO << "Clustering directions";
  float max_dir_mag = 0;
  boost::progress_display disp2(outImageSize[0]*outImageSize[1]*outImageSize[2]);
  while(!dirIt.IsAtEnd())
  {
    ++disp2;
    OutputImageType::IndexType idx3 = dirIt.GetIndex();
    int idx_lin = idx3[0]+(idx3[1]+idx3[2]*outImageSize[1])*outImageSize[0];

    itk::Index<4> idx4; idx4[0] = idx3[0]; idx4[1] = idx3[1]; idx4[2] = idx3[2];

    if (!m_DirectionsContainer->IndexExists(idx_lin))
    {
      ++dirIt;
      continue;
    }
    DirectionContainerType::Pointer dirCont = m_DirectionsContainer->GetElement(idx_lin);
    if (dirCont.IsNull() || dirCont->empty())
    {
      ++dirIt;
      continue;
    }

    DirectionContainerType::Pointer directions;
    if (m_MaxNumDirections>0)
    {
      directions = FastClustering(dirCont, peakLengths->GetElement(idx_lin));
      std::sort( directions->begin(), directions->end(), CompareVectorLengths );
    }
    else
      directions = dirCont;

    unsigned int numDir = directions->size();
    if (m_MaxNumDirections>0 && numDir>m_MaxNumDirections)
      numDir = m_MaxNumDirections;

    float voxel_max_mag = 0;
    for (unsigned int i=0; i<numDir; i++)
    {
      DirectionType dir = directions->at(i);
      float mag = dir.magnitude();

      if (mag>voxel_max_mag)
        voxel_max_mag = mag;
      if (mag>max_dir_mag)
        max_dir_mag = mag;
    }

    int count = 0;
    for (unsigned int i=0; i<numDir; i++)
    {
      DirectionType dir = directions->at(i);
      count++;

      float mag = dir.magnitude();
      if (m_NormalizationMethod==MAX_VEC_NORM && voxel_max_mag>mitk::eps)
        dir /= voxel_max_mag;
      else if (m_NormalizationMethod==SINGLE_VEC_NORM && mag>mitk::eps)
        dir.normalize();

      for (unsigned int j = 0; j<3; j++)
      {
        idx4[3] = i*3 + j;
        m_DirectionImage->SetPixel(idx4, dir[j]);
      }
    }
    dirIt.Set(count);
    ++dirIt;
  }

  if (m_NormalizationMethod==GLOBAL_MAX && max_dir_mag>0)
  {
    itk::ImageRegionIterator<ItkDirectionImageType> dirImgIt(m_DirectionImage, m_DirectionImage->GetLargestPossibleRegion());
    while(!dirImgIt.IsAtEnd())
    {
      dirImgIt.Set(dirImgIt.Get()/max_dir_mag);
      ++dirImgIt;
    }
  }
}
Пример #3
0
itkPhilipsRECDataImageReader::FloatImageType::DirectionType
itkPhilipsRECDataImageReader::ExtractPARRECImageOrientation ()
{

    typedef FloatImageType::DirectionType DirectionType;

    DirectionType eyedir;
    eyedir.SetIdentity();
    if (!this->io->GetFileName())
    {
        dtkWarn() << "io doesn't have a filename, call readInformation first";
        return eyedir;
    }

    itk::MetaDataDictionary PARheader = this->io->GetMetaDataDictionary();

    typedef itk::PhilipsRECImageIO::AngulationMidSliceType AngulationType;

    AngulationType angulation;
    int sliceorientation = 0;

    bool valid = itk::ExposeMetaData<AngulationType>(PARheader, "PAR_AngulationMidSlice", angulation);
    if (!valid)
    {
        dtkWarn() <<"cannot find angulation in PAR header, no correction";
        return eyedir;
    }

    valid = itk::ExposeMetaData<int>(PARheader, "PAR_SliceOrientation", sliceorientation);
    if (!valid)
    {
        dtkWarn() << "cannot find slice orientation in PAR header, no correction";
        return eyedir;
    }

    DirectionType AFRtoLPS;
    AFRtoLPS.Fill (0);
    AFRtoLPS[0][2] = 1;
    AFRtoLPS[1][0] = 1;
    AFRtoLPS[2][1] = 1;

    DirectionType magicmatrix;
    magicmatrix.Fill (0);
    magicmatrix [0][0] = -1;
    magicmatrix [1][2] = 1;
    magicmatrix [2][1] = -1;

    DirectionType TRA;
    TRA.Fill (0);
    TRA [0][1] = 1;
    TRA [1][0] = -1;
    TRA [2][2] = -1;
    DirectionType SAG;
    SAG.Fill (0);
    SAG [0][0] = -1;
    SAG [1][2] = 1;
    SAG [2][1] = -1;
    DirectionType COR;
    COR.Fill (0);
    COR [0][1] = 1;
    COR [1][2] = 1;
    COR [2][0] = -1;


    DirectionType Torientation;

    switch(sliceorientation)
    {

    case PAR_SLICE_ORIENTATION_TRANSVERSAL:
        // Transverse - the REC data appears to be stored as right-left,
        // anterior-posterior, and inferior-superior.
        // Verified using a marker on right side of brain.
        Torientation = TRA;
        break;
    case PAR_SLICE_ORIENTATION_SAGITTAL:
        // Sagittal - the REC data appears to be stored as anterior-posterior,
        // superior-inferior, and right-left.
        // Verified using marker on right side of brain.
        Torientation = SAG;
        break;
    case PAR_SLICE_ORIENTATION_CORONAL:
        // Coronal - the REC data appears to be stored as right-left,
        // superior-inferior, and anterior-posterior.
        // Verified using marker on right side of brain.
        // fall thru
    default:
        Torientation = COR;

    }


    double ap = angulation[0] * vnl_math::pi / 180.0;
    double fh = angulation[1] * vnl_math::pi / 180.0;
    double rl = angulation[2] * vnl_math::pi / 180.0;

    DirectionType Tap;
    Tap.Fill (0);
    Tap[0][0] = 1;
    Tap[1][1] = std::cos (ap);
    Tap[1][2] = - std::sin (ap);
    Tap[2][1] = std::sin (ap);
    Tap[2][2] = std::cos (ap);

    DirectionType Tfh;
    Tfh.Fill (0);
    Tfh[1][1] = 1;
    Tfh[0][0] = std::cos (fh);
    Tfh[0][2] = std::sin (fh);
    Tfh[2][0] = - std::sin (fh);
    Tfh[2][2] = std::cos (fh);

    DirectionType Trl;
    Trl.Fill (0);
    Trl[2][2] = 1;
    Trl[0][0] = std::cos (rl);
    Trl[0][1] = - std::sin (rl);
    Trl[1][0] = std::sin (rl);
    Trl[1][1] = std::cos (rl);

    DirectionType TR = AFRtoLPS * Trl * Tap * Tfh * magicmatrix.GetTranspose() * Torientation.GetTranspose();
    DirectionType retval;
    retval.SetIdentity();

    for (unsigned int i=0; i<3; i++)
        for (unsigned int j=0; j<3; j++)
            retval[i][j] = TR[i][j];

    return retval;
}
void TractsToVectorImageFilter< PixelType >::GenerateData()
{
    mitk::BaseGeometry::Pointer geometry = m_FiberBundle->GetGeometry();

    // calculate new image parameters
    itk::Vector<double> spacing;
    itk::Point<double> origin;
    itk::Matrix<double, 3, 3> direction;
    ImageRegion<3> imageRegion;
    if (!m_MaskImage.IsNull())
    {
        spacing = m_MaskImage->GetSpacing();
        imageRegion = m_MaskImage->GetLargestPossibleRegion();
        origin = m_MaskImage->GetOrigin();
        direction = m_MaskImage->GetDirection();
    }
    else
    {
        spacing = geometry->GetSpacing();
        origin = geometry->GetOrigin();
        mitk::BaseGeometry::BoundsArrayType bounds = geometry->GetBounds();
        origin[0] += bounds.GetElement(0);
        origin[1] += bounds.GetElement(2);
        origin[2] += bounds.GetElement(4);

        for (int i=0; i<3; i++)
            for (int j=0; j<3; j++)
                direction[j][i] = geometry->GetMatrixColumn(i)[j];
        imageRegion.SetSize(0, geometry->GetExtent(0));
        imageRegion.SetSize(1, geometry->GetExtent(1));
        imageRegion.SetSize(2, geometry->GetExtent(2));


        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);
    }
    OutputImageType::RegionType::SizeType outImageSize = imageRegion.GetSize();
    m_OutImageSpacing = m_MaskImage->GetSpacing();
    m_ClusteredDirectionsContainer = ContainerType::New();

    // initialize num directions image
    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);

    // initialize direction images
    m_DirectionImageContainer = DirectionImageContainerType::New();

    // resample fiber bundle
    double minSpacing = 1;
    if(m_OutImageSpacing[0]<m_OutImageSpacing[1] && m_OutImageSpacing[0]<m_OutImageSpacing[2])
        minSpacing = m_OutImageSpacing[0];
    else if (m_OutImageSpacing[1] < m_OutImageSpacing[2])
        minSpacing = m_OutImageSpacing[1];
    else
        minSpacing = m_OutImageSpacing[2];

    if (m_UseWorkingCopy)
        m_FiberBundle = m_FiberBundle->GetDeepCopy();

    // resample fiber bundle for sufficient voxel coverage
    m_FiberBundle->ResampleSpline(minSpacing/10);

    // iterate over all fibers
    vtkSmartPointer<vtkPolyData> fiberPolyData = m_FiberBundle->GetFiberPolyData();
    int numFibers = m_FiberBundle->GetNumFibers();
    m_DirectionsContainer = ContainerType::New();

    VectorContainer< unsigned int, std::vector< double > >::Pointer peakLengths = VectorContainer< unsigned int, std::vector< double > >::New();

    MITK_INFO << "Generating directions from tractogram";
    boost::progress_display disp(numFibers);
    for( int i=0; i<numFibers; i++ )
    {
        ++disp;
        vtkCell* cell = fiberPolyData->GetCell(i);
        int numPoints = cell->GetNumberOfPoints();
        vtkPoints* points = cell->GetPoints();
        if (numPoints<2)
            continue;

        vnl_vector_fixed<double, 3> dir;
        itk::Point<double, 3> worldPos;
        vnl_vector<double> v;


        float fiberWeight = m_FiberBundle->GetFiberWeight(i);

        for( int j=0; j<numPoints-1; j++)
        {
            // get current position along fiber in world coordinates
            double* temp = points->GetPoint(j);
            worldPos = GetItkPoint(temp);
            itk::Index<3> index;
            m_MaskImage->TransformPhysicalPointToIndex(worldPos, index);
            if (!m_MaskImage->GetLargestPossibleRegion().IsInside(index) || m_MaskImage->GetPixel(index)==0)
                continue;

            // get fiber tangent direction at this position
            v = GetVnlVector(temp);
            dir = GetVnlVector(points->GetPoint(j+1))-v;
            if (dir.is_zero())
                continue;
            dir.normalize();

            // add direction to container
            unsigned int idx = index[0] + outImageSize[0]*(index[1] + outImageSize[1]*index[2]);
            DirectionContainerType::Pointer dirCont;
            if (m_DirectionsContainer->IndexExists(idx))
            {
                peakLengths->ElementAt(idx).push_back(fiberWeight);

                dirCont = m_DirectionsContainer->GetElement(idx);
                if (dirCont.IsNull())
                {
                    dirCont = DirectionContainerType::New();
                    dirCont->push_back(dir);
                    m_DirectionsContainer->InsertElement(idx, dirCont);
                }
                else
                    dirCont->push_back(dir);
            }
            else
            {
                dirCont = DirectionContainerType::New();
                dirCont->push_back(dir);
                m_DirectionsContainer->InsertElement(idx, dirCont);

                std::vector< double > lengths; lengths.push_back(fiberWeight);
                peakLengths->InsertElement(idx, lengths);
            }
        }
    }

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

    itk::ImageRegionIterator<ItkUcharImgType> dirIt(m_NumDirectionsImage, m_NumDirectionsImage->GetLargestPossibleRegion());

    MITK_INFO << "Clustering directions";
    boost::progress_display disp2(outImageSize[0]*outImageSize[1]*outImageSize[2]);
    while(!dirIt.IsAtEnd())
    {
        ++disp2;
        OutputImageType::IndexType index = dirIt.GetIndex();
        int idx = index[0]+(index[1]+index[2]*outImageSize[1])*outImageSize[0];

        if (!m_DirectionsContainer->IndexExists(idx))
        {
            ++dirIt;
            continue;
        }
        DirectionContainerType::Pointer dirCont = m_DirectionsContainer->GetElement(idx);
        if (dirCont.IsNull() || dirCont->empty())
        {
            ++dirIt;
            continue;
        }

//        std::vector< double > lengths; lengths.resize(dirCont->size(), 1);  // all peaks have size 1
        DirectionContainerType::Pointer directions;
        if (m_MaxNumDirections>0)
        {
            directions = FastClustering(dirCont, peakLengths->GetElement(idx));
            std::sort( directions->begin(), directions->end(), CompareVectorLengths );
        }
        else
            directions = dirCont;

        unsigned int numDir = directions->size();
        if (m_MaxNumDirections>0 && numDir>m_MaxNumDirections)
            numDir = m_MaxNumDirections;

        int count = 0;
        for (unsigned int i=0; i<numDir; i++)
        {
            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 );
            DirectionType dir = directions->at(i);

            if (dir.magnitude()<m_SizeThreshold)
                continue;
            if (m_NormalizeVectors)
                dir.normalize();
            count++;

            if (m_CreateDirectionImages && i<10)
            {
                if (i==m_DirectionImageContainer->size())
                {
                    ItkDirectionImageType::Pointer directionImage = ItkDirectionImageType::New();
                    directionImage->SetSpacing( spacing );
                    directionImage->SetOrigin( origin );
                    directionImage->SetDirection( direction );
                    directionImage->SetRegions( imageRegion );
                    directionImage->Allocate();
                    Vector< float, 3 > nullVec; nullVec.Fill(0.0);
                    directionImage->FillBuffer(nullVec);
                    m_DirectionImageContainer->InsertElement(i, directionImage);
                }

                // set direction image pixel
                ItkDirectionImageType::Pointer directionImage = m_DirectionImageContainer->GetElement(i);
                Vector< float, 3 > pixel;
                pixel.SetElement(0, dir[0]);
                pixel.SetElement(1, dir[1]);
                pixel.SetElement(2, dir[2]);
                directionImage->SetPixel(index, pixel);
            }

            // add direction to vector field (with spacing compensation)
            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);
        }
        dirIt.Set(count);
        ++dirIt;
    }

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