7 #include "visuVTKAdaptor/SImagesBlend.hpp" 9 #include "visuVTKAdaptor/SImage.hpp" 11 #include <fwCom/Slot.hpp> 12 #include <fwCom/Slot.hxx> 13 #include <fwCom/Slots.hpp> 14 #include <fwCom/Slots.hxx> 16 #include <fwData/Boolean.hpp> 17 #include <fwData/Color.hpp> 18 #include <fwData/Image.hpp> 19 #include <fwData/Integer.hpp> 20 #include <fwData/String.hpp> 21 #include <fwData/TransferFunction.hpp> 23 #include <fwDataTools/fieldHelper/Image.hpp> 24 #include <fwDataTools/fieldHelper/MedicalImageHelpers.hpp> 26 #include <fwGui/dialog/MessageDialog.hpp> 28 #include <fwMath/Compare.hpp> 30 #include <fwServices/macros.hpp> 31 #include <fwServices/op/Add.hpp> 33 #include <fwVtkIO/vtk.hpp> 35 #include <boost/foreach.hpp> 37 #include <vtkImageBlend.h> 38 #include <vtkImageCheckerboard.h> 39 #include <vtkImageData.h> 40 #include <vtkImageMapToColors.h> 41 #include <vtkLookupTable.h> 50 const ::fwCom::Slots::SlotKeyType s_CHANGE_MODE_SLOT =
"changeMode";
51 const ::fwCom::Slots::SlotKeyType s_CHANGE_CHECKERBOARD_DIVISION_SLOT =
"changeCheckerboardDivision";
52 const ::fwCom::Slots::SlotKeyType s_SET_TOP_IMAGE_TRANSPARENCY_SLOT =
"setTopImageTransparency";
54 static const ::fwServices::IService::KeyType s_IMAGE_GROUP =
"image";
55 static const ::fwServices::IService::KeyType s_TF_GROUP =
"tf";
59 SImagesBlend::SImagesBlend() noexcept :
60 m_imageAlgorithm(
nullptr),
61 m_checkerboardDivision(10),
62 m_zDivision(m_checkerboardDivision)
64 newSlot(s_CHANGE_MODE_SLOT, &SImagesBlend::changeMode,
this);
65 newSlot(s_CHANGE_CHECKERBOARD_DIVISION_SLOT, &SImagesBlend::changeCheckerboardDivision,
this);
66 newSlot(s_SET_TOP_IMAGE_TRANSPARENCY_SLOT, &SImagesBlend::setTopImageTransparency,
this);
71 SImagesBlend::~SImagesBlend() noexcept
73 m_imageAlgorithm =
nullptr;
82 SLM_ASSERT(
"Image register is empty", !m_imageRegisterId.empty());
85 m_imageAlgorithm = vtkImageBlend::SafeDownCast(this->
getVtkObject(m_imageRegisterId));
87 if(
nullptr == m_imageAlgorithm)
90 m_imageAlgorithm = vtkImageCheckerboard::SafeDownCast(this->
getVtkObject(m_imageRegisterId));
94 SLM_ASSERT(
"Stored image algorithm doesn't contain a vtkImageBlend or vtkImageCheckerboard",
95 nullptr != m_imageAlgorithm);
97 this->addImageAdaptors();
100 this->changeCheckerboardDivision(m_checkerboardDivision);
107 this->removeImageAdaptors();
108 m_imageAlgorithm =
nullptr;
109 m_imagesInfo.clear();
116 this->removeImageAdaptors();
117 this->addImageAdaptors();
128 BOOST_FOREACH(const ::fwServices::IService::ConfigType::value_type& cfg, srvConfig.equal_range(
"inout"))
130 const ConfigType inoutConfig = cfg.second;
131 const std::string group = inoutConfig.get<std::string>(
"<xmlattr>.group");
132 if (group == s_IMAGE_GROUP)
134 BOOST_FOREACH(const ::fwServices::IService::ConfigType::value_type& v, inoutConfig.equal_range(
"key"))
136 const ::fwServices::IService::ConfigType& specAssoc = v.second;
137 const ::fwServices::IService::ConfigType& attr = specAssoc.get_child(
"<xmlattr>");
138 const std::string tfalpha = attr.get(
"tfalpha",
"no");
139 const double opacity = attr.get(
"opacity", 1.0);
142 info.m_imageOpacity = opacity;
143 info.m_useTFAlfa = (tfalpha ==
"yes");
144 m_imagesInfo.push_back(info);
149 const ConfigType config = srvConfig.get_child(
"config.<xmlattr>");
151 const std::string vtkimageregister = config.get(
"vtkimageregister",
"");
152 SLM_ASSERT(
"'vtkimageregister' must be defined", !vtkimageregister.empty());
153 this->setVtkImageRegisterId(vtkimageregister);
156 m_checkerboardDivision = config.get<
int>(
"checkerboardDivision", 10);
163 const std::string regexStr =
"([[:alnum:]]+)#([[:digit:]]+)";
164 const std::regex re(regexStr);
167 if( std::regex_match(key, match, re) )
169 const std::string group = match[1];
170 const unsigned long index = std::stoul(match[2]);
178 ::fwData::TransferFunction::sptr tf = this->getInOut< ::fwData::TransferFunction >(s_TF_GROUP, index);
179 ::fwServices::IService::sptr service = wsrv.lock();
182 service->registerInOut(tf, SImage::s_TF_INOUT,
false,
true);
183 service->swapKey(SImage::s_TF_INOUT,
nullptr);
187 ::fwServices::OSR::unregisterService(SImage::s_TF_INOUT, AccessType::INOUT, service);
188 service->swapKey(SImage::s_TF_INOUT,
nullptr);
203 bool haveSameInfo =
true;
207 for(
size_t i = 0; i < nbImages; ++i)
209 ::fwData::Image::csptr img = this->getInOut< ::fwData::Image >(s_IMAGE_GROUP, i);
213 if (size.empty() && spacing.empty() && origin.empty())
215 size = img->getSize();
216 spacing = img->getSpacing();
217 origin = img->getOrigin();
219 if(size.size() < 3 || size[2] <= 1)
226 if ( size != img->getSize() ||
227 !::fwMath::isContainerEqual< const ::fwData::Image::SpacingType >(spacing,
228 img->getSpacing()) ||
229 !::fwMath::isContainerEqual< const ::fwData::Image::OriginType >(origin,
232 OSLM_ERROR(
"imgA size : " << size[0] <<
" / " << size[1] <<
" / "<< size[2] );
233 OSLM_ERROR(
"imgA spacing : " << spacing[0] <<
" / " << spacing[1] <<
" / "<< spacing[2] );
234 OSLM_ERROR(
"imgA origin : " << origin[0] <<
" / " << origin[1] <<
" / "<< origin[2] );
237 "imgB size : " << img->getSize()[0] <<
" / " << img->getSize()[1] <<
" / "<<
240 "imgB spacing : " << img->getSpacing()[0] <<
" / " << img->getSpacing()[1] <<
" / "<<
241 img->getSpacing()[2] );
243 "imgB origin : " << img->getOrigin()[0] <<
" / " << img->getOrigin()[1] <<
" / "<<
244 img->getOrigin()[2] );
246 haveSameInfo =
false;
247 std::string errorMsg =
"Warning : images in blend have not the same";
248 errorMsg += (size != img->getSize()) ?
" size" :
"";
249 errorMsg += (spacing != img->getSpacing()) ?
" spacing" :
"";
250 errorMsg += (origin != img->getOrigin()) ?
" origin" :
"";
251 errorMsg +=
".\n Background image size, spacing and origin are use.";
254 ::fwGui::dialog::IMessageDialog::WARNING);
266 void SImagesBlend::addImageAdaptors()
270 int addedImageCount = 0;
271 size_t lastValidIndex = 0;
275 SLM_ASSERT(
"'" + s_TF_GROUP +
"' group must have the same number of elements that '" + s_IMAGE_GROUP +
"'",
276 nbTFs == 0 || nbImages == nbTFs);
278 for(
size_t i = 0; i < nbImages; ++i)
280 ::fwData::Image::sptr img = this->getInOut< ::fwData::Image >(s_IMAGE_GROUP, i);
281 ::fwData::TransferFunction::sptr tf;
287 tf = this->getInOut< ::fwData::TransferFunction >(s_TF_GROUP, i);
295 this->addImage(img, tf, info);
304 if(addedImageCount == 1 &&
nullptr != vtkImageCheckerboard::SafeDownCast(this->
getVtkObject(m_imageRegisterId)))
306 ::fwData::Image::sptr img = this->getInOut< ::fwData::Image >(s_IMAGE_GROUP, lastValidIndex);
307 ::fwData::TransferFunction::sptr tf;
310 tf = this->getInOut< ::fwData::TransferFunction >(s_TF_GROUP, lastValidIndex);
313 this->addImage(img, tf, info);
319 void SImagesBlend::removeImageAdaptors()
337 void SImagesBlend::changeMode(std::string _value, std::string _key)
339 if( _key ==
"ImageSource" )
342 m_imageRegisterId = _value;
345 m_imageAlgorithm = vtkImageBlend::SafeDownCast(this->
getVtkObject(m_imageRegisterId));
347 if(
nullptr == m_imageAlgorithm)
350 vtkImageCheckerboard* imageCheckerboard =
351 vtkImageCheckerboard::SafeDownCast(this->
getVtkObject(m_imageRegisterId));
353 if(
nullptr != imageCheckerboard)
356 imageCheckerboard->SetNumberOfDivisions(m_checkerboardDivision, m_checkerboardDivision,
360 m_imageAlgorithm = imageCheckerboard;
371 void SImagesBlend::addImage(::fwData::Image::sptr img, ::fwData::TransferFunction::sptr tf,
const ImageInfo&
info)
374 auto imageAdaptor = this->registerService< ::visuVTKAdaptor::SImage>(
"::visuVTKAdaptor::SImage");
376 imageAdaptor->registerInOut(img, SImage::s_IMAGE_INOUT,
true);
379 imageAdaptor->registerInOut(tf, SImage::s_TF_INOUT,
false,
true);
387 imageAdaptor->setVtkImageRegister(m_imageAlgorithm);
388 imageAdaptor->setImageOpacity(info.m_imageOpacity);
389 imageAdaptor->setAllowAlphaInTF(info.m_useTFAlfa);
391 imageAdaptor->start();
396 void SImagesBlend::setTopImageTransparency(
int transparency)
398 SLM_ASSERT(
"The image group is empty. Have you started the service?", m_imagesInfo.size() > 0);
399 SLM_ERROR_IF(
"Transparency must be in [0, 255].", transparency < 0 || transparency > 255);
400 auto topImageInfo = m_imagesInfo.rbegin();
402 topImageInfo->m_imageOpacity = 1. - (double(transparency) / 255.);
408 void SImagesBlend::changeCheckerboardDivision(
const int division)
410 m_checkerboardDivision = division;
413 vtkImageCheckerboard* imageCheckerboard =
414 vtkImageCheckerboard::SafeDownCast(this->
getVtkObject(m_imageRegisterId));
416 if(
nullptr != imageCheckerboard)
419 imageCheckerboard->SetNumberOfDivisions(m_checkerboardDivision, m_checkerboardDivision,
423 m_imageAlgorithm = imageCheckerboard;
This class is a helper to define the connections of a service and its data.
FWRENDERVTK_API vtkObject * getVtkObject(const SRender::VtkObjectIdType &objectId) const
Returns the vtk object defined by 'objectId' in the vtk scene.
The namespace visuVTKAdaptor contains the list of adaptors available for the generic scene...
static FWGUI_API IMessageDialog::Buttons showMessageDialog(const std::string &title, const std::string &message,::fwGui::dialog::IMessageDialog::Icons icon=INFO)
FWRENDERVTK_API void configureParams()
Parse the xml configuration for renderer, picker and transform.
VISUVTKADAPTOR_API void updating() override
Perform some computations according to object (this service is attached to) attribute values and its ...
const ServiceVector & getRegisteredServices() const
Get all subservices linked to this service.
VISUVTKADAPTOR_API void starting() override
Initialize the service activity.
Manage blend for image given in configuration.
virtual void swapping()
Swap the service from associated object to another object.
FWRENDERVTK_API SRender::sptr getRenderService() const
Returd the associated render service.
FWRENDERVTK_API SRender::PickerIdType getPickerId() const
Gets the identifier of the picker used by this adaptor.
VISUVTKADAPTOR_API void stopping() override
Uninitialize the service activity. The stop() method is always invoked before destroying a service...
#define OSLM_ERROR(message)
#define SLM_ERROR_IF(message, cond)
FWSERVICES_API void unregisterServices(const std::string &_implType="")
Unregister all services linked to this service, optionally matches only a given type of services...
#define SLM_ASSERT(message, cond)
work like 'assert' from 'cassert', with in addition a message logged by spylog (with FATAL loglevel) ...
bool checkImageInformations()
Return true if images to blend have the same spacing, origin and size. Else show a message dialog and...
FWRENDERVTK_API SRender::VtkObjectIdType getTransformId() const
Returns the identifier of the transform used by this adaptor.
virtual VISUVTKADAPTOR_API KeyConnectionsMap getAutoConnections() const override
Returns proposals to connect service slots to associated object signals, this method is used for obj/...
size_t getKeyGroupSize(const KeyType &keybase) const
Return the number of key in a group of keys.
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_BUFFER_MODIFIED_SIG
Type of signal when image's buffer is added.
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_MODIFIED_SIG
Key in m_signals map of signal m_sigModified.
std::vector< double > SpacingType
Image spacing type.
FWRENDERVTK_API SRender::RendererIdType getRendererId() const
Returns the renderer identifier.
FWRENDERVTK_API void initialize()
Initialize the adaptor with the associated render service. (must be call in starting).
This class defines a composite object.
VISUVTKADAPTOR_API void configuring() override
Configure the service before starting. Apply the configuration to service.
FWSERVICES_API bool isRegistered(const ::fwServices::IService::KeyType &objKey,::fwServices::IService::AccessType access,::fwServices::IService::sptr service)
Return true if a key is registered for a given service.
static FWSERVICES_APIconst::fwCom::Slots::SlotKeyType s_UPDATE_SLOT
Slot to call start method.
::fwData::Array::SizeType SizeType
Image size type.
Base class for VTK adaptors.
virtual FWSERVICES_API void info(std::ostream &_sstream)
Write information in a stream.
std::vector< double > OriginType
Image origin type.
FWSERVICES_API ConfigType getConfigTree() const
Return the configuration, in an boost property tree.