读取每一张DICOM文件的图像数据(二)

       上一篇文章分析了利用vtkDICOMImageReader::ExecuteInformation()函数判断是DICOM文件还是包含DICOM文件的目录,判断文件是否可以打开,并将目录中的DICOM文件按照0020,0032的Image position进行排序等等。本篇文章在分析读取Tag信息的同时,重点分析图像数据的读取。

void vtkDICOMImageReader::ExecuteDataWithInformation(vtkDataObject *output,
                                                     vtkInformation *outInfo)
{
  //分配存储数据的的内存
  vtkImageData *data = this->AllocateOutputData(output, outInfo);

  if (!this->FileName && this->DICOMFileNames->size() == 0)
  {
    vtkErrorMacro( << "Either a filename was not specified or the specified directory does not contain any DICOM images.");
    this->SetErrorCode( vtkErrorCode::NoFileNameError );
    return;
  }

  data->GetPointData()->GetScalars()->SetName("DICOMImage");

  this->ComputeDataIncrements();

  if (this->FileName)
  {
    vtkDebugMacro( << "Single file : " << this->FileName);
    //清除Tag回调函数
    this->Parser->ClearAllDICOMTagCallbacks();
    //打开文件
    this->Parser->OpenFile(this->FileName);
    this->AppHelper->Clear();
    this->AppHelper->RegisterCallbacks(this->Parser);
    //注册图像数据回调函数
    this->AppHelper->RegisterPixelDataCallback(this->Parser);
    //读取头信息
    this->Parser->ReadHeader();

    void* imgData = NULL;
    DICOMParser::VRTypes dataType;//数据类型USHORT, SHORT,CHAR等等。
    unsigned long imageDataLength;//图像数据长度,一般512*512*2
    
    this->AppHelper->GetImageData(imgData, dataType, imageDataLength);
    if( !imageDataLength )
    {
      vtkErrorMacro( << "There was a problem retrieving data from: " << this->FileName );
      this->SetErrorCode( vtkErrorCode::FileFormatError );
      return;
    }
    //取出一块内存
    void* buffer = data->GetScalarPointer();
    if (buffer == NULL)
    {
      vtkErrorMacro(<< "No memory allocated for image data!");
      return;
    }
    // DICOM 存储左上角像素作为第一个图像像素。
    // VTK 存储左下角像素为一张图像的第一个像素。
    // 需要对数据进行翻转.
    //存储数据
    vtkIdType rowLength;
    rowLength = this->DataIncrements[1];
    unsigned char *b = (unsigned char *)buffer;
    unsigned char *iData = (unsigned char *)imgData;
    iData += (imageDataLength - rowLength); // beginning of last row
    //数据复制
    for (int i=0; i < this->AppHelper->GetHeight(); ++i)
    {
      memcpy(b, iData, rowLength);
      b += rowLength;
      iData -= rowLength;
    }
  }
  else if (this->DICOMFileNames->size() > 0)
  {
    vtkDebugMacro( << "Multiple files (" << static_cast<int>(this->DICOMFileNames->size()) << ")");
    this->Parser->ClearAllDICOMTagCallbacks();
    this->AppHelper->Clear();
    this->AppHelper->RegisterCallbacks(this->Parser);
    this->AppHelper->RegisterPixelDataCallback(this->Parser);

    void* buffer = data->GetScalarPointer();
    if (buffer == NULL)
    {
      vtkErrorMacro(<< "No memory allocated for image data!");
      return;
    }

    std::vector<std::string>::iterator fiter;

    int count = 0;
    vtkIdType numFiles = static_cast<int>(this->DICOMFileNames->size());

    for (fiter = this->DICOMFileNames->begin();
         fiter != this->DICOMFileNames->end();
         fiter++)
    {
      count++;
      const char *file = fiter->c_str();
      vtkDebugMacro( << "File : " << file );
      this->Parser->OpenFile( file );
      this->Parser->ReadHeader();

      void* imgData = NULL;
      DICOMParser::VRTypes dataType;
      unsigned long imageDataLengthInBytes;

      this->AppHelper->GetImageData(imgData, dataType, imageDataLengthInBytes);
      if( !imageDataLengthInBytes )
      {
        vtkErrorMacro( << "There was a problem retrieving data from: " << file );
        this->SetErrorCode( vtkErrorCode::FileFormatError );
        return;
      }

      // DICOM 存储左上角像素作为第一个图像像素。
      // VTK 存储左下角像素为一张图像的第一个像素。
      // 需要对数据进行翻转.
      vtkIdType rowLength;
      rowLength = this->DataIncrements[1];
      unsigned char *b = (unsigned char *)buffer;
      unsigned char *iData = (unsigned char *)imgData;
      iData += (imageDataLengthInBytes - rowLength); // beginning of last row
      for (int i=0; i < this->AppHelper->GetHeight(); ++i)
      {
        memcpy(b, iData, rowLength);
        b += rowLength;
        iData -= rowLength;
      }
      buffer = ((char*) buffer) + imageDataLengthInBytes;

      this->UpdateProgress(float(count)/float(numFiles));
      int len = static_cast<int> (strlen((const char*) (*fiter).c_str()));
      char* filename = new char[len+1];
      strcpy(filename, (const char*) (*fiter).c_str());
      this->SetProgressText(filename);
      delete[] filename;
    }
  }
}
//该函数注册回调函数,并读取DICOM的Tag信息放到this->Implementation->TagMap中
void DICOMAppHelper::RegisterCallbacks(DICOMParser* parser)
{
  if (!parser)
    {
    dicom_stream::cerr << "Null parser!" << dicom_stream::endl;
    return;
    }

  SeriesUIDCB->SetCallbackFunction(this, &DICOMAppHelper::SeriesUIDCallback);
  parser->AddDICOMTagCallback(0x0020, 0x000e, DICOMParser::VR_UI, SeriesUIDCB);

  SliceNumberCB->SetCallbackFunction(this, &DICOMAppHelper::SliceNumberCallback);
  parser->AddDICOMTagCallback(0x0020, 0x0013, DICOMParser::VR_IS, SliceNumberCB);

  SliceLocationCB->SetCallbackFunction(this, &DICOMAppHelper::SliceLocationCallback);
  parser->AddDICOMTagCallback(0x0020, 0x1041, DICOMParser::VR_CS, SliceLocationCB);

  ImagePositionPatientCB->SetCallbackFunction(this, &DICOMAppHelper::ImagePositionPatientCallback);
  parser->AddDICOMTagCallback(0x0020, 0x0032, DICOMParser::VR_SH, ImagePositionPatientCB);

  ImageOrientationPatientCB->SetCallbackFunction(this, &DICOMAppHelper::ImageOrientationPatientCallback);
  parser->AddDICOMTagCallback(0x0020, 0x0037, DICOMParser::VR_SH, ImageOrientationPatientCB);

  TransferSyntaxCB->SetCallbackFunction(this, &DICOMAppHelper::TransferSyntaxCallback);
  parser->AddDICOMTagCallback(0x0002, 0x0010, DICOMParser::VR_UI, TransferSyntaxCB);

  ToggleSwapBytesCB->SetCallbackFunction(this, &DICOMAppHelper::ToggleSwapBytesCallback);

  BitsAllocatedCB->SetCallbackFunction(this, &DICOMAppHelper::BitsAllocatedCallback);
  parser->AddDICOMTagCallback(0x0028, 0x0100, DICOMParser::VR_US, BitsAllocatedCB);

  PixelSpacingCB->SetCallbackFunction(this, &DICOMAppHelper::PixelSpacingCallback);
  // Why is 0028,0030 VR:FL, it is VR::DS as per PS 3.6-2008 ...
  parser->AddDICOMTagCallback(0x0028, 0x0030, DICOMParser::VR_FL, PixelSpacingCB);
  parser->AddDICOMTagCallback(0x0018, 0x0050, DICOMParser::VR_FL, PixelSpacingCB);

  WidthCB->SetCallbackFunction(this, &DICOMAppHelper::WidthCallback);
  parser->AddDICOMTagCallback(0x0028, 0x0011, DICOMParser::VR_US, WidthCB);

  HeightCB->SetCallbackFunction(this, &DICOMAppHelper::HeightCallback);
  parser->AddDICOMTagCallback(0x0028, 0x0010, DICOMParser::VR_US, HeightCB);

  PixelRepresentationCB->SetCallbackFunction(this, &DICOMAppHelper::PixelRepresentationCallback);
  parser->AddDICOMTagCallback(0x0028, 0x0103, DICOMParser::VR_US, PixelRepresentationCB);

  PhotometricInterpretationCB->SetCallbackFunction(this, &DICOMAppHelper::PhotometricInterpretationCallback);
  parser->AddDICOMTagCallback(0x0028, 0x0004, DICOMParser::VR_CS, PhotometricInterpretationCB);

  RescaleOffsetCB->SetCallbackFunction(this, &DICOMAppHelper::RescaleOffsetCallback);
  parser->AddDICOMTagCallback(0x0028, 0x1052, DICOMParser::VR_CS, RescaleOffsetCB);

  RescaleSlopeCB->SetCallbackFunction(this, &DICOMAppHelper::RescaleSlopeCallback);
  parser->AddDICOMTagCallback(0x0028, 0x1053, DICOMParser::VR_FL, RescaleSlopeCB);

  PatientNameCB->SetCallbackFunction(this, &DICOMAppHelper::PatientNameCallback);
  parser->AddDICOMTagCallback(0x0010, 0x0010, DICOMParser::VR_PN, PatientNameCB);

  StudyUIDCB->SetCallbackFunction(this, &DICOMAppHelper::StudyUIDCallback);
  parser->AddDICOMTagCallback(0x0020, 0x000d, DICOMParser::VR_UI, StudyUIDCB);

  StudyIDCB->SetCallbackFunction(this, &DICOMAppHelper::StudyIDCallback);
  parser->AddDICOMTagCallback(0x0020, 0x0010, DICOMParser::VR_SH, StudyIDCB);

  GantryAngleCB->SetCallbackFunction(this, &DICOMAppHelper::GantryAngleCallback);
  parser->AddDICOMTagCallback(0x0018, 0x1120, DICOMParser::VR_FL, GantryAngleCB);


  DICOMTagInfo dicom_tags[] = {
    {0x0002, 0x0002, DICOMParser::VR_UI, "Media storage SOP class uid"},
    {0x0002, 0x0003, DICOMParser::VR_UI, "Media storage SOP inst uid"},
    {0x0002, 0x0010, DICOMParser::VR_UI, "Transfer syntax uid"},
    {0x0002, 0x0012, DICOMParser::VR_UI, "Implementation class uid"},
    {0x0008, 0x0018, DICOMParser::VR_UI, "Image UID"},
    {0x0008, 0x0020, DICOMParser::VR_DA, "Series date"},
    {0x0008, 0x0030, DICOMParser::VR_TM, "Series time"},
    {0x0008, 0x0060, DICOMParser::VR_SH, "Modality"},
    {0x0008, 0x0070, DICOMParser::VR_SH, "Manufacturer"},
    {0x0008, 0x1060, DICOMParser::VR_SH, "Physician"},
    {0x0018, 0x0050, DICOMParser::VR_FL, "slice thickness"},
    {0x0018, 0x0060, DICOMParser::VR_FL, "kV"},
    {0x0018, 0x0088, DICOMParser::VR_FL, "slice spacing"},
    {0x0018, 0x1100, DICOMParser::VR_SH, "Recon diameter"},
    {0x0018, 0x1151, DICOMParser::VR_FL, "mA"},
    {0x0018, 0x1210, DICOMParser::VR_SH, "Recon kernel"},
    {0x0020, 0x000d, DICOMParser::VR_UI, "Study UID"},
    {0x0020, 0x000e, DICOMParser::VR_UI, "Series UID"},
    {0x0020, 0x0013, DICOMParser::VR_IS, "Image number"},
    {0x0020, 0x0032, DICOMParser::VR_SH, "Patient position"},
    {0x0020, 0x0037, DICOMParser::VR_SH, "Patient position cosines"},
    {0x0020, 0x1041, DICOMParser::VR_CS, "Slice location"},
    {0x0028, 0x0010, DICOMParser::VR_FL, "Num rows"},
    {0x0028, 0x0011, DICOMParser::VR_FL, "Num cols"},
    {0x0028, 0x0030, DICOMParser::VR_FL, "pixel spacing"},
    {0x0028, 0x0100, DICOMParser::VR_US, "Bits allocated"},
    {0x0028, 0x0120, DICOMParser::VR_UL, "pixel padding"},
    {0x0028, 0x1052, DICOMParser::VR_FL, "pixel offset"}
  };

  int num_tags = sizeof(dicom_tags)/sizeof(DICOMTagInfo);

#ifdef DEBUG_DICOM_APP_HELPER
  DICOMMemberCallback<DICOMAppHelper>** callbackArray = new DICOMMemberCallback<DICOMAppHelper>*[num_tags];
#endif

  for (int j = 0; j < num_tags; j++)
    {
    //
    // Setup internal map.
    //
    DICOMTagInfo tagStruct = dicom_tags[j];
    doublebyte group = tagStruct.group;
    doublebyte element = tagStruct.element;

    dicom_stl::pair<doublebyte, doublebyte> gePair(group, element);
    dicom_stl::pair<const dicom_stl::pair<doublebyte, doublebyte>, DICOMTagInfo> mapPair(gePair, tagStruct);
    this->Implementation->TagMap.insert(mapPair);

#ifdef DEBUG_DICOM_APP_HELPER
    //
    // Make callback
    //
    callbackArray[j] = new DICOMMemberCallback<DICOMAppHelper>;
    callbackArray[j]->SetCallbackFunction(this, &DICOMAppHelper::ArrayCallback);
    //
    // Set callback on parser.
    //
    parser->AddDICOMTagCallback(group, element,datatype, callbackArray[j]);
#endif

    }

}


