void
  mitk::SlicedGeometry3D::InitializeSlicedGeometry( unsigned int slices )
{
  Superclass::Initialize();
  m_Slices = slices;

  PlaneGeometry::Pointer gnull = nullptr;
  m_PlaneGeometries.assign( m_Slices, gnull );

  Vector3D spacing;
  spacing.Fill( 1.0 );
  this->SetSpacing( spacing );

  m_DirectionVector.Fill( 0 );
}
示例#2
0
void mitk::ExtrudedContour::BuildGeometry()
{
  if(m_Contour.IsNull())
    return;

//  Initialize(1);

  Vector3D nullvector; nullvector.Fill(0.0);
  float xProj[3];
  unsigned int i;
  unsigned int numPts = 20; //m_Contour->GetNumberOfPoints();
  mitk::Contour::PathPointer path = m_Contour->GetContourPath();
  mitk::Contour::PathType::InputType cstart = path->StartOfInput();
  mitk::Contour::PathType::InputType cend   = path->EndOfInput();
  mitk::Contour::PathType::InputType cstep  = (cend-cstart)/numPts;
  mitk::Contour::PathType::InputType ccur;

  // Part I: guarantee/calculate legal vectors

  m_Vector.Normalize();
  itk2vtk(m_Vector, m_Normal);
  // check m_Vector
  if(mitk::Equal(m_Vector, nullvector) || m_AutomaticVectorGeneration)
  {
    if ( m_AutomaticVectorGeneration == false)
      itkWarningMacro("Extrusion vector is 0 ("<< m_Vector << "); trying to use normal of polygon");

    vtkPoints *loopPoints = vtkPoints::New();
    //mitk::Contour::PointsContainerIterator pointsIt = m_Contour->GetPoints()->Begin();
    double vtkpoint[3];

    unsigned int i=0;
    for(i=0, ccur=cstart; i<numPts; ++i, ccur+=cstep)
    {
      itk2vtk(path->Evaluate(ccur), vtkpoint);
      loopPoints->InsertNextPoint(vtkpoint);
    }

    // Make sure points define a loop with a m_Normal
    vtkPolygon::ComputeNormal(loopPoints, m_Normal);
    loopPoints->Delete();

    vtk2itk(m_Normal, m_Vector);
    if(mitk::Equal(m_Vector, nullvector))
    {
      itkExceptionMacro("Cannot calculate normal of polygon");
    }
  }
  // check m_RightVector
  if((mitk::Equal(m_RightVector, nullvector)) || (mitk::Equal(m_RightVector*m_Vector, 0.0)==false))
  {
    if(mitk::Equal(m_RightVector, nullvector))
    {
      itkDebugMacro("Right vector is 0. Calculating.");
    }
    else
    {
      itkWarningMacro("Right vector ("<<m_RightVector<<") not perpendicular to extrusion vector "<<m_Vector<<": "<<m_RightVector*m_Vector);
    }
    // calculate a legal m_RightVector
    if( mitk::Equal( m_Vector[1], 0.0f ) == false )
    {
      FillVector3D( m_RightVector, 1.0f, -m_Vector[0]/m_Vector[1], 0.0f );
      m_RightVector.Normalize();
    }
    else
    {
      FillVector3D( m_RightVector, 0.0f, 1.0f, 0.0f );
    }
  }

  // calculate down-vector
  VnlVector rightDV = m_RightVector.GetVnlVector(); rightDV.normalize(); vnl2vtk(rightDV, m_Right);
  VnlVector downDV  = vnl_cross_3d( m_Vector.GetVnlVector(), rightDV ); downDV.normalize();  vnl2vtk(downDV,  m_Down);

  // Part II: calculate plane as base for extrusion, project the contour
  // on this plane and store as polygon for IsInside test and BoundingBox calculation

  // initialize m_ProjectionPlane, yet with origin at 0
  m_ProjectionPlane->InitializeStandardPlane(rightDV, downDV);

  // create vtkPolygon from contour and simultaneously determine 2D bounds of
  // contour projected on m_ProjectionPlane
  //mitk::Contour::PointsContainerIterator pointsIt = m_Contour->GetPoints()->Begin();
  m_Polygon->Points->Reset();
  m_Polygon->Points->SetNumberOfPoints(numPts);
  m_Polygon->PointIds->Reset();
  m_Polygon->PointIds->SetNumberOfIds(numPts);
  mitk::Point2D pt2d;
  mitk::Point3D pt3d;
  mitk::Point2D min, max;
  min.Fill(ScalarTypeNumericTraits::max());
  max.Fill(ScalarTypeNumericTraits::min());
  xProj[2]=0.0;
  for(i=0, ccur=cstart; i<numPts; ++i, ccur+=cstep)
  {
    pt3d.CastFrom(path->Evaluate(ccur));
    m_ProjectionPlane->Map(pt3d, pt2d);
    xProj[0]=pt2d[0];
    if(pt2d[0]<min[0]) min[0]=pt2d[0];
    if(pt2d[0]>max[0]) max[0]=pt2d[0];
    xProj[1]=pt2d[1];
    if(pt2d[1]<min[1]) min[1]=pt2d[1];
    if(pt2d[1]>max[1]) max[1]=pt2d[1];
    m_Polygon->Points->SetPoint(i, xProj);
    m_Polygon->PointIds->SetId(i, i);
  }
  // shift parametric origin to (0,0)
  for(i=0; i<numPts; ++i)
  {
    double * pt = this->m_Polygon->Points->GetPoint(i);

    pt[0]-=min[0]; pt[1]-=min[1];
    itkDebugMacro( << i << ": (" << pt[0] << "," << pt[1] << "," << pt[2] << ")" );
  }
  this->m_Polygon->GetBounds(m_ProjectedContourBounds);
  //m_ProjectedContourBounds[4]=-1.0; m_ProjectedContourBounds[5]=1.0;

  // calculate origin (except translation along the normal) and bounds
  // of m_ProjectionPlane:
  //  origin is composed of the minimum x-/y-coordinates of the polygon,
  //  bounds from the extent of the polygon, both after projecting on the plane
  mitk::Point3D origin;
  m_ProjectionPlane->Map(min, origin);
  ScalarType bounds[6]={0, max[0]-min[0], 0, max[1]-min[1], 0, 1};
  m_ProjectionPlane->SetBounds(bounds);
  m_ProjectionPlane->SetOrigin(origin);

  // Part III: initialize geometry
  if(m_ClippingGeometry.IsNotNull())
  {
    ScalarType min_dist=ScalarTypeNumericTraits::max(), max_dist=ScalarTypeNumericTraits::min(), dist;
    unsigned char i;
    for(i=0; i<8; ++i)
    {
      dist = m_ProjectionPlane->SignedDistance( m_ClippingGeometry->GetCornerPoint(i) );
      if(dist<min_dist) min_dist=dist;
      if(dist>max_dist) max_dist=dist;
    }
    //incorporate translation along the normal into origin
    origin = origin+m_Vector*min_dist;
    m_ProjectionPlane->SetOrigin(origin);
    bounds[5]=max_dist-min_dist;
  }
  else
    bounds[5]=20;

  itk2vtk(origin, m_Origin);

  mitk::Geometry3D::Pointer g3d = GetGeometry( 0 );
  assert( g3d.IsNotNull() );
  g3d->SetBounds(bounds);
  g3d->SetIndexToWorldTransform(m_ProjectionPlane->GetIndexToWorldTransform());
  g3d->TransferItkToVtkTransform();

  ProportionalTimeGeometry::Pointer timeGeometry = ProportionalTimeGeometry::New();
  timeGeometry->Initialize(g3d,1);
  SetTimeGeometry(timeGeometry);

}
double
mitk::SortByImagePositionPatient
::InternalNumericDistance(const mitk::DICOMDatasetAccess* left, const mitk::DICOMDatasetAccess* right, bool& possible) const
{
  // sort by distance to world origin, assuming (almost) equal orientation
  static const DICOMTag tagImagePositionPatient = DICOMTag(0x0020,0x0032); // Image Position (Patient)
  static const DICOMTag    tagImageOrientation = DICOMTag(0x0020, 0x0037); // Image Orientation

  Vector3D leftRight; leftRight.Fill(0.0);
  Vector3D leftUp; leftUp.Fill(0.0);
  bool leftHasOrientation(false);
  DICOMStringToOrientationVectors( left->GetTagValueAsString( tagImageOrientation ).value,
                                   leftRight, leftUp, leftHasOrientation );

  Vector3D rightRight; rightRight.Fill(0.0);
  Vector3D rightUp; rightUp.Fill(0.0);
  bool rightHasOrientation(false);
  DICOMStringToOrientationVectors(right->GetTagValueAsString(tagImageOrientation).value,
                                   rightRight, rightUp, rightHasOrientation );

  Point3D leftOrigin; leftOrigin.Fill(0.0f);
  bool leftHasOrigin(false);
  leftOrigin = DICOMStringToPoint3D(left->GetTagValueAsString(tagImagePositionPatient).value, leftHasOrigin);

  Point3D rightOrigin; rightOrigin.Fill(0.0f);
  bool rightHasOrigin(false);
  rightOrigin = DICOMStringToPoint3D(right->GetTagValueAsString(tagImagePositionPatient).value, rightHasOrigin);

  //   we tolerate very small differences in image orientation, since we got to know about
  //   acquisitions where these values change across a single series (7th decimal digit)
  //   (http://bugs.mitk.org/show_bug.cgi?id=12263)
  //   still, we want to check if our assumption of 'almost equal' orientations is valid
  for (unsigned int dim = 0; dim < 3; ++dim)
  {
    if (   fabs(leftRight[dim] - rightRight[dim]) > 0.0001
        || fabs(leftUp[dim] - rightUp[dim]) > 0.0001)
    {
      MITK_ERROR << "Dicom images have different orientations.";
      throw std::logic_error("Dicom images have different orientations. Call GetSeries() first to separate images.");
    }
  }

  Vector3D normal;
  normal[0] = leftRight[1] * leftUp[2] - leftRight[2] * leftUp[1];
  normal[1] = leftRight[2] * leftUp[0] - leftRight[0] * leftUp[2];
  normal[2] = leftRight[0] * leftUp[1] - leftRight[1] * leftUp[0];

  double leftDistance = 0.0;
  double rightDistance = 0.0;

  // this computes the distance from world origin (0,0,0) ALONG THE NORMAL of the image planes
  for (unsigned int dim = 0; dim < 3; ++dim)
  {
    leftDistance += normal[dim] * leftOrigin[dim];
    rightDistance += normal[dim] * rightOrigin[dim];
  }

  // if we can sort by just comparing the distance, we do exactly that
  if ( fabs(leftDistance - rightDistance) >= mitk::eps)
  {
    possible = true;
    // default: compare position
    return rightDistance - leftDistance; // if (left < right> ==> diff > 0
  }
  else
  {
    possible = false;
    return 0.0;
  }
}
示例#4
0
bool mitk::PicHelper::GetSpacing(const mitkIpPicDescriptor* aPic, Vector3D & spacing)
{
    mitkIpPicDescriptor* pic = const_cast<mitkIpPicDescriptor*>(aPic);

    mitkIpPicTSV_t *tsv;
    bool pixelSize = false;

    tsv = mitkIpPicQueryTag( pic, "REAL PIXEL SIZE" );
    if(tsv==NULL)
    {
        tsv = mitkIpPicQueryTag( pic, "PIXEL SIZE" );
        pixelSize = true;
    }
    if(tsv)
    {
        bool tagFound = false;
        if((tsv->dim*tsv->n[0]>=3) && (tsv->type==mitkIpPicFloat))
        {
            if(tsv->bpe==32)
            {
                FillVector3D(spacing,((mitkIpFloat4_t*)tsv->value)[0], ((mitkIpFloat4_t*)tsv->value)[1],((mitkIpFloat4_t*)tsv->value)[2]);
                tagFound = true;
            }
            else if(tsv->bpe==64)
            {
                FillVector3D(spacing,((mitkIpFloat8_t*)tsv->value)[0], ((mitkIpFloat8_t*)tsv->value)[1],((mitkIpFloat8_t*)tsv->value)[2]);
                tagFound = true;
            }
        }
        if(tagFound && pixelSize)
        {
            tsv = mitkIpPicQueryTag( pic, "PIXEL SPACING" );
            if(tsv)
            {
                mitk::ScalarType zSpacing = 0;
                if((tsv->dim*tsv->n[0]>=3) && (tsv->type==mitkIpPicFloat))
                {
                    if(tsv->bpe==32)
                    {
                        zSpacing = ((mitkIpFloat4_t*)tsv->value)[2];
                    }
                    else if(tsv->bpe==64)
                    {
                        zSpacing = ((mitkIpFloat8_t*)tsv->value)[2];
                    }
                    if(zSpacing != 0)
                    {
                        spacing[2] = zSpacing;
                    }
                }
            }
        }
        if(tagFound) return true;
    }
#ifdef HAVE_IPDICOM
    tsv = mitkIpPicQueryTag( pic, "SOURCE HEADER" );
    if( tsv )
    {
        void *data;
        mitkIpUInt4_t len;
        mitkIpFloat8_t spacing_z = 0;
        mitkIpFloat8_t thickness = 1;
        mitkIpFloat8_t fx = 1;
        mitkIpFloat8_t fy = 1;
        bool ok=false;

        if( dicomFindElement( (unsigned char *) tsv->value, 0x0018, 0x0088, &data, &len ) )
        {
            ok=true;
            sscanf( (char *) data, "%lf", &spacing_z );
//        itkGenericOutputMacro( "spacing:  " << spacing_z << " mm");
        }
        if( dicomFindElement( (unsigned char *) tsv->value, 0x0018, 0x0050, &data, &len ) )
        {
            ok=true;
            sscanf( (char *) data, "%lf", &thickness );
//        itkGenericOutputMacro( "thickness: " << thickness << " mm");

            if( thickness == 0 )
                thickness = 1;
        }
        if( dicomFindElement( (unsigned char *) tsv->value, 0x0028, 0x0030, &data, &len )
                && len>0 && ((char *)data)[0] )
        {
            sscanf( (char *) data, "%lf\\%lf", &fy, &fx );    // row / column value
//        itkGenericOutputMacro( "fx, fy: " << fx << "/" << fy  << " mm");
        }
        else
            ok=false;
        if(ok)
            FillVector3D(spacing, fx, fy,( spacing_z > 0 ? spacing_z : thickness));
        return ok;
    }
#endif /* HAVE_IPDICOM */
    if(spacing[0]<=0 || spacing[1]<=0 || spacing[2]<=0)
    {
        itkGenericOutputMacro(<< "illegal spacing by pic tag: " << spacing << ". Setting spacing to (1,1,1).");
        spacing.Fill(1);
    }
void
mitk::NormalDirectionConsistencySorter
::Sort()
{
  DICOMDatasetList datasets = GetInput();

  if (datasets.size() > 1)
  {
    // at some point in the code, there is the expectation that
    // the direction of the slice normals is the same as the direction between
    // first and last slice origin. We need to make this sure here, because
    // we want to feed the files into itk::ImageSeriesReader with the consistent
    // setting of ReverseOrderOff.

    static const DICOMTag tagImagePositionPatient = DICOMTag(0x0020,0x0032); // Image Position (Patient)
    static const DICOMTag    tagImageOrientation = DICOMTag(0x0020, 0x0037); // Image Orientation

    DICOMDatasetAccess* firstDS = datasets.front();
    DICOMDatasetAccess*  lastDS = datasets.back();

    // make sure here that the direction from slice to slice is the direction of
    // image normals...
    std::string imageOrientationString = firstDS->GetTagValueAsString( tagImageOrientation );
    std::string imagePositionPatientFirst = firstDS->GetTagValueAsString( tagImagePositionPatient );
    std::string imagePositionPatientLast = lastDS->GetTagValueAsString( tagImagePositionPatient );

    Vector3D right; right.Fill(0.0);
    Vector3D up; up.Fill(0.0);
    bool hasOrientation(false);
    DICOMStringToOrientationVectors( imageOrientationString,
        right, up, hasOrientation );

    Point3D firstOrigin; firstOrigin.Fill(0.0f);
    bool firstHasOrigin(false);
    firstOrigin = DICOMStringToPoint3D( imagePositionPatientFirst, firstHasOrigin );

    Point3D lastOrigin; lastOrigin.Fill(0.0f);
    bool lastHasOrigin(false);
    lastOrigin = DICOMStringToPoint3D( imagePositionPatientLast, lastHasOrigin );

    Vector3D normal;
    normal[0] = right[1] * up[2] - right[2] * up[1];
    normal[1] = right[2] * up[0] - right[0] * up[2];
    normal[2] = right[0] * up[1] - right[1] * up[0];
    normal.Normalize();

    Vector3D directionOfSlices;
    directionOfSlices = lastOrigin - firstOrigin;
    directionOfSlices.Normalize();

    double projection = normal * directionOfSlices;

    MITK_DEBUG << "Making sense of \norientation '" << imageOrientationString
               << "'\nfirst position '" << imagePositionPatientFirst
               << "'\nlast position '" << imagePositionPatientLast << "'";
    MITK_DEBUG << "Normal: " << normal;
    MITK_DEBUG << "Direction of slices: " << directionOfSlices;
    MITK_DEBUG << "Projection of direction onto slice normal: " << projection;

    if ( projection < 0.0 )
    {
      MITK_DEBUG << "Need to reverse filenames";
      std::reverse( datasets.begin(), datasets.end() );

      m_TiltInfo = GantryTiltInformation::MakeFromTagValues(
          imagePositionPatientLast,
          imagePositionPatientFirst,
          imageOrientationString,
          datasets.size() - 1
          );
    }
    else
    {
      m_TiltInfo = GantryTiltInformation::MakeFromTagValues(
          imagePositionPatientFirst,
          imagePositionPatientLast,
          imageOrientationString,
          datasets.size() - 1
          );
    }
  }
  else // just ONE dataset, do not forget to reset tilt information
  {
    m_TiltInfo = GantryTiltInformation(); // empty info
  }

  this->SetNumberOfOutputs(1);
  this->SetOutput(0, datasets);
}