欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > 名人名企 > 读取每一张DICOM文件的图像数据(二)

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

2024/10/23 5:17:08 来源:https://blog.csdn.net/laziji/article/details/143057011  浏览:    关键词:读取每一张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*2this->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 rowfor (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;}}
}void DICOMParser::ReadNextRecord(doublebyte& group, doublebyte& element, DICOMParser::VRTypes& mytype)
{// 1. 读取组&元素// 2. 分析记录//      a. 查看下两个字节是不是一个有效的数据类型//      b. 如果类型有效,查找对应的类型字符长度// 3.   如果分析显示记录失败,分析隐式记录//      a. 查找隐式记录数据类型// 4. 查看该数据组&元素有没有注册相应的回调函数// 5. 如果有对应的回调函数,运行回调函数,回调数据,否则跳过数据,继续往下group = DataFile->ReadDoubleByte();element = DataFile->ReadDoubleByte();doublebyte representation = DataFile->ReadDoubleByteAsLittleEndian();quadbyte length = 0;mytype = DICOMParser::VR_UNKNOWN;this->IsValidRepresentation(representation, length, mytype);DICOMParserMap::iterator iter =Implementation->Map.find(DICOMMapKey(group,element));VRTypes callbackType;if (iter != Implementation->Map.end()){//// Only read the data if there's a registered callback.//unsigned char* tempdata = reinterpret_cast<unsigned char*>(DataFile->ReadAsciiCharArray(length));DICOMMapKey ge = (*iter).first;callbackType = VRTypes(((*iter).second.first));if (callbackType != mytype &&mytype != VR_UNKNOWN){//// mytype is not VR_UNKNOWN if the file is in Explicit format.//callbackType = mytype;}dicom_stl::pair<const DICOMMapKey,DICOMMapValue> p = *iter;DICOMMapValue mv = p.second;bool doSwap = (this->ToggleByteSwapImageData ^ this->DataFile->GetPlatformIsBigEndian()) && callbackType == VR_OW;if (group == 0x7FE0 &&element == 0x0010 ){if (doSwap){size_t uLength=static_cast<size_t>(length);DICOMFile::swap2(reinterpret_cast<ushort*>(tempdata),reinterpret_cast<ushort*>(tempdata),static_cast<int>(uLength/sizeof(ushort)));}else{}}else{if (this->DataFile->GetPlatformIsBigEndian() == true){size_t uLength=static_cast<size_t>(length);switch (callbackType){case DICOMParser::VR_OW:case DICOMParser::VR_US:case DICOMParser::VR_SS:DICOMFile::swap2(reinterpret_cast<ushort*>(tempdata),reinterpret_cast<ushort*>(tempdata),static_cast<int>(uLength/sizeof(ushort)));break;case DICOMParser::VR_FL:case DICOMParser::VR_FD:// No need to byte swap here, since these values were read by sscanfbreak;case DICOMParser::VR_SL:case DICOMParser::VR_UL:DICOMFile::swap4(reinterpret_cast<uint*>(tempdata),reinterpret_cast<uint*>(tempdata),static_cast<int>(uLength/sizeof(uint)));break;case DICOMParser::VR_AT:break;case VR_UNKNOWN:case VR_DA:case VR_OB:case VR_AE:case VR_SH:case VR_UI:case VR_TM:case VR_PN:case VR_UN:case VR_LO:case VR_SQ:case VR_AS:case VR_CS:case VR_DS:case VR_IS:case VR_DT:case VR_LT:case VR_ST:case VR_UT:case VR_AW:default:break;}}}dicom_stl::vector<DICOMCallback*> * cbVector = mv.second;for (dicom_stl::vector<DICOMCallback*>::iterator cbiter = cbVector->begin();cbiter != cbVector->end();cbiter++){//*cbiter 是DICOMAppHelper类的构造函数new 出来的对象。(*cbiter)->Execute(this,      // parserge.first,  // groupge.second,  // elementcallbackType,  // typetempdata, // datalength);  // length}delete [] tempdata;}else{//// Some lengths are negative, but we don't// want to back up the file pointer.//if (length > 0){DataFile->Skip(length);}}}
//该函数注册回调函数,并读取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_HELPERDICOMMemberCallback<DICOMAppHelper>** callbackArray = new DICOMMemberCallback<DICOMAppHelper>*[num_tags];
#endiffor (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;}}
}//注意函数中的returnASxxxxxx()函数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 bytescase DICOMParser::VR_OW: // ordered wordscase DICOMParser::VR_PN:case DICOMParser::VR_ST:case DICOMParser::VR_TM:case DICOMParser::VR_UN:case DICOMParser::VR_UT:case DICOMParser::VR_SQ: // sequencecase DICOMParser::VR_SH: // stringscase DICOMParser::VR_IS:HeaderFile << val;break;case DICOMParser::VR_FL: // floatfval = static_cast<float> (atof(reinterpret_cast<char*>(val)));HeaderFile << fval;break;case DICOMParser::VR_FD: // float doubledval = static_cast<double> (atof(reinterpret_cast<char*>(val)));HeaderFile << dval;break;case DICOMParser::VR_UL: // unsigned longcase DICOMParser::VR_SL: // signed longcase DICOMParser::VR_AT:HeaderFile << uival;break;case DICOMParser::VR_SS:ival = DICOMFile::ReturnAsSignedShort(val, parser->GetDICOMFile()->GetPlatformIsBigEndian());HeaderFile << ival;break;case DICOMParser::VR_US: // unsigned shortuival = 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 datadicom_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 entryDICOMOrderingElements ord;if( val ){ord.SliceNumber = atoi(reinterpret_cast<char *>(val));}else // Slice Number present but empty{ord.SliceNumber = 0;}// insert into the mapthis->Implementation->SliceOrderingMap.insert(dicom_stl::pair<const dicom_stl::string,DICOMOrderingElements>(parser->GetFileName(), ord));}else{// file found, add new valuesif( val ){(*it).second.SliceNumber = atoi(reinterpret_cast<char *>(val));}else // Slice Number present but empty{(*it).second.SliceNumber = 0;}}// cache the slice numberif( 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 datadicom_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 entryDICOMOrderingElements ord;ord.SliceLocation = static_cast<float>(atof(reinterpret_cast<char *>(val)));// insert into the mapthis->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 datadicom_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 entryDICOMOrderingElements 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 originord.ImagePositionPatient[0] = 0.0;ord.ImagePositionPatient[1] = 0.0;ord.ImagePositionPatient[2] = 0.0;}// insert into the mapthis->Implementation->SliceOrderingMap.insert(dicom_stl::pair<const dicom_stl::string,DICOMOrderingElements>(parser->GetFileName(), ord));// cache the valuememcpy( this->ImagePositionPatient, ord.ImagePositionPatient,3*sizeof(float) );}else{if (val){// file found, add new valuessscanf( 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 valuememcpy( 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 datadicom_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 entryDICOMOrderingElements 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 orientationord.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 mapthis->Implementation->SliceOrderingMap.insert(dicom_stl::pair<const dicom_stl::string,DICOMOrderingElements>(parser->GetFileName(), ord));// cache the valuememcpy( this->ImageOrientationPatient, ord.ImageOrientationPatient,6*sizeof(float) );}else{// file found, add new valuesif (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 valuememcpy( 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 _WIN32char platformByteOrder = 'L';
#elsechar platformByteOrder = 'B';
#endifdicom_stream::cout << "Platform byte order: " << platformByteOrder << dicom_stream::endl;
#endifstatic 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_HELPERdicom_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_HELPERdicom_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)
{//从DICOMFIle中读取数据,包括Header。 this->BitsAllocated = parser->GetDICOMFile()->ReturnAsUnsignedShort(val, parser->GetDICOMFile()->GetPlatformIsBigEndian());
#ifdef DEBUG_DICOM_APP_HELPERdicom_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_HELPERdicom_stream::cout << "ToggleSwapBytesCallback" << dicom_stream::endl;
#endifbool bs = parser->GetDICOMFile()->GetPlatformIsBigEndian();parser->GetDICOMFile()->SetPlatformIsBigEndian(!bs);#ifdef DEBUG_DICOM_APP_HELPERdicom_stream::cout << "Set byte swap to: " << parser->GetDICOMFile()->GetPlatformIsBigEndian() << dicom_stream::endl;
#endiflong 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)
{//获取图像宽度 DICOMFile::ReturnAsUnsignedShortunsigned short uival = DICOMFile::ReturnAsUnsignedShort(val, parser->GetDICOMFile()->GetPlatformIsBigEndian());
#ifdef DEBUG_DICOM_APP_HELPERdicom_stream::cout << "Width: " << uival << dicom_stream::endl;
#endifthis->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_HELPERdicom_stream::cout << "Height: " << uival << dicom_stream::endl;
#endifthis->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_HELPERdicom_stream::cout << "Pixel Representation: " << (uival ? "Signed" : "Unsigned") << dicom_stream::endl;
#endifthis->PixelRepresentation = uival;
}void DICOMAppHelper::PhotometricInterpretationCallback( DICOMParser *,doublebyte,doublebyte,DICOMParser::VRTypes,unsigned char* val,quadbyte)
{
#ifdef DEBUG_DICOM_APP_HELPERdicom_stream::cout << "Photometric Interpretation: " << (char*) val << dicom_stream::endl;
#endifdelete 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_HELPERdicom_stream::cout << "numPixels : " << numPixels << dicom_stream::endl;
#endifint 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_HELPERdicom_stream::cout << "Slope and offset are not integer valued : ";dicom_stream::cout << this->RescaleSlope << ", " << this->RescaleOffset << dicom_stream::endl;
#endifdelete [] (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_HELPERdicom_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_HELPERdicom_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_HELPERdicom_stream::cout << "Slope and offset are integer valued : ";dicom_stream::cout << this->RescaleSlope << ", " << this->RescaleOffset << dicom_stream::endl;
#endifif (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_HELPERdicom_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_HELPERdicom_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_HELPERdicom_stream::cout << "Pixel offset: " << this->RescaleOffset << dicom_stream::endl;
#endif
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com