fw4spl
fwVtkIO/src/fwVtkIO/SeriesDBReader.cpp
1 /* ***** BEGIN LICENSE BLOCK *****
2  * FW4SPL - Copyright (C) IRCAD, 2009-2016.
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 "fwVtkIO/helper/Mesh.hpp"
8 #include "fwVtkIO/helper/vtkLambdaCommand.hpp"
9 #include "fwVtkIO/SeriesDBReader.hpp"
10 #include "fwVtkIO/vtk.hpp"
11 
12 #include <fwCore/base.hpp>
13 
14 #include <fwJobs/IJob.hpp>
15 #include <fwJobs/Observer.hpp>
16 
17 #include <fwData/Image.hpp>
18 #include <fwData/Mesh.hpp>
19 #include <fwData/Reconstruction.hpp>
20 
21 #include <fwDataIO/reader/registry/macros.hpp>
22 
23 #include <fwMedData/Equipment.hpp>
24 #include <fwMedData/ImageSeries.hpp>
25 #include <fwMedData/ModelSeries.hpp>
26 #include <fwMedData/Patient.hpp>
27 #include <fwMedData/Study.hpp>
28 
29 #include <fwMemory/BufferObject.hpp>
30 #include <fwMemory/stream/in/IFactory.hpp>
31 
32 #include <fwTools/dateAndTime.hpp>
33 #include <fwTools/UUID.hpp>
34 
35 #include <boost/algorithm/string/join.hpp>
36 #include <boost/date_time/posix_time/posix_time.hpp>
37 #include <boost/filesystem/operations.hpp>
38 #include <boost/filesystem/path.hpp>
39 #include <boost/iostreams/categories.hpp>
40 #include <boost/iostreams/filtering_stream.hpp>
41 #include <boost/iostreams/stream.hpp>
42 
43 #include <vtkDataSetAttributes.h>
44 #include <vtkGenericDataObjectReader.h>
45 #include <vtkImageData.h>
46 #include <vtkInformation.h>
47 #include <vtkMetaImageReader.h>
48 #include <vtkPolyData.h>
49 #include <vtkSmartPointer.h>
50 #include <vtkStreamingDemandDrivenPipeline.h>
51 #include <vtkStructuredPoints.h>
52 #include <vtkStructuredPointsReader.h>
53 #include <vtkXMLGenericDataObjectReader.h>
54 #include <vtkXMLImageDataReader.h>
55 
56 #include <algorithm>
57 #include <iosfwd>
58 #include <numeric>
59 
60 fwDataIOReaderRegisterMacro( ::fwVtkIO::SeriesDBReader );
61 
62 namespace fwVtkIO
63 {
64 //------------------------------------------------------------------------------
65 
66 void initSeries(::fwMedData::Series::sptr series, const std::string& instanceUID)
67 {
68  const std::string unknown = "unknown";
69  series->setModality("OT");
70  ::boost::posix_time::ptime now = ::boost::posix_time::second_clock::local_time();
71  const std::string date = ::fwTools::getDate(now);
72  const std::string time = ::fwTools::getTime(now);
73  series->setDate(date);
74  series->setTime(time);
75  //series->setDescription(??);
76  //series->setPerformingPhysiciansName(??);
77 
78  series->getEquipment()->setInstitutionName(unknown);
79 
80  series->getPatient()->setName(unknown);
81  series->getPatient()->setPatientId(unknown);
82  series->getPatient()->setBirthdate(unknown);
83  series->getPatient()->setSex(unknown);
84 
85  series->getStudy()->setInstanceUID(instanceUID);
86  series->getStudy()->setDate(date);
87  series->getStudy()->setTime(time);
88  series->getStudy()->setReferringPhysicianName(unknown);
89  series->getStudy()->setDescription(unknown);
90  series->getStudy()->setPatientAge(unknown);
91 }
92 
93 //------------------------------------------------------------------------------
94 
95 
97  ::fwData::location::enableMultiFiles< ::fwDataIO::reader::IObjectReader >(this),
98  m_lazyMode(true),
99  m_job(::fwJobs::Observer::New("SeriesDB reader"))
100 {
101  SLM_TRACE_FUNC();
102 }
103 
104 //------------------------------------------------------------------------------
105 
107 {
108  SLM_TRACE_FUNC();
109 }
110 
111 //------------------------------------------------------------------------------
112 template <typename T, typename FILE>
113 vtkSmartPointer< vtkDataObject > getObj(FILE &file, const ::fwJobs::Observer::sptr& job)
114 {
115  using namespace fwVtkIO::helper;
116 
117  vtkSmartPointer< T > reader = vtkSmartPointer< T >::New();
118  reader->SetFileName(file.string().c_str());
119 
120  if(job)
121  {
122  vtkSmartPointer<vtkLambdaCommand> progressCallback;
123  progressCallback = vtkSmartPointer<vtkLambdaCommand>::New();
124  progressCallback->SetCallback([&](vtkObject* caller, long unsigned int, void* )
125  {
126  auto filter = static_cast<T*>(caller);
127  job->doneWork( filter->GetProgress()*100 );
128  });
129  reader->AddObserver(vtkCommand::ProgressEvent, progressCallback);
130 
131  job->addSimpleCancelHook( [&]()
132  {
133  reader->AbortExecuteOn();
134  } );
135  reader->Update();
136  job->finish();
137  }
138  else
139  {
140  reader->Update();
141  }
142  return reader->GetOutput();
143 }
144 
145 //------------------------------------------------------------------------------
146 
147 ::fwData::Object::sptr getDataObject(const vtkSmartPointer< vtkDataObject > &obj, const boost::filesystem::path &file)
148 {
149  vtkSmartPointer< vtkPolyData > mesh = vtkPolyData::SafeDownCast(obj);
150  vtkSmartPointer< vtkImageData > img = vtkImageData::SafeDownCast(obj);
151  vtkSmartPointer< vtkUnstructuredGrid > grid = vtkUnstructuredGrid::SafeDownCast(obj);
152  ::fwData::Object::sptr dataObj;
153 
154  if(grid)
155  {
156  ::fwData::Mesh::sptr meshObj = ::fwData::Mesh::New();
158 
159  ::fwData::Reconstruction::sptr rec = ::fwData::Reconstruction::New();
160  rec->setMesh(meshObj);
161  rec->setOrganName(file.stem().string());
162  rec->setIsVisible(true);
163  dataObj = rec;
164  }
165  if(mesh)
166  {
167  ::fwData::Mesh::sptr meshObj = ::fwData::Mesh::New();
169  ::fwData::Reconstruction::sptr rec = ::fwData::Reconstruction::New();
170  rec->setMesh(meshObj);
171  rec->setOrganName(file.stem().string());
172  rec->setIsVisible(true);
173  dataObj = rec;
174  }
175  else if(img)
176  {
177  try
178  {
179  ::fwData::Image::sptr imgObj = ::fwData::Image::New();
180  ::fwVtkIO::fromVTKImage( img, imgObj);
181  dataObj = imgObj;
182  }
183  catch( std::exception &e)
184  {
185  FW_RAISE("VTKImage to fwData::Image failed "<<e.what());
186  }
187  }
188  return dataObj;
189 }
190 //------------------------------------------------------------------------------
191 
192 struct FilteringStream : ::boost::iostreams::filtering_istream
193 {
194 
195  typedef ::boost::iostreams::stream< ::boost::iostreams::array_source > BufferStreamType;
196 
197 
198  FilteringStream(const ::fwData::Image::sptr &source ) :
199  m_image(source),
200  m_bufferObject(source->getDataArray()->getBufferObject()),
201  m_lock( m_bufferObject->lock() ),
202  m_bufferStream( std::make_shared<BufferStreamType>(static_cast<char *>(m_lock.getBuffer()),
203  m_bufferObject->getSize()) )
204  {
205  this->push(*m_bufferStream);
206  }
207 
208  ~FilteringStream()
209  {
210  try
211  {
212  this->reset();
213  }
214  catch (...)
215  {
216  }
217  }
218 
219  ::fwData::Image::sptr m_image;
220  ::fwMemory::BufferObject::sptr m_bufferObject;
222  SPTR(BufferStreamType) m_bufferStream;
223 };
224 
225 //------------------------------------------------------------------------------
226 
227 template< typename READER >
229 {
230 public:
231 
232  ImageStream( const ::boost::filesystem::path& path ) : m_path(path)
233  {
234  }
235 
236 protected:
237 
238  ::fwData::Image::sptr getImage()
239  {
240  if(!::boost::filesystem::exists(m_path))
241  {
242  FW_RAISE("file "<< m_path.string() << " does not exist anymore or has moved.");
243  }
244 
245  vtkSmartPointer< vtkDataObject > obj;
246  obj = getObj<READER>(m_path, nullptr);
247 
248  return ::fwData::Image::dynamicCast(getDataObject(obj, m_path));
249  }
250 
251  SPTR(std::istream) get()
252  {
254  = std::make_shared< FilteringStream>( this->getImage() );
255 
256  return is;
257  }
258 
259  ::boost::filesystem::path m_path;
260 };
261 
262 //------------------------------------------------------------------------------
263 
264 
265 bool checkIfReadDataTypeIsImage(const vtkSmartPointer< vtkMetaImageReader > &reader)
266 {
267  return true;
268 }
269 
270 bool checkIfReadDataTypeIsImage(const vtkSmartPointer< vtkGenericDataObjectReader > &reader)
271 {
272  return reader->IsFileStructuredPoints();
273 }
274 
275 bool checkIfReadDataTypeIsImage(const vtkSmartPointer< vtkXMLGenericDataObjectReader > &reader)
276 {
277  return (reader->GetImageDataOutput () != 0);
278 }
279 
280 void updateImageFromVtkInfo(const vtkSmartPointer< vtkInformation > &info, const ::fwData::Image::sptr &imgObj)
281 {
282  int extent[6];
283  info->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), extent);
284  ::fwData::Image::SizeType size(3,0);
285  size[0] = extent[1]-extent[0]+1;
286  size[1] = extent[3]-extent[2]+1;
287  size[2] = extent[5]-extent[4]+1;
288  imgObj->setSize(size);
289 
290  ::fwData::Image::SpacingType spacing(3, 0);
291  info->Get(vtkDataObject::SPACING(), &spacing[0]);
292  imgObj->setSpacing(spacing);
293 
294  ::fwData::Image::OriginType origin(3, 0);
295  info->Get(vtkDataObject::ORIGIN(), &origin[0]);
296  imgObj->setOrigin(origin);
297 
298  vtkInformation *attrInfo = vtkDataObject::GetActiveFieldInformation(info, vtkDataObject::FIELD_ASSOCIATION_POINTS,
299  vtkDataSetAttributes::SCALARS);
300  int type = attrInfo->Get(vtkDataObject::FIELD_ARRAY_TYPE());
301  int nbOfComponents = attrInfo->Get(vtkDataObject::FIELD_NUMBER_OF_COMPONENTS());
302  imgObj->setType( ::fwVtkIO::TypeTranslator::translate( attrInfo->Get(vtkDataObject::FIELD_ARRAY_TYPE()) ) );
303  imgObj->setNumberOfComponents(nbOfComponents);
304  imgObj->getDataArray()->setType(imgObj->getType());
305 }
306 
307 void getInfo(const vtkSmartPointer< vtkGenericDataObjectReader > &reader, const ::fwData::Image::sptr &imgObj)
308 {
309  vtkSmartPointer< vtkStructuredPointsReader > imgReader = vtkSmartPointer< vtkStructuredPointsReader >::New();
310  imgReader->SetFileName(reader->GetFileName());
311 
312  vtkSmartPointer< vtkInformation > info = vtkSmartPointer< vtkInformation >::New();
313  imgReader->ReadMetaData(info);
314 
315  updateImageFromVtkInfo(info, imgObj);
316  imgObj->getDataArray()->resize(imgObj->getSize(), false);
317 
318  ::fwMemory::BufferObject::sptr buffObj = imgObj->getDataArray()->getBufferObject();
319  boost::filesystem::path file = reader->GetFileName();
320  buffObj->setIStreamFactory( std::make_shared< ImageStream<vtkStructuredPointsReader> >(file),
321  imgObj->getSizeInBytes());
322 }
323 
324 
325 void getInfo(const vtkSmartPointer< vtkXMLGenericDataObjectReader > &reader, const ::fwData::Image::sptr &imgObj)
326 {
327  vtkSmartPointer< vtkXMLImageDataReader > imgReader = vtkSmartPointer< vtkXMLImageDataReader >::New();
328  imgReader->SetFileName(reader->GetFileName());
329 
330  vtkSmartPointer< vtkInformation > info = vtkSmartPointer< vtkInformation >::New();
331  imgReader->UpdateInformation();
332  imgReader->CopyOutputInformation(info,0);
333 
334  updateImageFromVtkInfo(info, imgObj);
335  imgObj->getDataArray()->resize(imgObj->getSize(), false);
336 
337  ::fwMemory::BufferObject::sptr buffObj = imgObj->getDataArray()->getBufferObject();
338  boost::filesystem::path file = reader->GetFileName();
339  buffObj->setIStreamFactory( std::make_shared< ImageStream<vtkXMLImageDataReader> >(file),
340  imgObj->getSizeInBytes());
341 
342 }
343 
344 //------------------------------------------------------------------------------
345 
346 template< typename DATA_READER >
347 ::fwData::Image::sptr lazyRead( const ::boost::filesystem::path &file, const ::fwJobs::Observer::sptr& job)
348 {
349  vtkSmartPointer< DATA_READER > reader = vtkSmartPointer< DATA_READER >::New();
350  reader->SetFileName(file.string().c_str());
351  reader->UpdateInformation();
352 
353  ::fwData::Image::sptr imgObj;
354 
355  if(checkIfReadDataTypeIsImage(reader))
356  {
357  imgObj = ::fwData::Image::New();
358  getInfo(reader, imgObj);
359 
360  job->finish();
361  }
362 
363  return imgObj;
364 }
365 
366 
367 //------------------------------------------------------------------------------
368 
369 
371 {
372  ::fwMedData::SeriesDB::sptr seriesDB = this->getConcreteObject();
373 
374  const ::fwData::location::ILocation::VectPathType files = this->getFiles();
375  const std::string instanceUID = ::fwTools::UUID::generateUUID();
376 
377  ::fwMedData::ModelSeries::ReconstructionVectorType recs;
378  std::vector< std::string > errorFiles;
379  for(const ::fwData::location::ILocation::VectPathType::value_type& file : files)
380  {
381  vtkSmartPointer< vtkDataObject > obj;
382  ::fwData::Image::sptr img;
383  ::fwData::Reconstruction::sptr rec;
384 
385  if(file.extension().string() == ".vtk")
386  {
387  if(m_lazyMode)
388  {
389  img = lazyRead<vtkGenericDataObjectReader>(file, m_job);
390  }
391  if (!img)
392  {
393  obj = getObj<vtkGenericDataObjectReader>(file, m_job);
394  }
395  }
396  else if(file.extension().string() == ".vti")
397  {
398  if(m_lazyMode)
399  {
400  img = lazyRead<vtkXMLGenericDataObjectReader>(file, m_job);
401  }
402  if (!img)
403  {
404  obj = getObj<vtkXMLGenericDataObjectReader>(file, m_job);
405  }
406  }
407  else if(file.extension().string() == ".mhd")
408  {
409  obj = getObj<vtkMetaImageReader>(file, m_job);
410  }
411  else if(file.extension().string() == ".vtu")
412  {
413  obj = getObj<vtkXMLGenericDataObjectReader>(file, m_job);
414  }
415 
416  if (!img)
417  {
418  ::fwData::Object::sptr dataObj = getDataObject(obj, file);
419  img = ::fwData::Image::dynamicCast(dataObj);
420  rec = ::fwData::Reconstruction::dynamicCast(dataObj);
421  }
422  if(img)
423  {
424  ::fwMedData::ImageSeries::sptr imgSeries = ::fwMedData::ImageSeries::New();
425  initSeries(imgSeries, instanceUID);
426  imgSeries->setImage(img);
427  seriesDB->getContainer().push_back(imgSeries);
428  }
429  else if (rec)
430  {
431  recs.push_back(rec);
432  }
433  else
434  {
435  errorFiles.push_back(file.string());
436  }
437  }
438 
439  if (!errorFiles.empty())
440  {
441  FW_RAISE("SeriesDBReader cannot read VTK file(s) : "<< ::boost::algorithm::join(errorFiles, ", ") );
442  }
443 
444  // Adds loaded Reconstructions in SeriesDB
445  if(!recs.empty())
446  {
447  ::fwMedData::ModelSeries::sptr modelSeries = ::fwMedData::ModelSeries::New();
448  initSeries(modelSeries, instanceUID);
449  modelSeries->setReconstructionDB(recs);
450  seriesDB->getContainer().push_back(modelSeries);
451  }
452 }
453 
454 //------------------------------------------------------------------------------
455 
457 {
458  return ".vtk";
459 }
460 
461 //------------------------------------------------------------------------------
462 
464 {
465  return m_job;
466 }
467 
468 } // namespace fwVtkIO
#define SPTR(_cls_)
FWVTKIO_API void read() override
Reading operator.
#define SLM_TRACE_FUNC()
Trace contextual function signature.
Definition: spyLog.hpp:329
This namespace fwDataIO contains reader and writer for several framework&#39;s data.
Key class used to restrict access to Object construction. See http://www.drdobbs.com/184402053.
base class for BufferObject Lock
std::shared_ptr< ::fwJobs::IJob > sptr
Cancel request callback type.
Definition: IJob.hpp:54
FWVTKIO_API SeriesDBReader(::fwDataIO::reader::IObjectReader::Key key)
Constructor.
static FWVTKIO_API void fromVTKGrid(vtkSmartPointer< vtkUnstructuredGrid > grid,::fwData::Mesh::sptr mesh)
Convert a vtkUnstructuredGrid to a ::fwData::Mesh::sptr.
virtual std::shared_ptr< DataType > getConcreteObject()
m_object getter.
std::vector< double > SpacingType
Image spacing type.
ILocation::VectPathType getFiles()
Get file system paths.
Definition: MultiFiles.hpp:77
FWVTKIO_API std::shared_ptr< ::fwJobs::IJob > getJob() const override
Contains the representation of the data objects used in the framework.
static FWVTKIO_API void fromVTKMesh(vtkSmartPointer< vtkPolyData > _polyData,::fwData::Mesh::sptr _mesh)
Convert a vtkPolyData to a ::fwData::Mesh::sptr.
This namespace fwJobs provides jobs management.
::fwData::Array::SizeType SizeType
Image size type.
FWVTKIO_API std::string extension() override
static FWTOOLS_API UUIDType generateUUID()
Return a new extended UUID;.
Definition: UUID.cpp:114
std::vector< double > OriginType
Image origin type.