fw4spl
MedicalImageAdaptor.cpp
1 /* ***** BEGIN LICENSE BLOCK *****
2  * FW4SPL - Copyright (C) IRCAD, 2009-2017.
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 "fwDataTools/helper/MedicalImageAdaptor.hpp"
8 
9 #include "fwDataTools/fieldHelper/Image.hpp"
10 #include "fwDataTools/fieldHelper/MedicalImageHelpers.hpp"
11 #include "fwDataTools/helper/Composite.hpp"
12 #include "fwDataTools/helper/Image.hpp"
13 
14 #include <fwCom/Slot.hpp>
15 #include <fwCom/Slot.hxx>
16 #include <fwCom/Slots.hpp>
17 #include <fwCom/Slots.hxx>
18 
19 #include <fwData/Image.hpp>
20 #include <fwData/TransferFunction.hpp>
21 
22 namespace fwDataTools
23 {
24 
25 namespace helper
26 {
27 
28 static const ::fwCom::Slots::SlotKeyType s_UPDATE_TF_POINTS_SLOT = "updateTFPoints";
29 static const ::fwCom::Slots::SlotKeyType s_UPDATE_TF_WINDOWING_SLOT = "updateTFWindowing";
30 
31 //------------------------------------------------------------------------------
32 
34  m_orientation(Z_AXIS)
35 {
36 }
37 
38 //------------------------------------------------------------------------------
39 
41 {
42 }
43 
44 //------------------------------------------------------------------------------
45 
46 void MedicalImageAdaptor::getImageSpacing(double spacing[3]) const
47 {
48  ::fwData::Image::sptr image = this->getImage();
49 
50  const ::fwData::Image::SpacingType& imSpacing = image->getSpacing();
51  std::copy(imSpacing.begin(), imSpacing.end(), spacing);
52 }
53 
54 //------------------------------------------------------------------------------
55 
56 void MedicalImageAdaptor::getImageOrigin(double origin[3]) const
57 {
58  ::fwData::Image::sptr image = this->getImage();
59 
60  std::copy(image->getOrigin().begin(), image->getOrigin().end(), origin);
61 }
62 
63 //------------------------------------------------------------------------------
64 
66 {
67  ::fwData::Image::sptr image = this->getImage();
68 
69  const ::fwData::Image::SizeType& imSize = image->getSize();
70  std::copy(imSize.begin(), imSize.end(), size);
71 }
72 
73 //------------------------------------------------------------------------------
74 
75 void MedicalImageAdaptor::getImageSize(double size[3]) const
76 {
77  ::fwData::Image::sptr image = this->getImage();
78  double spacing[3];
79 
80  const ::fwData::Image::SizeType& imSize = image->getSize();
81  std::copy(imSize.begin(), imSize.end(), size);
82  this->getImageSpacing(spacing);
83 
84  size[0] *= spacing[0];
85  size[1] *= spacing[1];
86  size[2] *= spacing[2];
87 }
88 
89 //------------------------------------------------------------------------------
90 
92 {
93  ::fwData::Image::sptr image = this->getImage();
94  double imageSize[3];
95  this->getImageSize(imageSize);
96  double origin[3];
97  this->getImageOrigin(origin);
98 
99  ::fwData::Integer::sptr sliceIndex[3];
100  this->getSliceIndex(sliceIndex);
101  double index[3] = {
102  static_cast<double>(sliceIndex[0]->value()),
103  static_cast<double>(sliceIndex[1]->value()),
104  static_cast<double>(sliceIndex[2]->value())
105  };
106 
107  center[0] = origin[0] + (imageSize[0]-1.)/ 2.;
108  center[1] = origin[1] + (imageSize[1]-1.)/ 2.;
109  center[2] = origin[2] + (imageSize[2]-1.)/ 2.;
110 
111  double spacing[3];
112  this->getImageSpacing(spacing);
113  center[m_orientation] = origin[m_orientation] + index[m_orientation]*spacing[m_orientation];
114 }
115 
116 //------------------------------------------------------------------------------
117 
119 {
120  m_orientation = orientation;
121 }
122 
123 //------------------------------------------------------------------------------
124 
125 void MedicalImageAdaptor::setOrientation( int orientation )
126 {
127  OSLM_ASSERT("orientation value must be 0,1 or 2 (value = " << orientation << ")",
128  orientation == 0 || orientation == 1 || orientation == 2);
129  this->setOrientation(static_cast< ::fwDataTools::helper::MedicalImageAdaptor::Orientation >(orientation));
130 }
131 
132 //------------------------------------------------------------------------------
133 
134 static const int indexZ[12] = { 0, 2, 4, 1, 2, 4, 1, 3, 4, 0, 3, 4 };
135 static const int indexY[12] = { 0, 2, 4, 1, 2, 4, 1, 2, 5, 0, 2, 5 };
136 static const int indexX[12] = { 0, 2, 4, 0, 2, 5, 0, 3, 5, 0, 3, 4 };
137 static const int* indexSet[3] = { indexX, indexY, indexZ };
138 //------------------------------------------------------------------------------
139 
140 void MedicalImageAdaptor::getPlane( double points[4][3], int sliceNumber)
141 {
142  ::fwData::Image::sptr image = this->getImage();
143  double extent[6];
144  for (unsigned char i = 0; i < 3; ++i )
145  {
146  extent[2*i] = 0;
147  extent[2*i+1] = image->getSize()[i]*image->getSpacing()[i];
148  }
149  extent[2*m_orientation] = sliceNumber*image->getSpacing()[m_orientation];
150  extent[2*m_orientation+1] = sliceNumber*image->getSpacing()[m_orientation];
151 
152  const int* extentIndex = indexSet[ m_orientation ];
153  for (int p = 0; p < 4; ++p)
154  {
155  for (int i = 0; i < 3; ++i)
156  {
157  points[p][i] = extent[ *(extentIndex++) ];
158  }
159  }
160 }
161 
162 //------------------------------------------------------------------------------
163 
164 void MedicalImageAdaptor::sliceIndexToWorld(const int index[3], double world[3] )
165 {
166  double spacing[3];
167  this->getImageSpacing(spacing);
168  double origin[3];
169  this->getImageOrigin(origin);
170  for ( int i = 0; i < 3; ++i )
171  {
172  world[i] = static_cast<int>( (index[i]*spacing[i]) + 0.5*spacing[i] + origin[i] );
173  }
174 }
175 
176 //------------------------------------------------------------------------------
177 
178 void MedicalImageAdaptor::worldToSliceIndex(const double world[3], int index[3] )
179 {
180  double spacing[3];
181  this->getImageSpacing(spacing);
182  double origin[3];
183  this->getImageOrigin(origin);
184  for ( int i = 0; i < 3; ++i )
185  {
186  // nearest integer
187  index[i] =
188  static_cast<int>( ( (world[i]-origin[i])/spacing[i] ) +
189  ( ( (world[i]-origin[i])/spacing[i] ) >= 0 ? 0.5 : -0.5 ) );
190  }
191 }
192 
193 //------------------------------------------------------------------------------
194 
195 void MedicalImageAdaptor::worldToImageSliceIndex(const double world[3], int index[3] )
196 {
197  int imageSize[3];
198  this->getImageDataSize(imageSize);
199  this->worldToSliceIndex(world, index);
200 
201  int idval;
202  for (int i = 0; i < 3; i++)
203  {
204  int max = imageSize[i]-1;
205  idval = index[i];
206  if (idval < 0)
207  {
208  index[i] = 0;
209  }
210  else if (idval > max)
211  {
212  index[i] = max;
213  }
214  }
215 }
216 
217 //------------------------------------------------------------------------------
218 
219 void MedicalImageAdaptor::getSliceIndex(::fwData::Integer::sptr index[3])
220 {
221  index[0] = m_sagittalIndex;
222  index[1] = m_frontalIndex;
223  index[2] = m_axialIndex;
224 }
225 
226 //------------------------------------------------------------------------------
227 
228 bool MedicalImageAdaptor::setSliceIndex(const int index[3])
229 {
230  bool isModified = false;
231 
232  ::fwData::Integer::sptr sliceIndex[3];
233 
234  this->getSliceIndex(sliceIndex);
235 
236  if( index[0] != m_sagittalIndex->value()
237  || index[1] != m_frontalIndex->value()
238  || index[2] != m_axialIndex->value() )
239  {
240  m_sagittalIndex->value() = index[0];
241  m_frontalIndex->value() = index[1];
242  m_axialIndex->value() = index[2];
243  isModified = true;
244  }
245  return isModified;
246 }
247 
248 //------------------------------------------------------------------------------
249 
250 void MedicalImageAdaptor::updateImageInfos( ::fwData::Image::sptr image )
251 {
252  m_weakImage = image;
254  ::fwData::Integer::New(0));
256  ::fwData::Integer::New(0));
258  ::fwData::Integer::New(0));
259 }
260 
261 //------------------------------------------------------------------------------
262 
263 void MedicalImageAdaptor::createTransferFunction( ::fwData::Image::sptr image )
264 {
265  ::fwData::Composite::sptr tfPool =
267  ::fwData::Composite::New());
268 
269  // create the default transfer function in the image tf field if it does not exist
270  if (tfPool->find(::fwData::TransferFunction::s_DEFAULT_TF_NAME) == tfPool->end())
271  {
272  ::fwData::TransferFunction::sptr tfGreyLevel = ::fwData::TransferFunction::createDefaultTF();
273  if (image->getWindowWidth() != 0 )
274  {
275  tfGreyLevel->setWindow( image->getWindowWidth() );
276  tfGreyLevel->setLevel( image->getWindowCenter() );
277  }
279  {
280  double min, max;
282  ::fwData::TransferFunction::TFValuePairType wlMinMax(min, max);
283  tfGreyLevel->setWLMinMax(wlMinMax);
284  }
285 
286  ::fwDataTools::helper::Composite compositeHelper(tfPool);
287  compositeHelper.add(::fwData::TransferFunction::s_DEFAULT_TF_NAME, tfGreyLevel);
288  compositeHelper.notify();
289  }
290 
291  if (m_transferFunction.expired())
292  {
293  ::fwData::TransferFunction::sptr tfGreyLevel =
295  m_transferFunction = tfGreyLevel;
296  }
297  else if (m_transferFunction.lock()->getTFValues().empty())
298  {
299  ::fwData::TransferFunction::sptr tfGreyLevel =
301  m_transferFunction.lock()->deepCopy(tfGreyLevel);
302  }
303 }
304 
305 //------------------------------------------------------------------------------v
306 
307 void MedicalImageAdaptor::setOrCreateTF(const fwData::TransferFunction::sptr& _tf, const fwData::Image::sptr& _image)
308 {
309  this->removeTFConnections();
310  if (_tf)
311  {
312  this->setTransferFunction(_tf);
313  }
314  else
315  {
316  this->createTransferFunction(_image);
317  }
318  this->installTFConnections();
319 }
320 
321 //------------------------------------------------------------------------------
322 
323 ::fwData::TransferFunction::sptr MedicalImageAdaptor::getTransferFunction() const
324 {
325  SLM_ASSERT("Transfer funtion is not defined, you must call setTransferFunction() or createTransferFunction() first."
326  , !m_transferFunction.expired());
327  return m_transferFunction.lock();
328 }
329 
330 //------------------------------------------------------------------------------
331 
332 ::fwData::Image::sptr MedicalImageAdaptor::getImage() const
333 {
334  SLM_ASSERT("Image weak pointer empty !", !m_weakImage.expired());
335  return m_weakImage.lock();
336 }
337 
338 //------------------------------------------------------------------------------
339 
340 void MedicalImageAdaptor::setTransferFunction(const ::fwData::TransferFunction::sptr& tf )
341 {
342  m_transferFunction = tf;
343 }
344 
345 //------------------------------------------------------------------------------
346 
348 {
349  ::fwCom::Connection connection;
350 
351  ::fwData::TransferFunction::sptr tf = this->getTransferFunction();
352 
353  connection = tf->signal(::fwData::TransferFunction::s_POINTS_MODIFIED_SIG)->connect(m_slotUpdateTFPoints);
354  m_tfConnections.addConnection(connection);
356  m_tfConnections.addConnection(connection);
357 }
358 
359 //------------------------------------------------------------------------------
360 
362 {
363  m_tfConnections.disconnect();
364 }
365 
366 //------------------------------------------------------------------------------
367 
369 {
370  m_slotUpdateTFPoints = hasslots->newSlot(s_UPDATE_TF_POINTS_SLOT, &MedicalImageAdaptor::updateTFPoints, this);
372  hasslots->newSlot(s_UPDATE_TF_WINDOWING_SLOT, &MedicalImageAdaptor::updateTFWindowing, this);
373 }
374 
375 //------------------------------------------------------------------------------
376 
378 {
379  SLM_ASSERT("This methods (updateTFPoints) must be reimplemented in subclass to manage TF modifications", false);
380 }
381 
382 //------------------------------------------------------------------------------
383 
384 void MedicalImageAdaptor::updateTFWindowing(double /*window*/, double /*level*/)
385 {
386  SLM_ASSERT("This methods (updateTFWindowing) must be reimplemented in subclass to manage TF modifications",
387  false);
388 }
389 
390 //------------------------------------------------------------------------------
391 
392 } //namespace helper
393 
394 } //namespace fwDataTools
FWCOM_API void disconnect()
Disconnect all registered connections and clear m_connections.
FWDATATOOLS_API::fwData::TransferFunction::sptr getTransferFunction() const
Get the current transfer function.
FWDATATOOLS_API void setTransferFunction(const ::fwData::TransferFunction::sptr &tf)
Set the current TransferFunction.
FWDATATOOLS_API void installTFSlots(::fwCom::HasSlots *hasslots)
Install the slots to managed TF modifications.
static FWDATA_API const std::string s_DEFAULT_TF_NAME
Default transfer function name.
#define OSLM_ASSERT(message, cond)
work like &#39;assert&#39; from &#39;cassert&#39;, with in addition a message logged by spylog (with FATAL loglevel) ...
Definition: spyLog.hpp:310
FWDATATOOLS_API void notify()
Send the message of modification.
::fwData::Integer::sptr m_axialIndex
Axial slice index.
FWCOM_API void addConnection(::fwCom::Connection connection)
Add a connection.
static FWDATATOOLS_API const std::string m_transferFunctionCompositeId
The namespace fwDataTools contains classes which provide helpers to manipulate fwData::Object. *.
FWDATATOOLS_API void add(std::string _compositeKey,::fwData::Object::sptr _newObject)
Add an object in the composite.
FWDATATOOLS_API void createTransferFunction(::fwData::Image::sptr image)
Create and set the default transfer function.
Defines an helper to modify an fwData::Composite and create in parallel the message to announce this ...
virtual FWDATATOOLS_API void setOrientation(Orientation orientation)
Set the image orientation.
FWDATATOOLS_API void getImageSize(double size[3]) const
Get the image size ( = dataSize * spacing ).
This class proposes a mapping between a SlotKeyType and a SlotBase.
Definition: HasSlots.hpp:22
::fwData::Integer::sptr m_sagittalIndex
Sagittal slice index.
UpdateTFWindowingSlotType::sptr m_slotUpdateTFWindowing
Slot called when transfer function windowing is modified.
Class managing Signal-Slot connections.
Definition: Connection.hpp:17
FWDATATOOLS_API void getPlane(double points[4][3], int sliceNumber)
Return the 4 points of the image plane.
FWDATATOOLS_API void worldToSliceIndex(const double world[3], int index[3])
Convert world coordinates to slice index coordinates.
FWDATATOOLS_API bool setSliceIndex(const int index[3])
Set the slice index.
FWDATATOOLS_API void worldToImageSliceIndex(const double world[3], int index[3])
Convert coordinates in the world to coordinates in the image.
FWDATATOOLS_API void sliceIndexToWorld(const int index[3], double world[3])
Convert from world coordinates system to image coordinates system.
FWDATATOOLS_API void getCurrentSliceCenter(double center[3])
Get the slice center.
Orientation m_orientation
Image orientation.
FWDATATOOLS_API void updateImageInfos(::fwData::Image::sptr image)
Update the image information (slice index, min/max,...)
virtual FWDATATOOLS_API void updateTFPoints()
Slot: called when transfer function points are modified.
#define SLM_ASSERT(message, cond)
work like &#39;assert&#39; from &#39;cassert&#39;, with in addition a message logged by spylog (with FATAL loglevel) ...
Definition: spyLog.hpp:308
FWDATATOOLS_API MedicalImageAdaptor()
Constructor. Do nothing.
FWDATATOOLS_API void getImageOrigin(double origin[3]) const
Get the image origin.
FWDATATOOLS_API::fwData::Image::sptr getImage() const
Return the image.
::fwData::Integer::sptr m_frontalIndex
Frontal slice index.
FWDATATOOLS_API void removeTFConnections()
Remove the TF connections.
static FWDATATOOLS_API bool checkImageValidity(::fwData::Image::csptr _pImg)
Check if the image is valid.
virtual FWDATATOOLS_API void updateTFWindowing(double window, double level)
Slot: called when transfer function windowing is modified.
FWDATATOOLS_API void installTFConnections()
Install connections to listen TF modifications.
UpdateTFPointsSlotType::sptr m_slotUpdateTFPoints
Slot called when transfer function points are modified.
FWDATATOOLS_API void getImageDataSize(int size[3]) const
Get the image data size (number of slices).
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_WINDOWING_MODIFIED_SIG
Type of signal when points are modified.
FWDATATOOLS_API void setOrCreateTF(const ::fwData::TransferFunction::sptr &_tf, const fwData::Image::sptr &_image)
Sets the transfer function, creates one if _tf is null (.
static void getMinMax(const ::fwData::Image::csptr _img, MINMAXTYPE &_min, MINMAXTYPE &_max)
Return minimum and maximum values contained in image. If image min or max value is out of MINMAXTYPE ...
FWDATATOOLS_API void getSliceIndex(::fwData::Integer::sptr index[3])
Get the slice index.
virtual FWDATATOOLS_API ~MedicalImageAdaptor()
Destructor. Do nothing.
FWDATATOOLS_API void getImageSpacing(double spacing[3]) const
Get the image spacing.
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_POINTS_MODIFIED_SIG
Type of signal when points are modified.