fw4spl
TagValueSplitter.cpp
1 /* ***** BEGIN LICENSE BLOCK *****
2  * FW4SPL - Copyright (C) IRCAD, 2009-2018.
3  * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
4  * published by the Free Software Foundation.
5  * ****** END LICENSE BLOCK ****** */
6 
7 #include "fwDicomIOFilter/splitter/TagValueSplitter.hpp"
8 
9 #include "fwDicomIOFilter/exceptions/FilterFailure.hpp"
10 #include "fwDicomIOFilter/registry/macros.hpp"
11 
12 #include <dcmtk/config/osconfig.h>
13 #include <dcmtk/dcmdata/dcdeftag.h>
14 #include <dcmtk/dcmdata/dcfilefo.h>
15 #include <dcmtk/dcmdata/dcistrmb.h>
16 #include <dcmtk/dcmimgle/dcmimage.h>
17 #include <dcmtk/dcmnet/diutil.h>
18 
19 fwDicomIOFilterRegisterMacro( ::fwDicomIOFilter::splitter::TagValueSplitter );
20 
21 namespace fwDicomIOFilter
22 {
23 namespace splitter
24 {
25 
26 const std::string TagValueSplitter::s_FILTER_NAME = "Tag value splitter";
28  "Split instances according to a tag value.";
29 
30 //-----------------------------------------------------------------------------
31 
33  ISplitter()
34 {
35  m_tag = DCM_UndefinedTagKey;
36 }
37 
38 //-----------------------------------------------------------------------------
39 
41 {
42 }
43 
44 //-----------------------------------------------------------------------------
45 
46 std::string TagValueSplitter::getName() const
47 {
49 }
50 
51 //-----------------------------------------------------------------------------
52 
54 {
56 }
57 
58 //-----------------------------------------------------------------------------
59 
61 {
62  return true;
63 }
64 
65 //-----------------------------------------------------------------------------
66 
67 TagValueSplitter::DicomSeriesContainerType TagValueSplitter::apply(
68  const ::fwMedData::DicomSeries::sptr& series,
69  const ::fwLog::Logger::sptr& logger) const
70 {
71  if(m_tag == DCM_UndefinedTagKey)
72  {
73  const std::string msg = "Unable to split the series, the specified tag is not valid.";
74  throw ::fwDicomIOFilter::exceptions::FilterFailure(msg);
75  }
76 
77  DicomSeriesContainerType result;
78 
79  typedef std::vector< ::fwMemory::BufferObject::sptr > InstanceContainerType;
80  typedef std::map< std::string, InstanceContainerType > InstanceGroupContainer;
81 
82  // Create a container to store the groups of instances
83  InstanceGroupContainer groupContainer;
84 
85  OFCondition status;
86  DcmDataset* dataset;
87  OFString data;
88 
89  for(const auto& item : series->getDicomContainer())
90  {
91  const ::fwMemory::BufferObject::sptr bufferObj = item.second;
92  const size_t buffSize = bufferObj->getSize();
93  ::fwMemory::BufferObject::Lock lock(bufferObj);
94  char* buffer = static_cast< char* >( lock.getBuffer() );
95 
96  DcmInputBufferStream is;
97  is.setBuffer(buffer, offile_off_t(buffSize));
98  is.setEos();
99 
100  DcmFileFormat fileFormat;
101  fileFormat.transferInit();
102  if (!fileFormat.read(is).good())
103  {
104  FW_RAISE("Unable to read Dicom file '"<< bufferObj->getStreamInfo().fsFile.string() <<"' "<<
105  "(slice: '" << item.first << "')");
106  }
107 
108  fileFormat.loadAllDataIntoMemory();
109  fileFormat.transferEnd();
110 
111  dataset = fileFormat.getDataset();
112 
113  // Get the value of the instance
114  dataset->findAndGetOFStringArray(m_tag, data);
115  const std::string value = data.c_str();
116 
117  // Add the instance to the group
118  groupContainer[value].push_back(bufferObj);
119  }
120 
121  for(const InstanceGroupContainer::value_type& group : groupContainer)
122  {
123  // Copy the series
124  ::fwMedData::DicomSeries::sptr dicomSeries = ::fwMedData::DicomSeries::New();
125  dicomSeries->deepCopy(series);
126  dicomSeries->clearDicomContainer();
127 
128  size_t index = 0;
129  // Add the paths to the series
130  for(const ::fwMemory::BufferObject::sptr& buffer : group.second)
131  {
132  dicomSeries->addBinary(index++, buffer);
133  }
134 
135  // Set number of instances
136  dicomSeries->setNumberOfInstances(dicomSeries->getDicomContainer().size());
137 
138  result.push_back(dicomSeries);
139  }
140 
141  if(result.size() > 1)
142  {
143  std::stringstream ss;
144  ss << "Series has been split according to the tag value (" <<
145  std::hex << std::setfill('0') << std::setw(4) << m_tag.getGroup() << "," <<
146  std::hex << std::setfill('0') << std::setw(4) << m_tag.getElement() << ").";
147  logger->warning(ss.str());
148  }
149 
150  return result;
151 
152 }
153 
154 } // namespace splitter
155 } // namespace fwDicomIOFilter
FWDICOMIOFILTER_API TagValueSplitter(::fwDicomIOFilter::IFilter::Key key)
Constructor.
fwDicomIOFilter contains filters used to pre-process images before reading.
base class for BufferObject Lock
static const std::string s_FILTER_NAME
Filter name.
virtual FWDICOMIOFILTER_API std::string getName() const override
Return the name of the filter.
virtual FWDICOMIOFILTER_API ~TagValueSplitter()
Destructor.
virtual FWDICOMIOFILTER_API std::string getDescription() const override
Return the description of the filter.
LockBase< T >::BufferType getBuffer() const
Returns BufferObject&#39;s buffer pointer.
Key class used to restrict access to Filter construction. See http://www.drdobbs.com/184402053.
static const std::string s_FILTER_DESCRIPTION
Filter description.
DcmTagKey m_tag
Tag used to sort instances.
virtual FWDICOMIOFILTER_API DicomSeriesContainerType apply(const ::fwMedData::DicomSeries::sptr &series, const ::fwLog::Logger::sptr &logger) const override
Override.
virtual FWDICOMIOFILTER_API bool isConfigurationRequired() const override
Return true if a configuration is required.
Filter that uses a tag to split the instances.
Base class for Dicom instance splitter.
Definition: ISplitter.hpp:23