fw4spl
SImage.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 "visuVTKAdaptor/SImage.hpp"
8 
9 #include <fwCom/Slot.hpp>
10 #include <fwCom/Slot.hxx>
11 #include <fwCom/Slots.hpp>
12 #include <fwCom/Slots.hxx>
13 
14 #include <fwData/Boolean.hpp>
15 #include <fwData/Image.hpp>
16 #include <fwData/TransferFunction.hpp>
17 
18 #include <fwDataTools/fieldHelper/Image.hpp>
19 #include <fwDataTools/fieldHelper/MedicalImageHelpers.hpp>
20 
21 #include <fwRenderVTK/vtk/fwVtkWindowLevelLookupTable.hpp>
22 
23 #include <fwServices/macros.hpp>
24 
25 #include <fwVtkIO/helper/TransferFunction.hpp>
26 #include <fwVtkIO/vtk.hpp>
27 
28 #include <vtkImageBlend.h>
29 #include <vtkImageCheckerboard.h>
30 #include <vtkImageData.h>
31 #include <vtkImageMapToColors.h>
32 
33 fwServicesRegisterMacro( ::fwRenderVTK::IAdaptor, ::visuVTKAdaptor::SImage);
34 
35 namespace visuVTKAdaptor
36 {
37 
38 static const ::fwCom::Slots::SlotKeyType s_UPDATE_IMAGE_OPACITY_SLOT = "updateImageOpacity";
39 
40 const ::fwServices::IService::KeyType SImage::s_IMAGE_INOUT = "image";
41 const ::fwServices::IService::KeyType SImage::s_TF_INOUT = "tf";
42 
43 //------------------------------------------------------------------------------
44 
45 SImage::SImage() noexcept :
46  m_imageRegister(nullptr),
47  m_imagePortId(-1),
48  m_imageOpacity(0.),
49  m_allowAlphaInTF(false),
50  m_lut(vtkSmartPointer<fwVtkWindowLevelLookupTable>::New()),
51  m_map2colors(vtkSmartPointer<vtkImageMapToColors>::New()),
52  m_imageData(vtkSmartPointer<vtkImageData>::New())
53 {
54  this->installTFSlots(this);
55  newSlot(s_UPDATE_IMAGE_OPACITY_SLOT, &SImage::updateImageOpacity, this);
56 }
57 
58 //------------------------------------------------------------------------------
59 
60 SImage::~SImage() noexcept
61 {
62 }
63 
64 //------------------------------------------------------------------------------
65 
67 {
68  this->initialize();
69 
70  ::fwData::TransferFunction::sptr tf = this->getInOut< ::fwData::TransferFunction >(s_TF_INOUT);
71  ::fwData::Image::sptr image = this->getInOut< ::fwData::Image >(s_IMAGE_INOUT);
72  SLM_ASSERT("Missing image", image);
73 
74  this->setOrCreateTF(tf, image);
75 
76  this->updating();
77 }
78 
79 //------------------------------------------------------------------------------
80 
82 {
83  this->removeTFConnections();
84  this->destroyPipeline();
85 }
86 
87 //------------------------------------------------------------------------------
88 
90 {
91  ::fwData::Image::sptr image = this->getInOut< ::fwData::Image >(s_IMAGE_INOUT);
92  SLM_ASSERT("Missing image", image);
93 
95 
96  if (imageIsValid)
97  {
98  this->updateImage(image);
99  this->buildPipeline();
100  this->updateImageTransferFunction();
101  this->updateImageOpacity();
102  }
103 
104  this->requestRender();
105 }
106 
107 //------------------------------------------------------------------------------
108 
109 void SImage::swapping(const KeyType& key)
110 {
111  if (key == s_TF_INOUT)
112  {
113  ::fwData::TransferFunction::sptr tf = this->getInOut< ::fwData::TransferFunction >(s_TF_INOUT);
114  ::fwData::Image::sptr image = this->getInOut< ::fwData::Image >(s_IMAGE_INOUT);
115  SLM_ASSERT("Missing image", image);
116 
117  this->setOrCreateTF(tf, image);
118  this->updating();
119  }
120 }
121 
122 //------------------------------------------------------------------------------
123 
125 {
126  this->updateImageTransferFunction();
127  this->requestRender();
128 }
129 
130 //------------------------------------------------------------------------------
131 
132 void SImage::updateTFWindowing(double window, double level)
133 {
134  ::fwData::Image::sptr image = this->getInOut< ::fwData::Image >(s_IMAGE_INOUT);
135  SLM_ASSERT("Missing image", image);
136 
137  m_lut->SetWindow(window);
138  m_lut->SetLevel(level);
139  m_lut->Modified();
140  this->setVtkPipelineModified();
141  this->requestRender();
142 }
143 
144 //------------------------------------------------------------------------------
145 
147 {
148  this->configureParams();
149 
150  const ConfigType config = this->getConfigTree().get_child("config.<xmlattr>");
151 
152  this->setVtkImageRegisterId( config.get<std::string>("vtkimageregister", ""));
153 
154  m_imageOpacity = config.get<double>("opacity", 0.);
155 
156  const std::string tfalpha = config.get<std::string>("tfalpha", "no");
157  SLM_ASSERT("'tfalpha' value must be 'yes' or 'no', actual: " + tfalpha, tfalpha == "yes" || tfalpha == "no");
158  this->setAllowAlphaInTF(tfalpha == "yes");
159 }
160 
161 //------------------------------------------------------------------------------
162 
163 void SImage::updateImage( ::fwData::Image::sptr image )
164 {
165  ::fwVtkIO::toVTKImage(image, m_imageData);
166 
167  this->updateImageInfos(image);
168  this->setVtkPipelineModified();
169 }
170 
171 //------------------------------------------------------------------------------
172 
173 void SImage::updateImageTransferFunction()
174 {
175  ::fwData::TransferFunction::sptr tf = this->getTransferFunction();
176 
177  ::fwVtkIO::helper::TransferFunction::toVtkLookupTable( tf, m_lut, m_allowAlphaInTF, 256 );
178 
179  m_lut->SetClamping( !tf->getIsClamped() );
180  m_lut->SetWindow(tf->getWindow());
181  m_lut->SetLevel(tf->getLevel());
182 
183  this->setVtkPipelineModified();
184 }
185 
186 //------------------------------------------------------------------------------
187 
189 {
190  if (m_imagePortId >= 0)
191  {
192  ::fwData::Image::sptr img = this->getInOut< ::fwData::Image >(s_IMAGE_INOUT);
193  SLM_ASSERT("Missing image", img);
194 
195  if(img->getField( "TRANSPARENCY" ) )
196  {
197  ::fwData::Integer::sptr transparency = img->getField< ::fwData::Integer >( "TRANSPARENCY" );
198  m_imageOpacity = (100 - (*transparency) ) / 100.0;
199  }
200  if(img->getField( "VISIBILITY" ) )
201  {
202  ::fwData::Boolean::sptr visible = img->getField< ::fwData::Boolean >( "VISIBILITY" );
203  m_imageOpacity = (*visible) ? m_imageOpacity : 0.0;
204  }
205 
206  vtkImageBlend* imageBlend = vtkImageBlend::SafeDownCast(m_imageRegister);
207  if(nullptr != imageBlend )
208  {
209  imageBlend->SetOpacity(m_imagePortId, m_imageOpacity);
210  OSLM_TRACE(
211  "vtkImageBlend " << this->m_imageRegisterId << " opacity :" << m_imagePortId << "," << m_imageOpacity );
212  }
213 
214  this->setVtkPipelineModified();
215  this->requestRender();
216  }
217 }
218 
219 //------------------------------------------------------------------------------
220 
221 void SImage::buildPipeline( )
222 {
223  m_map2colors->SetInputData(m_imageData);
224  m_map2colors->SetLookupTable(m_lut);
225  m_map2colors->SetOutputFormatToRGBA();
226 
227  if (!m_imageRegisterId.empty())
228  {
229  m_imageRegister = this->getVtkObject(m_imageRegisterId);
230  }
231 
232  vtkImageAlgorithm* algorithm = vtkImageAlgorithm::SafeDownCast(m_imageRegister);
233  vtkImageData* imageData = vtkImageData::SafeDownCast(m_imageRegister);
234  vtkImageBlend* imageBlend = vtkImageBlend::SafeDownCast(m_imageRegister);
235  vtkImageCheckerboard* imageChecker = vtkImageCheckerboard::SafeDownCast(m_imageRegister);
236 
237  SLM_ASSERT("Invalid vtk image register", algorithm||imageData||imageBlend||imageChecker );
238  if (imageBlend)
239  {
240  SLM_TRACE("Register is a vtkImageBlend");
241  if (m_imagePortId < 0)
242  {
243  m_imagePortId = imageBlend->GetNumberOfInputConnections(0);
244  imageBlend->AddInputConnection(m_map2colors->GetOutputPort());
245  OSLM_TRACE(this->getID() << ": Added image " << m_imagePortId << " on vtkImageBlend");
246  }
247  }
248  else if (imageChecker)
249  {
250  SLM_TRACE("Register is a vtkImageCheckerboard");
251  if (m_imagePortId < 0)
252  {
253  m_imagePortId = imageChecker->GetNumberOfInputConnections(0);
254  imageChecker->SetInputConnection(m_imagePortId, m_map2colors->GetOutputPort());
255  OSLM_TRACE(this->getID() << ": Added image " << m_imagePortId << " on vtkImageCheckerboard");
256  }
257  }
258  else if (algorithm)
259  {
260  SLM_TRACE("Register is a vtkImageAlgorithm");
261  algorithm->SetInputConnection(m_map2colors->GetOutputPort());
262  }
263  else if (imageData)
264  {
265  SLM_TRACE("Register is a vtkImageData");
266  m_map2colors->SetOutput(imageData);
267  m_map2colors->Update();
268  }
269 
270  this->setVtkPipelineModified();
271 }
272 
273 //------------------------------------------------------------------------------
274 
275 void SImage::destroyPipeline( )
276 {
277  vtkImageAlgorithm* algorithm = vtkImageAlgorithm::SafeDownCast(m_imageRegister);
278  vtkImageData* imageData = vtkImageData::SafeDownCast(m_imageRegister);
279  vtkImageBlend* imageBlend = vtkImageBlend::SafeDownCast(m_imageRegister);
280  vtkImageCheckerboard* imageChecker = vtkImageCheckerboard::SafeDownCast(m_imageRegister);
281 
282  if (imageBlend)
283  {
284  if (m_imagePortId >= 0)
285  {
286  //Warning : only the removal of the last input connection in the image blend is safe.
287  imageBlend->RemoveInputConnection(0, m_map2colors->GetOutputPort());
288  m_imagePortId = -1;
289  }
290  }
291  else if(imageChecker)
292  {
293  if (m_imagePortId >= 0)
294  {
295  //Warning : only the removal of the last input connection in the image blend is safe.
296  imageChecker->RemoveInputConnection(0, m_map2colors->GetOutputPort());
297  m_imagePortId = -1;
298  }
299  }
300  else if (algorithm)
301  {
302  algorithm->RemoveInputConnection(0, m_map2colors->GetOutputPort());
303  }
304  else if (imageData)
305  {
306  m_map2colors->SetOutput(0);
307  }
308 
309  this->setVtkPipelineModified();
310 }
311 
312 //------------------------------------------------------------------------------
313 
315 {
316  KeyConnectionsMap connections;
317  connections.push(s_IMAGE_INOUT, ::fwData::Image::s_MODIFIED_SIG, s_UPDATE_SLOT);
318  connections.push(s_IMAGE_INOUT, ::fwData::Image::s_VISIBILITY_MODIFIED_SIG, s_UPDATE_IMAGE_OPACITY_SLOT);
319  connections.push(s_IMAGE_INOUT, ::fwData::Image::s_TRANSPARENCY_MODIFIED_SIG, s_UPDATE_IMAGE_OPACITY_SLOT);
320  connections.push(s_IMAGE_INOUT, ::fwData::Image::s_BUFFER_MODIFIED_SIG, s_UPDATE_SLOT);
321 
322  return connections;
323 }
324 
325 //------------------------------------------------------------------------------
326 
327 } //namespace visuVTKAdaptor
Render an image on the generic scene.
Definition: SImage.hpp:62
VISUVTKADAPTOR_API void configuring() override
Configure the service before starting. Apply the configuration to service.
Definition: SImage.cpp:146
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_TRANSPARENCY_MODIFIED_SIG
Type of signal when image&#39;s buffer is added.
This class is a helper to define the connections of a service and its data.
Definition: IService.hpp:454
FWRENDERVTK_API vtkObject * getVtkObject(const SRender::VtkObjectIdType &objectId) const
Returns the vtk object defined by &#39;objectId&#39; in the vtk scene.
FWDATATOOLS_API::fwData::TransferFunction::sptr getTransferFunction() const
Get the current transfer function.
FWDATATOOLS_API void installTFSlots(::fwCom::HasSlots *hasslots)
Install the slots to managed TF modifications.
virtual VISUVTKADAPTOR_API void updateTFPoints() override
Slot: update the displayed lookup table.
Definition: SImage.cpp:124
The namespace visuVTKAdaptor contains the list of adaptors available for the generic scene...
static FWVTKIO_API void toVtkLookupTable(fwData::TransferFunction::csptr tf, vtkSmartPointer< vtkLookupTable > lt, bool allowTransparency=false, unsigned int size=256)
Convert a fwData::TransferFunction to a vtkLookupTable.
This class contains an integer value. Integer object is essentially used as a field in other objects...
Definition: Integer.hpp:24
FWRENDERVTK_API void configureParams()
Parse the xml configuration for renderer, picker and transform.
FWRENDERVTK_API void requestRender()
notify a render request iff vtkPipeline is modified
virtual void swapping()
Swap the service from associated object to another object.
Definition: IService.hpp:613
FWRENDERVTK_API void setVtkPipelineModified()
End-user have to call this method when a vtk structure has been modified, thus a render request will ...
#define OSLM_TRACE(message)
Definition: spyLog.hpp:230
VISUVTKADAPTOR_API void updating() override
Perform some computations according to object (this service is attached to) attribute values and its ...
Definition: SImage.cpp:89
FWTOOLS_API IDType getID(Policy policy=GENERATE) const
Returns the id of the object. If it is not set and the policy value is.
Definition: fwID.cpp:78
virtual VISUVTKADAPTOR_API KeyConnectionsMap getAutoConnections() const override
Returns proposals to connect service slots to associated object signals, this method is used for obj/...
Definition: SImage.cpp:314
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_VISIBILITY_MODIFIED_SIG
Type of signal when image&#39;s buffer is added.
FWDATATOOLS_API void updateImageInfos(::fwData::Image::sptr image)
Update the image information (slice index, min/max,...)
void updateImageOpacity()
Slot: Update image opacity and visibility.
Definition: SImage.cpp:188
VISUVTKADAPTOR_API void stopping() override
Uninitialize the service activity. The stop() method is always invoked before destroying a service...
Definition: SImage.cpp:81
#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
VISUVTKADAPTOR_API void starting() override
Initialize the service activity.
Definition: SImage.cpp:66
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_BUFFER_MODIFIED_SIG
Type of signal when image&#39;s buffer is added.
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_MODIFIED_SIG
Key in m_signals map of signal m_sigModified.
FWDATATOOLS_API void removeTFConnections()
Remove the TF connections.
static FWDATATOOLS_API bool checkImageValidity(::fwData::Image::csptr _pImg)
Check if the image is valid.
#define SLM_TRACE(message)
Definition: spyLog.hpp:228
FWRENDERVTK_API void initialize()
Initialize the adaptor with the associated render service. (must be call in starting).
FWDATATOOLS_API void setOrCreateTF(const ::fwData::TransferFunction::sptr &_tf, const fwData::Image::sptr &_image)
Sets the transfer function, creates one if _tf is null (.
Reinplementation of vtkWindowLevelLookupTable : add specific out-of-bounds colors.
static FWSERVICES_APIconst::fwCom::Slots::SlotKeyType s_UPDATE_SLOT
Slot to call start method.
Definition: IService.hpp:177
This class contains a boolean value.
FWSERVICES_API ConfigType getConfigTree() const
Return the configuration, in an boost property tree.
Definition: IService.cpp:247
virtual VISUVTKADAPTOR_API void updateTFWindowing(double window, double level) override
Slot: update the windowing of the displayed lookup table.
Definition: SImage.cpp:132