⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gdcmseriehelper.cxx

📁 DTMK软件开发包,此为开源软件,是一款很好的医学图像开发资源.
💻 CXX
📖 第 1 页 / 共 2 页
字号:
      if ( strImPos == GDCM_UNFOUND)
      {
         gdcmWarningMacro( "Unfound Image Position Patient (0020,0032)");
         strImPos = (*it)->GetEntryValue(0x0020,0x0030); // For ACR-NEMA images
         if ( strImPos == GDCM_UNFOUND )
         {
            gdcmWarningMacro( "Unfound Image Position (RET) (0020,0030)");
            // User wants to split on the 'Position'
            // No 'Position' info found.
            // We return an empty Htable !
            return CoherentFileSet;
         }  
      }

      if ( sscanf( strImPos.c_str(), "%f \\%f \\%f ", 
                                              &pos[0], &pos[1], &pos[2]) != 3 )
      {
            gdcmWarningMacro( "Wrong number for Position : ["
                       << strImPos << "]" );
             return CoherentFileSet;
      }

      // Let's build again the 'position' string, to be sure of it's format      

      ossPosition << pos[0];      
      for (int i = 1; i < 3; i++)
      {
        ossPosition << "\\";
        ossPosition << pos[i]; 
      }      
      strPosition = ossPosition.str();
      ossPosition.str("");

      if ( CoherentFileSet.count(strPosition) == 0 )
      {
         gdcmDebugMacro(" New Position :[" << strPosition << "]");
         // create a File set in 'position' position
         CoherentFileSet[strPosition] = new FileList;
      }
      // Current Position and DICOM header match; add the file:
      CoherentFileSet[strPosition]->push_back( (*it) );
   }   
   return CoherentFileSet;
}

/**
 * \brief   Splits a 'Single SerieUID' File set Coherent according to the
 *          value of a given Tag
 * @param fileSet File Set to be splitted
 * @param   group  group number of the target Element
 * @param   elem element number of the target Element
 * \return  std::map of 'Xcoherent' File sets
 */

XCoherentFileSetmap SerieHelper::SplitOnTagValue(FileList *fileSet, 
                                               uint16_t group, uint16_t element)
{
   XCoherentFileSetmap CoherentFileSet;

   size_t nb = fileSet->size();
   if (nb == 0 )
      return CoherentFileSet;

   std::string strTagValue;  // read on disc

   FileList::const_iterator it = fileSet->begin();
   for ( ;
         it != fileSet->end();
       ++it)
   {     
      // Information is in :      
      // 0020,0032 : Image Position Patient
      // 0020,0030 : Image Position (RET)

      strTagValue = (*it)->GetEntryValue(group,element);
      
      if ( CoherentFileSet.count(strTagValue) == 0 )
      {
         gdcmDebugMacro(" New Tag Value :[" << strTagValue << "]");
         // create a File set in 'position' position
         CoherentFileSet[strTagValue] = new FileList;
      }
      // Current Tag value and DICOM header match; add the file:
      CoherentFileSet[strTagValue]->push_back( (*it) );
   }
   return CoherentFileSet;
}

//-----------------------------------------------------------------------------
// Protected

//-----------------------------------------------------------------------------
// Private
/**
 * \brief sorts the images, according to their Patient Position.
 *
 *  We may order, considering :
 *   -# Image Position Patient
 *   -# Image Number
 *   -# file name
 *   -# More to come :-)
 * \note : FileList = std::vector<File* >
 * @param fileList Coherent File list (same Serie UID) to sort
 * @return false only if the header is bugged !
 */