//利用下面的回调函数回调出来各个Tag信息。
void DICOMAppHelper::SeriesUIDCallback(DICOMParser *parser,
                                       doublebyte,
                                       doublebyte,
                                       DICOMParser::VRTypes,
                                       unsigned char* val,
                                       quadbyte)
{
  char* newString = reinterpret_cast<char*>(val);
  dicom_stl::string newStdString(newString);
  dicom_stl::map<dicom_stl::string, dicom_stl::vector<dicom_stl::string>, ltstdstr>::iterator iter = this->Implementation->SeriesUIDMap.find(newStdString);
  if ( iter == this->Implementation->SeriesUIDMap.end())
    {
    dicom_stl::vector<dicom_stl::string> newVector;

    newVector.push_back(parser->GetFileName());
    this->Implementation->SeriesUIDMap.insert(dicom_stl::pair<const dicom_stl::string, dicom_stl::vector<dicom_stl::string> > (newStdString, newVector));
    }
  else
    {
    (*iter).second.push_back(parser->GetFileName());
    }
}

void DICOMAppHelper::OutputSeries()
{
  dicom_stream::cout << dicom_stream::endl << dicom_stream::endl;

  for (dicom_stl::map<dicom_stl::string, dicom_stl::vector<dicom_stl::string>, ltstdstr >::iterator iter = this->Implementation->SeriesUIDMap.begin();
       iter != this->Implementation->SeriesUIDMap.end();
       iter++)
    {
    dicom_stream::cout << "SERIES: " << (*iter).first.c_str() << dicom_stream::endl;
    dicom_stl::vector<dicom_stl::string>& v_ref = (*iter).second;

    for (dicom_stl::vector<dicom_stl::string>::iterator v_iter = v_ref.begin();
         v_iter != v_ref.end();
         v_iter++)
      {
      dicom_stl::map<dicom_stl::string, DICOMOrderingElements, ltstdstr>::iterator sn_iter = Implementation->SliceOrderingMap.find(*v_iter);

      int slice = -1;
      if (sn_iter != Implementation->SliceOrderingMap.end())
        {
        slice = (*sn_iter).second.SliceNumber;
        }
      dicom_stream::cout << "\t" << (*v_iter).c_str() << " [" << slice << "]" <<  dicom_stream::endl;
      }
    }
}


