Ejemplo n.º 1
0
TractsToVectorImageFilter< PixelType >::DirectionContainerType::Pointer TractsToVectorImageFilter< PixelType >::FastClustering(DirectionContainerType::Pointer inDirs, std::vector< double > lengths)
{
  DirectionContainerType::Pointer outDirs = DirectionContainerType::New();
  if (inDirs->size()<2)
  {
    if (inDirs->size()==1)
      inDirs->SetElement(0, inDirs->at(0)*lengths.at(0));
    return inDirs;
  }

  DirectionType oldMean, currentMean;
  std::vector< int > touched;

  // initialize
  touched.resize(inDirs->size(), 0);
  bool free = true;
  currentMean = inDirs->at(0);  // initialize first seed
  currentMean.normalize();
  double length = lengths.at(0);
  touched[0] = 1;
  std::vector< double > newLengths;
  bool meanChanged = false;

  double max = 0;
  while (free)
  {
    oldMean.fill(0.0);

    // start mean-shift clustering
    double angle = 0;

    while (fabs(dot_product(currentMean, oldMean))<0.99)
    {
      oldMean = currentMean;
      currentMean.fill(0.0);
      for (unsigned int i=0; i<inDirs->size(); i++)
      {
        angle = dot_product(oldMean, inDirs->at(i));
        if (angle>=m_AngularThreshold)
        {
          currentMean += inDirs->at(i);
          if (meanChanged)
            length += lengths.at(i);
          touched[i] = 1;
          meanChanged = true;
        }
        else if (-angle>=m_AngularThreshold)
        {
          currentMean -= inDirs->at(i);
          if (meanChanged)
            length += lengths.at(i);
          touched[i] = 1;
          meanChanged = true;
        }
      }
      if(!meanChanged)
        currentMean = oldMean;
      else
        currentMean.normalize();
    }

    // found stable mean
    outDirs->push_back(currentMean);
    newLengths.push_back(length);
    if (length>max)
      max = length;

    // find next unused seed
    free = false;
    for (unsigned int i=0; i<touched.size(); i++)
      if (touched[i]==0)
      {
        currentMean = inDirs->at(i);
        free = true;
        meanChanged = false;
        length = lengths.at(i);
        touched[i] = 1;
        break;
      }
  }

  if (inDirs->size()==outDirs->size())
  {
    if (max>0)
    {
      for (unsigned int i=0; i<outDirs->size(); i++)
        outDirs->SetElement(i, outDirs->at(i)*newLengths.at(i));
    }
    return outDirs;
  }
  else
    return FastClustering(outDirs, newLengths);
}
Ejemplo n.º 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;
    }
  }
}
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);
}