bool SerieHelper::ImagePositionPatientOrdering( FileList *fileList )
//based on Jolinda Smith's algorithm
{
   //iop is calculated based on the file file
   float cosines[6];
   double normal[3];
   double ipp[3];
   double dist;
   double min = 0, max = 0;
   bool first = true;

   std::multimap<double,File *> distmultimap;
   // Use a multimap to sort the distances from 0,0,0
   for ( FileList::const_iterator 
         it = fileList->begin();
         it != fileList->end(); ++it )
   {
      if ( first ) 
      {
         (*it)->GetImageOrientationPatient( cosines );
      
         // You only have to do this once for all slices in the volume. Next, 
         // for each slice, calculate the distance along the slice normal 
         // using the IPP ("Image Position Patient") tag.
         // ("dist" is initialized to zero before reading the first slice) :
         normal[0] = cosines[1]*cosines[5] - cosines[2]*cosines[4];
         normal[1] = cosines[2]*cosines[3] - cosines[0]*cosines[5];
         normal[2] = cosines[0]*cosines[4] - cosines[1]*cosines[3];
  
         ipp[0] = (*it)->GetXOrigin();
         ipp[1] = (*it)->GetYOrigin();
         ipp[2] = (*it)->GetZOrigin();

         dist = 0;
         for ( int i = 0; i < 3; ++i )
         {
            dist += normal[i]*ipp[i];
         }
    
         distmultimap.insert(std::pair<const double,File *>(dist, *it));

         max = min = dist;
         first = false;
      }
      else 
      {
         ipp[0] = (*it)->GetXOrigin();
         ipp[1] = (*it)->GetYOrigin();
         ipp[2] = (*it)->GetZOrigin();

         dist = 0;
         for ( int i = 0; i < 3; ++i )
         {
            dist += normal[i]*ipp[i];
         }

         distmultimap.insert(std::pair<const double,File *>(dist, *it));

         min = (min < dist) ? min : dist;
         max = (max > dist) ? max : dist;
      }
   }

   // Find out if min/max are coherent
   if ( min == max )
   {
     gdcmWarningMacro("Looks like all images have the exact same image position"
                      << ". No PositionPatientOrdering sort performed" );
     return false;
   }

   // Check to see if image shares a common position
   bool ok = true;
   for (std::multimap<double, File *>::iterator it2 = distmultimap.begin();
        it2 != distmultimap.end();
        ++it2)
   {
      if (distmultimap.count((*it2).first) != 1)
      {
         gdcmErrorMacro("File: "
              << ((*it2).second->GetFileName())
              << " Distance: "
              << (*it2).first
              << " position is not unique");

         ok = false;
      }
   }
   if (!ok)
   {
      return false;
   }

   fileList->clear();  // doesn't delete list elements, only nodes

   if (DirectOrder)
   {  
      for (std::multimap<double, File *>::iterator it3 = distmultimap.begin();
           it3 != distmultimap.end();
           ++it3)
      {
         fileList->push_back( (*it3).second );
      }
   }
   else // user asked for reverse order
   {
      std::multimap<double, File *>::const_iterator it4;
      it4 = distmultimap.end();
      do
      {
         it4--;
         fileList->push_back( (*it4).second );
      } while (it4 != distmultimap.begin() );
   }

   distmultimap.clear();

   return true;
}

//-----------------------------------------------------------------------------
static bool ImageNumberLessThan(File *file1, File *file2)
{
  return file1->GetImageNumber() < file2->GetImageNumber();
}
static bool ImageNumberGreaterThan (File *file1, File *file2)
{
  return file1->GetImageNumber() > file2->GetImageNumber();
}
static bool FileNameLessThan (File *file1, File *file2)
{
   return file1->GetFileName() < file2->GetFileName();
}
static bool FileNameGreaterThan (File *file1, File *file2)
{
   return file1->GetFileName() > file2->GetFileName();
}

class SortFunctor
{
public:
  bool operator() (File *file1, File *file2)
    {
    return (SortFunction)(file1, file2);
    }
  BOOL_FUNCTION_PFILE_PFILE_POINTER SortFunction;
  SortFunctor()
    {
    SortFunction = 0;
    }
  SortFunctor(SortFunctor const &sf)
    {
    SortFunction = sf.SortFunction;
    }
  void operator=(BOOL_FUNCTION_PFILE_PFILE_POINTER sf)
    {
    SortFunction = sf;
    }
};

//-----------------------------------------------------------------------------
// Sort
/**
 * \brief   Sort FileList.
 */
static void Sort(FileList *fileList, SortFunctor &sf)
{
  std::sort(fileList->begin(), fileList->end(), sf );
}


/**
 * \brief sorts the images, according to their Image Number
 * \note Works only on bona fide files  (i.e image number is a character string
 *                                      corresponding to an integer)
 *             within a bona fide serie (i.e image numbers are consecutive)
 * @param fileList File set (same Serie UID) to sort 
 * @return false if non bona fide stuff encountered
 */
bool SerieHelper::ImageNumberOrdering(FileList *fileList) 
{
   int min, max, pos;
   size_t n = fileList->size();

   FileList::const_iterator it = fileList->begin();
   min = max = (*it)->GetImageNumber();

   for (; it != fileList->end(); ++it, ++n)
   {
      pos = (*it)->GetImageNumber();
      min = (min < pos) ? min : pos;
      max = (max > pos) ? max : pos;
   }

   // Find out if image numbers are coherent (consecutive)
   if ( min == max || max == 0 || max >= (static_cast<int>(n)+min) )
   {
      gdcmWarningMacro( " 'Image numbers' not coherent. "
                        << " No ImageNumberOrdering sort performed.");
      return false;
   }
   SortFunctor sf;
   if (DirectOrder)
     sf = ImageNumberLessThan;
   else
     sf = ImageNumberGreaterThan;
   Sort(fileList, sf);

   return true;
}
/**
 * \brief sorts the images, according to their File Name
 * @param fileList Coherent File list (same Serie UID) to sort
 * @return false only if the header is bugged !
 */
bool SerieHelper::FileNameOrdering(FileList *fileList)
{
   SortFunctor sf;
   if (DirectOrder) 
      sf = FileNameLessThan;
   else
      sf = FileNameGreaterThan;
   Sort(fileList, sf);

   return true;
}