void DICOMAppHelper::ArrayCallback(DICOMParser *parser,
                                   doublebyte group,
                                   doublebyte element,
                                   DICOMParser::VRTypes datatype,
                                   unsigned char* val,
                                   quadbyte len)
{
  const char* desc = "No description";

  TagMapType::iterator iter = this->Implementation->TagMap.find(dicom_stl::pair<doublebyte, doublebyte> (group, element));
  if (iter != this->Implementation->TagMap.end())
    {
    desc = (*iter).second.description;
    }

  int t2 = int((0x0000FF00 & datatype) >> 8);
  int t1 = int((0x000000FF & datatype));

  char ct2=static_cast<char>(t2);
  char ct1=static_cast<char>(t1);


  HeaderFile << "(0x";

  HeaderFile.width(4);
  char prev = HeaderFile.fill('0');

  HeaderFile << dicom_stream::hex << group;
  HeaderFile << ",0x";

  HeaderFile.width(4);
  HeaderFile.fill('0');

  HeaderFile << dicom_stream::hex << element;
  HeaderFile << ") ";

  HeaderFile.fill(prev);
  HeaderFile << dicom_stream::dec;
  HeaderFile << " " << ct1 << ct2 << " ";
  HeaderFile << "[" << len << " bytes] ";

  HeaderFile << desc << " : ";

  unsigned int uival = 0;
  float fval = 0;
  double dval = 0;
  int ival = 0;

  if (val)
    {
    switch (datatype)
      {
      case DICOMParser::VR_AE:
      case DICOMParser::VR_AS:
      case DICOMParser::VR_CS:
      case DICOMParser::VR_UI:
      case DICOMParser::VR_DA:
      case DICOMParser::VR_DS:
      case DICOMParser::VR_DT:
      case DICOMParser::VR_LO:
      case DICOMParser::VR_LT:
      case DICOMParser::VR_OB: // ordered bytes
      case DICOMParser::VR_OW: // ordered words
      case DICOMParser::VR_PN:
      case DICOMParser::VR_ST:
      case DICOMParser::VR_TM:
      case DICOMParser::VR_UN:
      case DICOMParser::VR_UT:
      case DICOMParser::VR_SQ: // sequence
      case DICOMParser::VR_SH: // strings
      case DICOMParser::VR_IS:
        HeaderFile << val;
        break;
      case DICOMParser::VR_FL: // float
        fval = static_cast<float> (atof(reinterpret_cast<char*>(val)));
        HeaderFile << fval;
        break;
      case DICOMParser::VR_FD: // float double
        dval = static_cast<double> (atof(reinterpret_cast<char*>(val)));
        HeaderFile << dval;
        break;
      case DICOMParser::VR_UL: // unsigned long
      case DICOMParser::VR_SL: // signed long
      case DICOMParser::VR_AT:
        HeaderFile << uival;
        break;
      //case DICOMParser::VR_IS:
      //  ival = DICOMFile::ReturnAsSignedLong(val, parser->GetDICOMFile()->GetPlatformIsBigEndian());
      //  HeaderFile << ival;
      //  break;
      case DICOMParser::VR_SS:
        ival = DICOMFile::ReturnAsSignedShort(val, parser->GetDICOMFile()->GetPlatformIsBigEndian());
        HeaderFile << ival;
        break;
      case DICOMParser::VR_US: // unsigned short
        uival = DICOMFile::ReturnAsUnsignedShort(val, parser->GetDICOMFile()->GetPlatformIsBigEndian());
        HeaderFile << uival;
        break;
      case DICOMParser::VR_UNKNOWN:
      case DICOMParser::VR_AW:
      default:
        HeaderFile << val << dicom_stream::endl;
        break;
      }
    }
  else
    {
    HeaderFile << "NULL";
    }

  HeaderFile << dicom_stream::dec << dicom_stream::endl;
  HeaderFile.fill(prev);

  delete [] val;
}

