7 #include "fwGdcmIO/helper/DicomSeries.hpp" 9 #include "fwGdcmIO/helper/DicomDir.hpp" 11 #include <fwCore/exceptionmacros.hpp> 14 #include <fwJobs/Aggregator.hpp> 15 #include <fwJobs/IJob.hpp> 16 #include <fwJobs/Job.hpp> 17 #include <fwJobs/Observer.hpp> 19 #include <fwMedData/DicomSeries.hpp> 20 #include <fwMedData/Equipment.hpp> 21 #include <fwMedData/Patient.hpp> 22 #include <fwMedData/Study.hpp> 24 #include <boost/algorithm/string.hpp> 25 #include <boost/filesystem/operations.hpp> 26 #include <boost/regex.h> 28 #include <gdcmMediaStorage.h> 29 #include <gdcmReader.h> 39 static const ::gdcm::Tag s_MediaStorageSOPClassUID(0x0002, 0x0002);
40 static const ::gdcm::Tag s_SpecificCharacterSetTag(0x0008, 0x0005);
41 static const ::gdcm::Tag s_SeriesInstanceUIDTag(0x0020, 0x000e);
42 static const ::gdcm::Tag s_SeriesDateTag(0x0008, 0x0021);
43 static const ::gdcm::Tag s_SeriesTimeTag(0x0008, 0x0031);
44 static const ::gdcm::Tag s_ModalityTag(0x0008, 0x0060);
45 static const ::gdcm::Tag s_SeriesDescriptionTag(0x0008, 0x103e);
46 static const ::gdcm::Tag s_PerformingPhysicianNameTag(0x0008, 0x1050);
47 static const ::gdcm::Tag s_SOPClassUIDTag(0x0008, 0x0016);
49 static const ::gdcm::Tag s_InstitutionNameTag(0x0008, 0x0080);
51 static const ::gdcm::Tag s_PatientNameTag(0x0010, 0x0010);
52 static const ::gdcm::Tag s_PatientIDTag(0x0010, 0x0020);
53 static const ::gdcm::Tag s_PatientBirthDateTag(0x0010, 0x0030);
54 static const ::gdcm::Tag s_PatientSexTag(0x0010, 0x0040);
56 static const ::gdcm::Tag s_StudyInstanceUIDTag(0x0020, 0x000d);
57 static const ::gdcm::Tag s_StudyDateTag(0x0008, 0x0020);
58 static const ::gdcm::Tag s_StudyTimeTag(0x0008, 0x0030);
59 static const ::gdcm::Tag s_ReferringPhysicianNameTag(0x0008, 0x0090);
60 static const ::gdcm::Tag s_StudyDescriptionTag(0x0008, 0x1030);
61 static const ::gdcm::Tag s_PatientAgeTag(0x0010, 0x1010);
65 std::string getStringValue(const ::gdcm::Scanner& scanner,
66 const std::string& filename,
69 std::string result =
"";
70 const char* value = scanner.GetValue( filename.c_str(), tag );
74 result = ::gdcm::LOComp::Trim(value);
81 std::string getStringValue(const ::gdcm::DataSet& dataset,
84 std::string result =
"";
85 if (dataset.FindDataElement(tag))
87 const ::gdcm::DataElement& dataElement = dataset.GetDataElement(tag);
89 if (!dataElement.IsEmpty())
92 const ::gdcm::ByteValue* bv = dataElement.GetByteValue();
95 std::string buffer(bv->GetPointer(), bv->GetLength());
97 result = ::gdcm::LOComp::Trim(buffer.c_str());
131 std::set< ::gdcm::Tag > selectedtags;
132 selectedtags.insert( s_SpecificCharacterSetTag);
133 selectedtags.insert( s_SeriesInstanceUIDTag);
134 selectedtags.insert( s_ModalityTag);
135 selectedtags.insert( s_SeriesDateTag);
136 selectedtags.insert( s_SeriesTimeTag);
137 selectedtags.insert( s_SeriesDescriptionTag);
138 selectedtags.insert( s_PerformingPhysicianNameTag);
139 selectedtags.insert( s_SOPClassUIDTag);
141 for(
const auto& series : seriesDB)
143 if(series->getDicomContainer().empty())
145 SLM_ERROR(
"DicomSeries doesn't not contain any instance.");
148 const auto& firstItem = series->getDicomContainer().begin();
149 const ::fwMemory::BufferObject::sptr bufferObj = firstItem->second;
150 const ::fwMemory::BufferManager::StreamInfo streamInfo = bufferObj->getStreamInfo();
151 SPTR(std::istream) is = streamInfo.stream;
153 ::gdcm::Reader reader;
154 reader.SetStream(*is);
156 if(!reader.ReadSelectedTags(selectedtags))
158 FW_RAISE(
"Unable to read Dicom file '"<< bufferObj->getStreamInfo().fsFile.string() <<
"' "<<
159 "(slice: '" << firstItem->first <<
"')");
161 const ::gdcm::DataSet& dataset = reader.GetFile().GetDataSet();
164 std::string modality = getStringValue( dataset, s_ModalityTag );
165 series->setModality(modality);
168 std::string seriesDate = getStringValue( dataset, s_SeriesDateTag );
169 series->setDate(seriesDate);
172 std::string seriesTime = getStringValue( dataset, s_SeriesTimeTag );
173 series->setTime(seriesTime);
176 std::string seriesDescription = getStringValue( dataset, s_SeriesDescriptionTag );
177 series->setDescription(seriesDescription);
180 std::string performingPhysicianNamesStr = getStringValue( dataset, s_PerformingPhysicianNameTag );
182 if(!performingPhysicianNamesStr.empty())
184 ::fwMedData::DicomValuesType performingPhysicianNames;
185 ::boost::split( performingPhysicianNames, performingPhysicianNamesStr, ::boost::is_any_of(
"\\"));
186 series->setPerformingPhysiciansName(performingPhysicianNames);
190 std::string sopClassUID = getStringValue( dataset, s_SOPClassUIDTag );
191 ::fwMedData::DicomSeries::SOPClassUIDContainerType sopClassUIDContainer = series->getSOPClassUIDs();
192 sopClassUIDContainer.insert(sopClassUID);
193 series->setSOPClassUIDs(sopClassUIDContainer);
196 this->
fillSeries(seriesDB, completeSeriesObserver);
202 const ::fwJobs::Observer::sptr& readerObserver)
204 ::gdcm::Scanner seriesScanner;
205 seriesScanner.AddTag(s_SpecificCharacterSetTag);
206 seriesScanner.AddTag(s_SeriesInstanceUIDTag);
207 seriesScanner.AddTag(s_ModalityTag);
208 seriesScanner.AddTag(s_SeriesDateTag);
209 seriesScanner.AddTag(s_SeriesTimeTag);
210 seriesScanner.AddTag(s_SeriesDescriptionTag);
211 seriesScanner.AddTag(s_PerformingPhysicianNameTag);
212 seriesScanner.AddTag(s_SOPClassUIDTag);
213 seriesScanner.AddTag(s_MediaStorageSOPClassUID);
215 readerObserver->setTotalWorkUnits(filenames.size());
216 readerObserver->doneWork(0);
218 std::vector< std::string > fileVec;
219 for(
auto file : filenames)
221 fileVec.push_back(file.string());
224 bool status = seriesScanner.Scan( fileVec );
225 FW_RAISE_IF(
"Unable to read the files.", !status);
227 ::gdcm::Directory::FilenamesType keys = seriesScanner.GetKeys();
228 ::gdcm::Directory::FilenamesType::const_iterator it;
230 unsigned int progress = 0;
232 DicomSeriesContainerType seriesDB;
235 for(const ::boost::filesystem::path& dicomFile : filenames)
237 auto filename = dicomFile.string();
239 OSLM_ASSERT(
"The file \"" << dicomFile <<
"\" is not a key of the gdcm scanner",
240 seriesScanner.IsKey(filename.c_str()));
242 const std::string sopClassUID = getStringValue(seriesScanner, filename, s_SOPClassUIDTag);
243 const std::string mediaStorageSopClassUID = getStringValue(seriesScanner, filename, s_MediaStorageSOPClassUID);
245 if(sopClassUID != ::gdcm::MediaStorage::GetMSString(::gdcm::MediaStorage::MediaStorageDirectoryStorage)
246 && mediaStorageSopClassUID
247 != ::gdcm::MediaStorage::GetMSString(::gdcm::MediaStorage::MediaStorageDirectoryStorage))
253 if (!readerObserver || readerObserver->cancelRequested())
258 readerObserver->doneWork(static_cast< std::uint64_t >(++progress * 100 / keys.size()));
267 const ::fwJobs::Observer::sptr& completeSeriesObserver)
273 std::set< ::gdcm::Tag > selectedtags;
274 selectedtags.insert(s_SpecificCharacterSetTag);
275 selectedtags.insert(s_PatientIDTag);
276 selectedtags.insert(s_PatientNameTag);
277 selectedtags.insert(s_PatientBirthDateTag);
278 selectedtags.insert(s_PatientSexTag);
279 selectedtags.insert(s_StudyInstanceUIDTag);
280 selectedtags.insert(s_StudyDateTag);
281 selectedtags.insert(s_StudyTimeTag);
282 selectedtags.insert(s_ReferringPhysicianNameTag);
283 selectedtags.insert(s_StudyDescriptionTag);
284 selectedtags.insert(s_PatientAgeTag);
285 selectedtags.insert(s_InstitutionNameTag);
286 selectedtags.insert(s_SeriesInstanceUIDTag);
288 std::uint64_t progress = 0;
291 for(const ::fwMedData::DicomSeries::sptr& series : seriesDB)
294 const size_t size = series->getDicomContainer().size();
295 series->setNumberOfInstances(size);
299 SLM_ERROR(
"The DicomSeries doesn't contain any instance.");
304 const auto& firstItem = series->getDicomContainer().begin();
305 const ::fwMemory::BufferObject::sptr bufferObj = firstItem->second;
306 const ::fwMemory::BufferManager::StreamInfo streamInfo = bufferObj->getStreamInfo();
307 SPTR(std::istream) is = streamInfo.stream;
309 ::gdcm::Reader reader;
310 reader.SetStream(*is);
312 if(!reader.ReadSelectedTags(selectedtags))
314 FW_RAISE(
"Unable to read Dicom file '"<< bufferObj->getStreamInfo().fsFile.string() <<
"' "<<
315 "(slice: '" << firstItem->first <<
"')");
317 const ::gdcm::DataSet& dataset = reader.GetFile().GetDataSet();
320 ::fwMedData::Patient::sptr patient = this->
createPatient(dataset);
321 ::fwMedData::Study::sptr study = this->
createStudy(dataset);
322 ::fwMedData::Equipment::sptr equipment = this->
createEquipment(dataset);
325 series->setPatient(patient);
326 series->setStudy(study);
327 series->setEquipment(equipment);
329 if(completeSeriesObserver)
331 completeSeriesObserver->doneWork(static_cast<std::uint64_t>(++progress * 100 / seriesDB.size() ));
333 if(completeSeriesObserver->cancelRequested())
344 const ::gdcm::Scanner& scanner,
345 const ::boost::filesystem::path& filename)
347 ::fwMedData::DicomSeries::sptr series = ::fwMedData::DicomSeries::sptr();
349 const std::string stringFilename = filename.string();
352 std::string seriesInstanceUID = getStringValue( scanner, stringFilename, s_SeriesInstanceUIDTag );
355 for(::fwMedData::DicomSeries::sptr dicomSeries : seriesDB)
357 if(dicomSeries->getInstanceUID() == seriesInstanceUID)
359 series = dicomSeries;
367 series = ::fwMedData::DicomSeries::New();
369 seriesDB.push_back(series);
372 series->setInstanceUID(seriesInstanceUID);
375 std::string modality = getStringValue( scanner, stringFilename, s_ModalityTag );
376 series->setModality(modality);
379 std::string seriesDate = getStringValue( scanner, stringFilename, s_SeriesDateTag );
380 series->setDate(seriesDate);
383 std::string seriesTime = getStringValue( scanner, stringFilename, s_SeriesTimeTag );
384 series->setTime(seriesTime);
387 std::string seriesDescription = getStringValue( scanner, stringFilename, s_SeriesDescriptionTag );
388 series->setDescription(seriesDescription);
391 std::string performingPhysicianNamesStr = getStringValue( scanner, stringFilename,
392 s_PerformingPhysicianNameTag );
394 if(!performingPhysicianNamesStr.empty())
396 ::fwMedData::DicomValuesType performingPhysicianNames;
397 ::boost::split( performingPhysicianNames, performingPhysicianNamesStr, ::boost::is_any_of(
"\\"));
398 series->setPerformingPhysiciansName(performingPhysicianNames);
403 std::string sopClassUID = getStringValue( scanner, stringFilename, s_SOPClassUIDTag );
404 ::fwMedData::DicomSeries::SOPClassUIDContainerType sopClassUIDContainer = series->getSOPClassUIDs();
405 sopClassUIDContainer.insert(sopClassUID);
406 series->setSOPClassUIDs(sopClassUIDContainer);
409 const size_t instanceNumber = series->getDicomContainer().size();
410 series->addDicomPath(instanceNumber, filename);
417 ::fwMedData::Patient::sptr result;
420 std::string patientID = getStringValue( dataset, s_PatientIDTag );
425 result = ::fwMedData::Patient::New();
429 result->setPatientId(patientID);
432 std::string patientName = getStringValue( dataset, s_PatientNameTag );
433 result->setName(patientName);
436 std::string patientBirthDate = getStringValue( dataset, s_PatientBirthDateTag );
437 result->setBirthdate(patientBirthDate);
440 std::string patientSex = getStringValue( dataset, s_PatientSexTag );
441 result->setSex(patientSex);
446 result = ::fwMedData::Patient::New();
457 ::fwMedData::Study::sptr result;
460 std::string studyInstanceUID = getStringValue( dataset, s_StudyInstanceUIDTag );
465 result = ::fwMedData::Study::New();
469 result->setInstanceUID(studyInstanceUID);
472 std::string studyDate = getStringValue( dataset, s_StudyDateTag );
473 result->setDate(studyDate);
476 std::string studyTime = getStringValue( dataset, s_StudyTimeTag );
477 result->setTime(studyTime);
480 std::string referringPhysicianName = getStringValue( dataset, s_ReferringPhysicianNameTag );
481 result->setReferringPhysicianName(referringPhysicianName);
484 std::string studyDescription = getStringValue( dataset, s_StudyDescriptionTag );
485 result->setDescription(studyDescription);
488 std::string patientAge = getStringValue( dataset, s_PatientAgeTag );
489 result->setPatientAge(patientAge);
494 result = ::fwMedData::Study::New();
495 result->deepCopy(
m_studyMap[studyInstanceUID]);
505 ::fwMedData::Equipment::sptr result;
508 std::string institutionName = getStringValue( dataset, s_InstitutionNameTag );
513 result = ::fwMedData::Equipment::New();
517 result->setInstitutionName(institutionName);
522 result = ::fwMedData::Equipment::New();
#define OSLM_ASSERT(message, cond)
work like 'assert' from 'cassert', with in addition a message logged by spylog (with FATAL loglevel) ...
std::shared_ptr< ::fwMedData::Patient > createPatient(const ::gdcm::DataSet &dataset)
Create a patient from the dataset and store it in the patient map.
void fillSeries(DicomSeriesContainerType &seriesDB, const std::shared_ptr< ::fwJobs::Observer > &completeSeriesObserver)
Fill series with information contained in first instance.
void createSeries(DicomSeriesContainerType &seriesDB, const ::gdcm::Scanner &scanner, const ::boost::filesystem::path &filename)
Create a series from the dataset and store it in the series map.
The namespace fwGdcmIO contains reader, writer and helper for dicom data.
EquipmentMapType m_equipmentMap
Equipment Map.
DicomSeriesContainerType splitFiles(FilenameContainerType &filenames, const std::shared_ptr< ::fwJobs::Observer > &readerObserver)
Create DicomSeries from list of files. Every instance is read in order to retrieve instance informati...
PatientMapType m_patientMap
Patient Map.
#define SLM_ERROR(message)
std::shared_ptr< ::fwMedData::Equipment > createEquipment(const ::gdcm::DataSet &dataset)
Create an equipment from the dataset and store it in the equipment map.
std::shared_ptr< ::fwMedData::Study > createStudy(const ::gdcm::DataSet &dataset)
Create a study from the dataset and store it in the study map.
FWGDCMIO_API DicomSeriesContainerType read(FilenameContainerType &filenames, const std::shared_ptr< ::fwJobs::Observer > &readerObserver=nullptr, const std::shared_ptr< ::fwJobs::Observer > &completeSeriesObserver=nullptr)
Read DicomSeries from paths.
FWGDCMIO_API void complete(DicomSeriesContainerType &seriesDB, const std::shared_ptr< ::fwJobs::Observer > &completeSeriesObserver)
Fill DicomSeries information for series generated using DICOMDIR helper.
FWGDCMIO_API DicomSeries()
Constructor.
StudyMapType m_studyMap
Study Map.
FWGDCMIO_API ~DicomSeries()
Destructor.
This file defines SpyLog macros. These macros are used to log messages to a file or to the console du...
This class manages a job.