7 #include "fwGdcmIO/reader/SeriesDB.hpp" 9 #include "fwGdcmIO/helper/DicomDir.hpp" 10 #include "fwGdcmIO/helper/DicomSearch.hpp" 11 #include "fwGdcmIO/helper/DicomSeries.hpp" 12 #include "fwGdcmIO/helper/SOPClass.hpp" 13 #include "fwGdcmIO/reader/Series.hpp" 15 #include <fwDataIO/reader/registry/macros.hpp> 17 #include <fwDicomIOFilter/factory/new.hpp> 18 #include <fwDicomIOFilter/helper/Filter.hpp> 19 #include <fwDicomIOFilter/IFilter.hpp> 21 #include <fwJobs/Aggregator.hpp> 22 #include <fwJobs/Job.hpp> 23 #include <fwJobs/Observer.hpp> 25 #include <fwMedDataTools/helper/SeriesDB.hpp> 27 #include <fwServices/registry/ActiveWorkers.hpp> 29 #include <boost/algorithm/string/split.hpp> 31 #include <gdcmAttribute.h> 32 #include <gdcmDirectory.h> 33 #include <gdcmMediaStorage.h> 47 ::
fwData::location::enableFolder< IObjectReader >(this),
48 ::
fwData::location::enableMultiFiles< IObjectReader >(this),
49 m_isDicomdirActivated(false),
50 m_dicomFilterType(
""),
51 m_logger(::
fwLog::Logger::New()),
52 m_job(::
fwJobs::Aggregator::New(
"DICOM reader")),
53 m_enableBufferRotation(true),
54 m_dicomdirFileLookupJob(::
fwJobs::Observer::New(
"Extracting information from DICOMDIR")),
55 m_regularFileLookupJob(::
fwJobs::Observer::New(
"Looking for DICOM files")),
56 m_readerJob(::
fwJobs::Observer::New(
"Reading DICOM files")),
57 m_completeDicomSeriesJob(::
fwJobs::Observer::New(
"Completing series")),
58 m_converterJob(::
fwJobs::Observer::New(
"DICOM data convertion"))
75 m_dicomSeriesContainer.clear();
77 m_job->add(m_dicomdirFileLookupJob);
78 m_job->add(m_regularFileLookupJob);
79 m_job->add(m_readerJob);
80 m_job->add(m_completeDicomSeriesJob);
81 m_job->add(m_converterJob);
87 catch (
const std::exception& e)
90 m_logger->critical(
"An error has occurred during the reading process : unable to retrieve series.");
93 m_dicomdirFileLookupJob->finish();
94 m_regularFileLookupJob->finish();
95 m_readerJob->finish();
96 m_completeDicomSeriesJob->finish();
97 m_converterJob->finish();
103 if(!m_dicomFilterType.empty())
105 ::fwDicomIOFilter::IFilter::sptr filter = ::fwDicomIOFilter::factory::New(m_dicomFilterType);
109 if(m_dicomSeriesContainer.empty())
111 m_logger->critical(
"Unable to retrieve series from the selected folder.");
112 m_converterJob->done();
113 m_converterJob->finish();
118 this->convertDicomSeries();
126 catch (
const std::exception& e)
128 m_logger->critical(
"An error has occurred during the reading process : " + std::string(e.what()));
132 m_logger->critical(
"An unkown error has occurred during the reading process.");
135 if(m_dicomSeriesContainer.empty())
137 m_logger->critical(
"Unable to retrieve series from the selected folder.");
146 m_dicomSeriesContainer.clear();
148 m_job->add(m_dicomdirFileLookupJob);
149 m_job->add(m_regularFileLookupJob);
150 m_job->add(m_readerJob);
151 m_job->add(m_completeDicomSeriesJob);
157 catch (
const std::exception& e)
160 m_logger->critical(
"An error has occurred during the reading process : unable to retrieve series.");
163 m_dicomdirFileLookupJob->finish();
164 m_regularFileLookupJob->finish();
165 m_readerJob->finish();
166 m_completeDicomSeriesJob->finish();
175 if(!m_job->cancelRequested())
177 for(::fwMedData::DicomSeries::sptr series : m_dicomSeriesContainer)
179 seriesDBHelper.
add(series);
188 catch (
const std::exception& e)
190 m_logger->critical(
"An error has occurred during the reading process : " + std::string(e.what()));
194 m_logger->critical(
"An unkown error has occurred during the reading process.");
197 if(m_dicomSeriesContainer.empty())
199 m_logger->critical(
"Unable to retrieve series from the selected folder.");
206 void SeriesDB::readDicom()
208 SLM_ASSERT(
"This reader only work on folder selection.",
209 (::fwData::location::have < ::fwData::location::Folder, ::fwDataIO::reader::IObjectReader > (
this)));
213 if(m_isDicomdirActivated && ::boost::filesystem::exists(dicomdir))
217 m_dicomSeriesContainer,
219 m_readerJob->progressCallback(),
220 m_readerJob->cancelRequestedCallback()
224 helper.
complete(m_dicomSeriesContainer, m_completeDicomSeriesJob);
229 m_dicomdirFileLookupJob->done();
230 m_dicomdirFileLookupJob->finish();
233 if(!m_isDicomdirActivated || !::boost::filesystem::exists(dicomdir) || m_dicomSeriesContainer.empty())
235 m_readerJob->doneWork(0);
238 std::vector< ::boost::filesystem::path > filenames;
240 this->
getFolder(), filenames,
true, m_regularFileLookupJob);
244 m_dicomSeriesContainer = helper.
read(filenames, m_readerJob, m_completeDicomSeriesJob);
248 m_regularFileLookupJob->done();
249 m_regularFileLookupJob->finish();
253 m_readerJob->finish();
256 m_completeDicomSeriesJob->done();
257 m_completeDicomSeriesJob->finish();
264 const ::fwServices::IService::sptr& notifier)
267 m_dicomSeriesContainer.clear();
269 m_job->add(m_converterJob);
272 for(::fwMedData::Series::sptr series : dicomSeriesDB->getContainer())
274 ::fwMedData::DicomSeries::sptr dicomSeries = ::fwMedData::DicomSeries::dynamicCast(series);
275 SLM_ASSERT(
"Trying to read a series which is not a DicomSeries.", dicomSeries);
276 m_dicomSeriesContainer.push_back(dicomSeries);
280 if(!m_dicomFilterType.empty())
282 ::fwDicomIOFilter::IFilter::sptr filter = ::fwDicomIOFilter::factory::New(m_dicomFilterType);
286 if(m_dicomSeriesContainer.empty())
288 m_logger->critical(
"Unable to retrieve series from the selected folder.");
289 m_converterJob->done();
290 m_converterJob->finish();
295 this->convertDicomSeries(notifier);
303 catch (
const std::exception& e)
305 m_logger->critical(
"An error has occurred during the reading process : " + std::string(e.what()));
309 m_logger->critical(
"An unkown error has occurred during the reading process.");
319 return ::boost::filesystem::exists(dicomdir);
324 void SeriesDB::convertDicomSeries(const ::fwServices::IService::sptr& notifier)
329 std::sort(m_dicomSeriesContainer.begin(), m_dicomSeriesContainer.end(), SeriesDB::dicomSeriesComparator);
333 seriesReader->setBufferRotationEnabled(m_enableBufferRotation);
334 seriesReader->setLogger(m_logger);
336 m_converterJob->setTotalWorkUnits(m_dicomSeriesContainer.size());
341 std::uint64_t totalWorkUnits = 0;
342 for(const ::fwMedData::DicomSeries::sptr& dicomSeries : m_dicomSeriesContainer)
344 totalWorkUnits += dicomSeries->getDicomContainer().size();
346 m_converterJob->setTotalWorkUnits(totalWorkUnits);
348 std::uint64_t completedProgress = 0;
349 auto progressCallback = [&](std::uint64_t progress)
351 m_converterJob->doneWork(completedProgress + progress);
355 for(const ::fwMedData::DicomSeries::csptr& dicomSeries : m_dicomSeriesContainer)
357 ::fwMedData::DicomSeries::SOPClassUIDContainerType sopClassUIDContainer = dicomSeries->getSOPClassUIDs();
358 FW_RAISE_IF(
"The series contains several SOPClassUIDs. Try to apply a filter in order to split the series.",
359 sopClassUIDContainer.size() != 1);
360 const std::string sopClassUID = sopClassUIDContainer.begin()->c_str();
362 const SupportedSOPClassContainerType::iterator bIt = m_supportedSOPClassContainer.begin();
363 const SupportedSOPClassContainerType::iterator eIt = m_supportedSOPClassContainer.end();
365 if(m_supportedSOPClassContainer.empty() || std::find(bIt, eIt, sopClassUID) != eIt)
367 seriesReader->setProgressCallback(progressCallback);
368 seriesReader->setCancelRequestedCallback(m_converterJob->cancelRequestedCallback());
371 ::fwMedData::Series::sptr series = seriesReader->read(dicomSeries);
377 seriesDBHelper.
add(series);
387 m_logger->critical(
"Unable to read series : " + dicomSeries->getInstanceUID());
393 m_logger->critical(
"DICOM SOP Class \"" + sopClassName +
"\" is not supported by the selected reader.");
396 if(m_job->cancelRequested())
401 completedProgress = m_converterJob->getDoneWorkUnits();
404 m_converterJob->done();
405 m_converterJob->finish();
414 const ::fwMedData::DicomSeries::SOPClassUIDContainerType aSOPClassUIDContainer = a->
getSOPClassUIDs();
415 const std::string aSOPClassUID = *(aSOPClassUIDContainer.begin());
416 const ::fwMedData::DicomSeries::SOPClassUIDContainerType bSOPClassUIDContainer = b->
getSOPClassUIDs();
417 const std::string bSOPClassUID = *(bSOPClassUIDContainer.begin());
420 const bool aIsAnImage =
421 (::gdcm::MediaStorage::GetMSType(aSOPClassUID.c_str()) == ::gdcm::MediaStorage::EnhancedSR ||
422 ::gdcm::MediaStorage::GetMSType(aSOPClassUID.c_str()) == ::gdcm::MediaStorage::ComprehensiveSR ||
423 aSOPClassUID ==
"1.2.840.10008.5.1.4.1.1.88.34" ||
426 ::gdcm::MediaStorage::GetMSType(aSOPClassUID.c_str()) == ::gdcm::MediaStorage::SpacialFiducialsStorage ||
427 ::gdcm::MediaStorage::GetMSType(aSOPClassUID.c_str()) == ::gdcm::MediaStorage::SurfaceSegmentationStorage);
429 const bool bIsAnImage =
430 (::gdcm::MediaStorage::GetMSType(bSOPClassUID.c_str()) == ::gdcm::MediaStorage::EnhancedSR ||
431 ::gdcm::MediaStorage::GetMSType(bSOPClassUID.c_str()) == ::gdcm::MediaStorage::ComprehensiveSR ||
432 bSOPClassUID ==
"1.2.840.10008.5.1.4.1.1.88.34" ||
435 ::gdcm::MediaStorage::GetMSType(bSOPClassUID.c_str()) == ::gdcm::MediaStorage::SpacialFiducialsStorage ||
436 ::gdcm::MediaStorage::GetMSType(aSOPClassUID.c_str()) == ::gdcm::MediaStorage::SurfaceSegmentationStorage);
438 return bIsAnImage && !aIsAnImage;
445 return m_dicomSeriesContainer;
FWGDCMIO_API DicomSeriesContainerType & getDicomSeries()
Return DicomSeries container.
ILocation::PathType getFolder()
Get folder filesystem path.
FWGDCMIO_API ~SeriesDB()
Destructor.
#define SLM_TRACE_FUNC()
Trace contextual function signature.
This class is an interface for class managing job.
static FWGDCMIO_API::boost::filesystem::path findDicomDir(const ::boost::filesystem::path &root)
Find the DICOMDIR file in the parent arborescence.
Key class used to restrict access to Object construction. See http://www.drdobbs.com/184402053.
FWGDCMIO_API void read() override
Reads DICOM data from configured path and fills SeriesDB object.
FWGDCMIO_API SeriesDB(::fwDataIO::reader::IObjectReader::Key key)
Constructor.
The namespace fwGdcmIO contains reader, writer and helper for dicom data.
static FWDICOMIOFILTER_API bool applyFilter(DicomSeriesContainerType &dicomSeriesContainer,::fwDicomIOFilter::IFilter::sptr filter, bool forcedApply=false, const ::fwLog::Logger::sptr &logger=::fwLog::Logger::New())
Apply a filter to the DicomSeries.
FWGDCMIO_API std::shared_ptr< ::fwJobs::IJob > getJob() const override
Getter for reader's job.
fwLog contains classes used to manage logs.
Implements a failed exception class for fwGdcmIO.
This class adds patient(s) from DICOM file(s) to fwData::SeriesDB.
FWGDCMIO_API void readFromDicomSeriesDB(const ::fwMedData::SeriesDB::csptr &dicomSeriesDB, const ::fwServices::IService::sptr ¬ifier=::fwServices::IService::sptr())
Reads DICOM data from DicomSeries and fills SeriesDB object.
static FWGDCMIO_API void searchRecursively(const ::boost::filesystem::path &dirPath, std::vector< ::boost::filesystem::path > &dicomFiles, bool checkIsDicom, const std::shared_ptr< ::fwJobs::Observer > &fileLookupObserver=nullptr)
Search Dicom files recursively by excluding files with known extensions.
FWGDCMIO_API bool isDicomDirAvailable()
Return true if a dicomdir file can be read.
#define SLM_ASSERT(message, cond)
work like 'assert' from 'cassert', with in addition a message logged by spylog (with FATAL loglevel) ...
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.
virtual std::shared_ptr< DataType > getConcreteObject()
m_object getter.
const SOPClassUIDContainerType & getSOPClassUIDs() const
SOP Class UID.
FWGDCMIO_API void complete(DicomSeriesContainerType &seriesDB, const std::shared_ptr< ::fwJobs::Observer > &completeSeriesObserver)
Fill DicomSeries information for series generated using DICOMDIR helper.
static FWGDCMIO_API std::string getSOPClassName(const std::string &SOPClassUID)
Returns SOP Class Name.
Contains the representation of the data objects used in the framework.
FWGDCMIO_API void readDicomSeries()
Reads DICOM data from configured path and fills SeriesDB object with DicomSeries. ...
static FWGDCMIO_API void retrieveDicomSeries(const ::boost::filesystem::path &dicomdir, std::vector< std::shared_ptr< ::fwMedData::DicomSeries > > &seriesDB, const std::shared_ptr< ::fwLog::Logger > &logger, std::function< void(std::uint64_t) > progress=nullptr, std::function< bool() > cancel=nullptr)
Create DicomSeries from information stored in DICOMDIR.
DicomSeries Helper. This class is used to generate/fill DicomSeries.
This namespace fwJobs provides jobs management.
Series class used to read Series.