void DICOMAppHelper::SliceNumberCallback(DICOMParser *parser,
                                         doublebyte,
                                         doublebyte,
                                         DICOMParser::VRTypes,
                                         unsigned char* val,
                                         quadbyte)
{
  // Look for the current file in the map of slice ordering data
  dicom_stl::map<dicom_stl::string, DICOMOrderingElements, ltstdstr>::iterator it;
  it = this->Implementation->SliceOrderingMap.find(parser->GetFileName());
  if (it == Implementation->SliceOrderingMap.end())
    {
    // file not found, create a new entry
    DICOMOrderingElements ord;
    if( val )
      {
      ord.SliceNumber = atoi(reinterpret_cast<char *>(val));
      }
    else // Slice Number present but empty
      {
      ord.SliceNumber = 0;
      }

    // insert into the map
    this->Implementation->SliceOrderingMap.insert(
      dicom_stl::pair<const dicom_stl::string,
      DICOMOrderingElements>(parser->GetFileName(), ord));
    }
  else
    {
    // file found, add new values
    if( val )
      {
      (*it).second.SliceNumber = atoi(reinterpret_cast<char *>(val));
      }
    else // Slice Number present but empty
      {
      (*it).second.SliceNumber = 0;
      }
    }

  // cache the slice number
  if( val )
    {
    this->SliceNumber = atoi(reinterpret_cast<char *>(val));
    }
  else // Slice Number present but empty
    {
    this->SliceNumber = 0;
    }
}


void DICOMAppHelper::SliceLocationCallback(DICOMParser *parser,
                                           doublebyte,
                                           doublebyte,
                                           DICOMParser::VRTypes,
                                           unsigned char* val,
                                           quadbyte)
{
  // Look for the current file in the map of slice ordering data
  dicom_stl::map<dicom_stl::string, DICOMOrderingElements, ltstdstr>::iterator it;
  it = this->Implementation->SliceOrderingMap.find(parser->GetFileName());
  if (it == Implementation->SliceOrderingMap.end())
    {
    // file not found, create a new entry
    DICOMOrderingElements ord;
    ord.SliceLocation = static_cast<float>(
      atof(reinterpret_cast<char *>(val)));

    // insert into the map
    this->Implementation->SliceOrderingMap.insert(dicom_stl::pair<const dicom_stl::string,
      DICOMOrderingElements>(parser->GetFileName(), ord));
    }
  else if (val)
    {
    // file found, add new values
    (*it).second.SliceLocation =
      static_cast<float>(atof(reinterpret_cast<char *>(val) ));
    }
}

void DICOMAppHelper::ImagePositionPatientCallback(DICOMParser *parser,
                                                  doublebyte,
                                                  doublebyte,
                                                  DICOMParser::VRTypes,
                                                  unsigned char* val,
                                                  quadbyte)
{
  // Look for the current file in the map of slice ordering data
  dicom_stl::map<dicom_stl::string, DICOMOrderingElements, ltstdstr>::iterator it;
  it = this->Implementation->SliceOrderingMap.find(parser->GetFileName());
  if (it == Implementation->SliceOrderingMap.end())
    {
    // file not found, create a new entry
    DICOMOrderingElements ord;

    if (val)
      {
      sscanf(reinterpret_cast<char*>(val), "%f\\%f\\%f",
              &ord.ImagePositionPatient[0],
              &ord.ImagePositionPatient[1],
              &ord.ImagePositionPatient[2] );
      }
    else
      {
      // no actual position specified, default to the origin
      ord.ImagePositionPatient[0] = 0.0;
      ord.ImagePositionPatient[1] = 0.0;
      ord.ImagePositionPatient[2] = 0.0;
      }

    // insert into the map
    this->Implementation->SliceOrderingMap.insert(dicom_stl::pair<const dicom_stl::string,
      DICOMOrderingElements>(parser->GetFileName(), ord));

    // cache the value
    memcpy( this->ImagePositionPatient, ord.ImagePositionPatient,
            3*sizeof(float) );
    }
  else
    {
    if (val)
      {
      // file found, add new values
      sscanf( reinterpret_cast<char*>(val), "%f\\%f\\%f",
              &(*it).second.ImagePositionPatient[0],
              &(*it).second.ImagePositionPatient[1],
              &(*it).second.ImagePositionPatient[2] );
      }
    else
      {
      // no actual position specified, default to the origin
      (*it).second.ImagePositionPatient[0] = 0.0;
      (*it).second.ImagePositionPatient[1] = 0.0;
      (*it).second.ImagePositionPatient[2] = 0.0;
      }

    // cache the value
    memcpy( this->ImagePositionPatient, (*it).second.ImagePositionPatient,
            3*sizeof(float) );
    }
}


void DICOMAppHelper::ImageOrientationPatientCallback(DICOMParser *parser,
                                                     doublebyte,
                                                     doublebyte,
                                                     DICOMParser::VRTypes,
                                                     unsigned char* val,
                                                     quadbyte)
{
  // Look for the current file in the map of slice ordering data
  dicom_stl::map<dicom_stl::string, DICOMOrderingElements, ltstdstr>::iterator it;
  it = this->Implementation->SliceOrderingMap.find(parser->GetFileName());
  if (it == Implementation->SliceOrderingMap.end())
    {
    // file not found, create a new entry
    DICOMOrderingElements ord;
    if (val)
      {
      sscanf( reinterpret_cast<char*>(val), "%f\\%f\\%f\\%f\\%f\\%f",
              &ord.ImageOrientationPatient[0],
              &ord.ImageOrientationPatient[1],
              &ord.ImageOrientationPatient[2],
              &ord.ImageOrientationPatient[3],
              &ord.ImageOrientationPatient[4],
              &ord.ImageOrientationPatient[5] );
      }
    else
      {
      // no orientation defined, default to an standard axial orientation
      ord.ImageOrientationPatient[0] = 1.0;
      ord.ImageOrientationPatient[1] = 0.0;
      ord.ImageOrientationPatient[2] = 0.0;
      ord.ImageOrientationPatient[3] = 0.0;
      ord.ImageOrientationPatient[4] = 1.0;
      ord.ImageOrientationPatient[5] = 0.0;
      }

    // insert into the map
    this->Implementation->SliceOrderingMap.insert(dicom_stl::pair<const dicom_stl::string,
      DICOMOrderingElements>(parser->GetFileName(), ord));

    // cache the value
    memcpy( this->ImageOrientationPatient, ord.ImageOrientationPatient,
            6*sizeof(float) );
    }
  else
    {
    // file found, add new values
    if (val)
      {
      sscanf( reinterpret_cast<char*>(val), "%f\\%f\\%f\\%f\\%f\\%f",
              &(*it).second.ImageOrientationPatient[0],
              &(*it).second.ImageOrientationPatient[1],
              &(*it).second.ImageOrientationPatient[2],
              &(*it).second.ImageOrientationPatient[3],
              &(*it).second.ImageOrientationPatient[4],
              &(*it).second.ImageOrientationPatient[5] );
      }
    else
      {
      // no orientation defined, default to an standard axial orientation
      (*it).second.ImageOrientationPatient[0] = 1.0;
      (*it).second.ImageOrientationPatient[1] = 0.0;
      (*it).second.ImageOrientationPatient[2] = 0.0;
      (*it).second.ImageOrientationPatient[3] = 0.0;
      (*it).second.ImageOrientationPatient[4] = 1.0;
      (*it).second.ImageOrientationPatient[5] = 0.0;
      }

    // cache the value
    memcpy( this->ImageOrientationPatient, (*it).second.ImageOrientationPatient,
            6*sizeof(float) );
    }
}


void DICOMAppHelper::TransferSyntaxCallback(DICOMParser *parser,
                                            doublebyte,
                                            doublebyte,
                                            DICOMParser::VRTypes,
                                            unsigned char* val,
                                            quadbyte)
{

#ifdef DEBUG_DICOM_APP_HELPER
#ifdef _WIN32
  char platformByteOrder = 'L';
#else
  char platformByteOrder = 'B';
#endif
  dicom_stream::cout << "Platform byte order: " << platformByteOrder << dicom_stream::endl;
#endif

  static const char* TRANSFER_UID_EXPLICIT_BIG_ENDIAN = "1.2.840.10008.1.2.2";

  // Only add the ToggleSwapBytes callback when we need it.
  if (strcmp(TRANSFER_UID_EXPLICIT_BIG_ENDIAN,
             reinterpret_cast<char*>(val)) == 0)
    {
    this->ByteSwapData = true;
    parser->AddDICOMTagCallback(0x0800, 0x0000, DICOMParser::VR_UNKNOWN, ToggleSwapBytesCB);
#ifdef DEBUG_DICOM_APP_HELPER
    dicom_stream::cerr <<"Registering callback for swapping bytes." << dicom_stream::endl;
#endif
    }

  delete this->TransferSyntaxUID;
  this->TransferSyntaxUID = new dicom_stl::string(
    reinterpret_cast<char*>(val));

#ifdef DEBUG_DICOM_APP_HELPER
  dicom_stream::cout << "Transfer Syntax UID: " << *this->TransferSyntaxUID;
  dicom_stream::cout << " " << this->TransferSyntaxUIDDescription(this->TransferSyntaxUID->c_str()) << dicom_stream::endl;
#endif
}

void DICOMAppHelper::BitsAllocatedCallback(DICOMParser *parser,
                                           doublebyte,
                                           doublebyte,
                                           DICOMParser::VRTypes,
                                           unsigned char* val,
                                           quadbyte)
{
  this->BitsAllocated = parser->GetDICOMFile()->ReturnAsUnsignedShort(val, parser->GetDICOMFile()->GetPlatformIsBigEndian());
#ifdef DEBUG_DICOM_APP_HELPER
  dicom_stream::cout << "Bits allocated: " << this->BitsAllocated << dicom_stream::endl;
#endif
}


void DICOMAppHelper::ToggleSwapBytesCallback(DICOMParser *parser,
                                             doublebyte,
                                             doublebyte,
                                             DICOMParser::VRTypes,
                                             unsigned char* ,
                                             quadbyte len)
{
#ifdef DEBUG_DICOM_APP_HELPER
  dicom_stream::cout << "ToggleSwapBytesCallback" << dicom_stream::endl;
#endif
  bool bs = parser->GetDICOMFile()->GetPlatformIsBigEndian();
  parser->GetDICOMFile()->SetPlatformIsBigEndian(!bs);

#ifdef DEBUG_DICOM_APP_HELPER
  dicom_stream::cout << "Set byte swap to: " << parser->GetDICOMFile()->GetPlatformIsBigEndian() << dicom_stream::endl;
#endif

  long pos = parser->GetDICOMFile()->Tell();

  //
  // The +4 is probably a hack, but it's a guess at the length of the previous field.
  //
  parser->GetDICOMFile()->SkipToPos(pos - len + 4);
}


//
// 0028,0030 is Pixel Spacing, which is NOT the pixel spacing for modality such as US, or X-ray
// see Imager Pixel Spacing and Pixel Ratio instead
//
void DICOMAppHelper::PixelSpacingCallback(DICOMParser *parser,
                                          doublebyte group,
                                          doublebyte element,
                                          DICOMParser::VRTypes,
                                          unsigned char* val,
                                          quadbyte)
{
  if (group == 0x0028 && element == 0x0030)
    {
    if (!val || sscanf(reinterpret_cast<char*>(val), "%f\\%f",
                       &this->PixelSpacing[0],
                       &this->PixelSpacing[1]) != 2)
      {
      this->PixelSpacing[0] = this->PixelSpacing[1] = 0.0;
      }
    }
  else if (group == 0x0018 && element == 0x0050)
    {
    this->PixelSpacing[2] =
      DICOMFile::ReturnAsFloat(
        val, parser->GetDICOMFile()->GetPlatformIsBigEndian());
    }
}

void DICOMAppHelper::WidthCallback(DICOMParser *parser,
                                   doublebyte,
                                   doublebyte,
                                   DICOMParser::VRTypes,
                                   unsigned char* val,
                                   quadbyte)
{
  unsigned short uival = DICOMFile::ReturnAsUnsignedShort(val, parser->GetDICOMFile()->GetPlatformIsBigEndian());
#ifdef DEBUG_DICOM_APP_HELPER
  dicom_stream::cout << "Width: " << uival << dicom_stream::endl;
#endif

  this->Width = uival;
  this->Dimensions[0] = this->Width;
}

void DICOMAppHelper::HeightCallback(DICOMParser *parser,
                                    doublebyte,
                                    doublebyte,
                                    DICOMParser::VRTypes,
                                    unsigned char* val,
                                    quadbyte)
{
  unsigned short uival = DICOMFile::ReturnAsUnsignedShort(val, parser->GetDICOMFile()->GetPlatformIsBigEndian());
#ifdef DEBUG_DICOM_APP_HELPER
  dicom_stream::cout << "Height: " << uival << dicom_stream::endl;
#endif
  this->Height = uival;
  this->Dimensions[1] = this->Height;
}


void DICOMAppHelper::PixelRepresentationCallback( DICOMParser *parser,
                                                  doublebyte,
                                                  doublebyte,
                                                  DICOMParser::VRTypes,
                                                  unsigned char* val,
                                                  quadbyte)
{
  unsigned short uival = DICOMFile::ReturnAsUnsignedShort(val, parser->GetDICOMFile()->GetPlatformIsBigEndian());
#ifdef DEBUG_DICOM_APP_HELPER
  dicom_stream::cout << "Pixel Representation: " << (uival ? "Signed" : "Unsigned") << dicom_stream::endl;
#endif
  this->PixelRepresentation = uival;
}

void DICOMAppHelper::PhotometricInterpretationCallback( DICOMParser *,
                                                        doublebyte,
                                                        doublebyte,
                                                        DICOMParser::VRTypes,
                                                        unsigned char* val,
                                                        quadbyte)
{
#ifdef DEBUG_DICOM_APP_HELPER
  dicom_stream::cout << "Photometric Interpretation: " << (char*) val << dicom_stream::endl;
#endif
  delete this->PhotometricInterpretation;

  this->PhotometricInterpretation = new dicom_stl::string(
    reinterpret_cast<char*>(val));
}

void DICOMAppHelper::PixelDataCallback( DICOMParser *,
                                        doublebyte,
                                        doublebyte,
                                        DICOMParser::VRTypes,
                                        unsigned char* data,
                                        quadbyte len)
{
  int numPixels = this->Dimensions[0] * this->Dimensions[1] * this->GetNumberOfComponents();
  if (len < numPixels)
    {
    numPixels = len;
    }
  if (numPixels < 0)
    {
    numPixels = 0;
    }

#ifdef DEBUG_DICOM_APP_HELPER
  dicom_stream::cout << "numPixels : " << numPixels << dicom_stream::endl;
#endif

  int ptrIncr = int(this->BitsAllocated/8.0);

  unsigned short* ushortInputData = reinterpret_cast<unsigned short*>(data);
  unsigned char* ucharInputData = data;
  short* shortInputData = reinterpret_cast<short*> (data);

  float* floatOutputData; // = NULL;

  bool isFloat = this->RescaledImageDataIsFloat();

  if (isFloat)
    {
#ifdef DEBUG_DICOM_APP_HELPER
    dicom_stream::cout << "Slope and offset are not integer valued : ";
    dicom_stream::cout << this->RescaleSlope << ", " << this->RescaleOffset << dicom_stream::endl;
#endif
    delete [] (static_cast<char*> (this->ImageData));
    this->ImageData = new float[numPixels];
    floatOutputData = static_cast<float*> (this->ImageData);

    this->ImageDataType = DICOMParser::VR_FL;
    unsigned long uNumPixels=static_cast<unsigned long>(numPixels);
    this->ImageDataLengthInBytes = uNumPixels*sizeof(float);
    float newFloatPixel;

    if (ptrIncr == 1)
      {
      for (int i = 0; i < numPixels; i++)
        {
        newFloatPixel = float(static_cast<double>(this->RescaleSlope) * ucharInputData[i] + static_cast<double>(this->RescaleOffset));
        floatOutputData[i] = newFloatPixel;
        }
#ifdef DEBUG_DICOM_APP_HELPER
      dicom_stream::cout << "Did rescale, offset to float from char." << dicom_stream::endl;
      dicom_stream::cout << numPixels << " pixels." << dicom_stream::endl;
#endif
      }
    else if (ptrIncr == 2)
      {
      for (int i = 0; i < numPixels; i++)
        {
        newFloatPixel = float(static_cast<double>(this->RescaleSlope) * ushortInputData[i] + static_cast<double>(this->RescaleOffset));
        floatOutputData[i] = newFloatPixel;
        }
#ifdef DEBUG_DICOM_APP_HELPER
      dicom_stream::cout << "Did rescale, offset to float from short." << dicom_stream::endl;
      dicom_stream::cout << numPixels << " pixels." << dicom_stream::endl;
#endif
      }
    }
  else
    {
#ifdef DEBUG_DICOM_APP_HELPER
    dicom_stream::cout << "Slope and offset are integer valued : ";
    dicom_stream::cout << this->RescaleSlope << ", " << this->RescaleOffset << dicom_stream::endl;
#endif

    if (ptrIncr == 1)
      {
      delete [] (static_cast<char*> (this->ImageData));
      this->ImageData = new char[numPixels];

      char*  charOutputData =  static_cast<char*>  (this->ImageData);

      this->ImageDataType = DICOMParser::VR_OB;
      unsigned long uNumPixels=static_cast<unsigned long>(numPixels);
      this->ImageDataLengthInBytes = uNumPixels * sizeof(char);
      char newCharPixel;

      for (int i = 0; i < numPixels; i++)
        {
        newCharPixel = char(static_cast<double>(this->RescaleSlope) * ucharInputData[i] + static_cast<double>(this->RescaleOffset));
        charOutputData[i] = newCharPixel;
        }
#ifdef DEBUG_DICOM_APP_HELPER
      dicom_stream::cout << "Did rescale, offset to char from char." << dicom_stream::endl;
      dicom_stream::cout << numPixels << " pixels." << dicom_stream::endl;
#endif
      }
    else if (ptrIncr == 2)
      {
      delete [] (static_cast<char*> (this->ImageData));
      this->ImageData = new short[numPixels];
      short* shortOutputData = static_cast<short*> (this->ImageData);

      this->ImageDataType = DICOMParser::VR_OW;
      unsigned long uNumPixels=static_cast<unsigned long>(numPixels);
      this->ImageDataLengthInBytes = uNumPixels * sizeof(short);
      short newShortPixel;
      for (int i = 0; i < numPixels; i++)
        {
        newShortPixel = short(static_cast<double>(this->RescaleSlope) * shortInputData[i] + static_cast<double>(this->RescaleOffset));
        shortOutputData[i] = newShortPixel;
        }
#ifdef DEBUG_DICOM_APP_HELPER
      dicom_stream::cout << "Did rescale, offset to short from short." << dicom_stream::endl;
      dicom_stream::cout << numPixels << " pixels." << dicom_stream::endl;
#endif
      }
    }
}

void DICOMAppHelper::RegisterPixelDataCallback(DICOMParser* parser)
{
  this->PixelDataCB->SetCallbackFunction(this, &DICOMAppHelper::PixelDataCallback);
  parser->AddDICOMTagCallback(0x7FE0, 0x0010, DICOMParser::VR_OW, this->PixelDataCB);
}

void DICOMAppHelper::RescaleOffsetCallback( DICOMParser *parser,
                                            doublebyte,
                                            doublebyte,
                                            DICOMParser::VRTypes,
                                            unsigned char* val,
                                            quadbyte)
{
  float fval = DICOMFile::ReturnAsFloat(val, parser->GetDICOMFile()->GetPlatformIsBigEndian());
  this->RescaleOffset = fval;
#ifdef DEBUG_DICOM_APP_HELPER
  dicom_stream::cout << "Pixel offset: " << this->RescaleOffset << dicom_stream::endl;
#endif
}

上一篇:解决高版本使用Gson报错Caused by: java.lang.NoClassDefFoundError: java/sql/Time


下一篇:Redis底层和缓存雪崩,击穿,穿透-2.Redis数据结构—inset