/**
 * \brief sorts the images, according to user supplied function
 * @param fileList Coherent File list (same Serie UID) to sort
 * @return false only if the header is bugged !
 */
bool SerieHelper::UserOrdering(FileList *fileList)
{
   SortFunctor sf;
   sf = SerieHelper::UserLessThanFunction;
   Sort(fileList,sf);
   if (!DirectOrder) 
   {
      std::reverse(fileList->begin(), fileList->end());
   }
   return true;
}

//-----------------------------------------------------------------------------
// Print
/**
 * \brief   Canonical printer.
 */
void SerieHelper::Print(std::ostream &os, std::string const &indent)
{
   // For all the Coherent File lists of the gdcm::Serie
   SingleSerieUIDFileSetmap::iterator itl = SingleSerieUIDFileSetHT.begin();
   if ( itl == SingleSerieUIDFileSetHT.end() )
   {
      gdcmWarningMacro( "No SingleSerieUID File set found" );
      return;
   }
   while (itl != SingleSerieUIDFileSetHT.end())
   { 
      os << "Serie UID :[" << itl->first << "]" << std::endl;

      // For all the files of a SingleSerieUID File set
      for (FileList::iterator it =  (itl->second)->begin();
                                  it != (itl->second)->end(); 
                                ++it)
      {
         os << indent << " --- " << (*it)->GetFileName() << std::endl;
      }
      ++itl;
   }
}

void SerieHelper::CreateDefaultUniqueSeriesIdentifier()
{
   // If the user requests, additional information can be appended
   // to the SeriesUID to further differentiate volumes in the DICOM
   // objects being processed.
 
   // 0020 0011 Series Number
   // A scout scan prior to a CT volume scan can share the same
   //   SeriesUID, but they will sometimes have a different Series Number
   AddRestriction( 0x0020, 0x0011);
   // 0018 0024 Sequence Name
   // For T1-map and phase-contrast MRA, the different flip angles and
   //   directions are only distinguished by the Sequence Name
   AddRestriction(0x0018, 0x0024);
   // 0018 0050 Slice Thickness
   // On some CT systems, scout scans and subsequence volume scans will
   //   have the same SeriesUID and Series Number - YET the slice 
   //   thickness will differ from the scout slice and the volume slices.
   AddRestriction(0x0018, 0x0050);
   // 0028 0010 Rows
   // If the 2D images in a sequence don't have the same number of rows,
   // then it is difficult to reconstruct them into a 3D volume.
   AddRestriction(0x0028, 0x0010);
   // 0028 0011 Columns
   // If the 2D images in a sequence don't have the same number of columns,
   // then it is difficult to reconstruct them into a 3D volume.
   AddRestriction(0x0028, 0x0011);
}

/**
 * \brief Heuristics to *try* to build a Serie Identifier that would ensure
 *        all the images are coherent.
 *
 * By default, uses the SeriesUID.  If UseSeriesDetails(true) has been called,
 *         then additional identifying information is used.
 *  We allow user to add his own critierions, using AddSeriesDetail
 *        (he knows more than we do about his images!)
 *        ex : in tagging series, the only pertnent tag is
 *        0018|1312 [In-plane Phase Encoding Direction] value : ROW/COLUMN
 * @param inFile gdcm::File we want to build a Serie Identifier for.
 * @return the SeriesIdentifier
 */
std::string SerieHelper::CreateUniqueSeriesIdentifier( File *inFile )
{
   if( inFile->IsReadable() )
   {
    // 0020 000e UI REL Series Instance UID
    std::string uid = inFile->GetEntryValue (0x0020, 0x000e);
    std::string id = uid.c_str();
    if(m_UseSeriesDetails)
      {
      for(SerieExRestrictions::iterator it2 = ExRefine.begin();
        it2 != ExRefine.end();
        ++it2)
        {
        const ExRule &r = *it2;
        std::string s = inFile->GetEntryValue( r.group, r.elem );
        if( s == gdcm::GDCM_UNFOUND )
          {
          s = "";
          }
        if( id == uid && !s.empty() )
          {
          id += "."; // add separator
          }
        id += s;
        }
      }
    // Eliminate non-alnum characters, including whitespace...
    //   that may have been introduced by concats.
    for(size_t i=0; i<id.size(); i++)
      {
      while(i<id.size() 
        && !( id[i] == '.'
          || (id[i] >= 'a' && id[i] <= 'z')
          || (id[i] >= '0' && id[i] <= '9')
          || (id[i] >= 'A' && id[i] <= 'Z')))
        {
        id.erase(i, 1);
        }
      }
    return id;
    }
  else // Could not open inFile
    {
    gdcmWarningMacro("Could not parse series info.");
    std::string id = gdcm::GDCM_UNFOUND;
    return id;
    }
}


//-----------------------------------------------------------------------------
} // end namespace gdcm

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -