7 #include "scene2D/adaptor/SNegato.hpp" 9 #include <fwCom/Signal.hpp> 10 #include <fwCom/Signal.hxx> 11 #include <fwCom/Signals.hpp> 12 #include <fwCom/Slot.hpp> 13 #include <fwCom/Slot.hxx> 14 #include <fwCom/Slots.hpp> 15 #include <fwCom/Slots.hxx> 17 #include <fwData/Image.hpp> 18 #include <fwData/TransferFunction.hpp> 20 #include <fwDataTools/fieldHelper/Image.hpp> 21 #include <fwDataTools/fieldHelper/MedicalImageHelpers.hpp> 22 #include <fwDataTools/helper/Image.hpp> 24 #include <fwRenderQt/Scene2DGraphicsView.hpp> 26 #include <fwServices/macros.hpp> 29 #include <QGraphicsItemGroup> 39 static const ::fwServices::IService::KeyType s_IMAGE_INOUT =
"image";
40 static const ::fwServices::IService::KeyType s_TF_INOUT =
"tf";
42 static const ::fwCom::Slots::SlotKeyType s_UPDATE_SLICE_INDEX_SLOT =
"updateSliceIndex";
43 static const ::fwCom::Slots::SlotKeyType s_UPDATE_SLICE_TYPE_SLOT =
"updateSliceType";
44 static const ::fwCom::Slots::SlotKeyType s_UPDATE_BUFFER_SLOT =
"updateBuffer";
45 static const ::fwCom::Slots::SlotKeyType s_UPDATE_VISIBILITY_SLOT =
"updateVisibility";
47 typedef ::fwDataTools::helper::MedicalImageAdaptor MedicalImageAdaptor;
51 SNegato::SNegato() noexcept :
53 m_pixmapItem(
nullptr),
55 m_orientation(MedicalImageAdaptor::Z_AXIS),
56 m_pointIsCaptured(false),
57 m_changeSliceTypeAllowed(true)
60 newSlot(s_UPDATE_SLICE_INDEX_SLOT, &SNegato::updateSliceIndex,
this);
61 newSlot(s_UPDATE_SLICE_TYPE_SLOT, &SNegato::updateSliceType,
this);
62 newSlot(s_UPDATE_BUFFER_SLOT, &SNegato::updateBuffer,
this);
63 newSlot(s_UPDATE_VISIBILITY_SLOT, &SNegato::updateVisibility,
this);
68 SNegato::~SNegato() noexcept
78 const ConfigType config = this->
getConfigTree().get_child(
"config.<xmlattr>");
80 if( config.count(
"orientation") )
82 const std::string orientationValue = config.get<std::string>(
"orientation");
84 if ( orientationValue ==
"axial" )
86 m_orientation = MedicalImageAdaptor::Z_AXIS;
88 else if ( orientationValue ==
"sagittal" )
90 m_orientation = MedicalImageAdaptor::X_AXIS;
92 else if ( orientationValue ==
"frontal" )
94 m_orientation = MedicalImageAdaptor::Y_AXIS;
98 if(config.count(
"changeSliceType"))
100 const std::string changeValue = config.get<std::string>(
"changeSliceType");
102 if(changeValue ==
"true" || changeValue ==
"yes")
104 m_changeSliceTypeAllowed =
true;
106 else if(changeValue ==
"no" || changeValue ==
"false")
108 m_changeSliceTypeAllowed =
false;
115 void SNegato::updateBufferFromImage( QImage* qimg )
123 const double wlMin = tf->getWLMinMax().first;
126 ::fwData::Image::sptr image = this->getInOut< ::fwData::Image >(s_IMAGE_INOUT);
128 const ::fwData::Image::SizeType size = image->getSize();
129 const short* imgBuff =
static_cast<const short*
>(imgHelper.getBuffer());
130 const size_t imageZOffset = size[0] * size[1];
132 const double tfMin = tf->getMinMaxTFValues().first;
133 const double tfMax = tf->getMinMaxTFValues().second;
134 const double tfWin = (1. / tf->getWindow()) * ((tfMax - tfMin) + tfMin);
136 std::uint8_t* pDest = qimg->bits();
139 if( m_orientation == MedicalImageAdaptor::X_AXIS )
141 const size_t sagitalIndex =
static_cast<size_t>(
m_sagittalIndex->value());
143 for(
size_t z = 0; z < size[2]; ++z)
145 const size_t zOffset = (size[2] - 1 - z) * imageZOffset;
146 const size_t zxOffset = zOffset + sagitalIndex;
148 for(
size_t y = 0; y < size[1]; ++y )
150 const QRgb val = this->getQImageVal(zxOffset + y * size[0], imgBuff, wlMin, tfWin, tf);
152 *pDest++ =
static_cast<std::uint8_t
>(qRed(val));
153 *pDest++ =
static_cast<std::uint8_t
>(qGreen(val));
154 *pDest++ =
static_cast<std::uint8_t
>(qBlue(val));
158 else if( m_orientation == MedicalImageAdaptor::Y_AXIS )
160 const size_t frontalIndex =
static_cast<size_t>(
m_frontalIndex->value());
161 const size_t yOffset = frontalIndex * size[0];
163 for(
size_t z = 0; z < size[2]; ++z)
165 const size_t zOffset = (size[2] - 1 - z) * imageZOffset;
166 const size_t zyOffset = zOffset + yOffset;
168 for(
size_t x = 0;
x < size[0]; ++
x )
170 const QRgb val = this->getQImageVal(zyOffset +
x, imgBuff, wlMin, tfWin, tf);
172 *pDest++ =
static_cast<std::uint8_t
>(qRed(val));
173 *pDest++ =
static_cast<std::uint8_t
>(qGreen(val));
174 *pDest++ =
static_cast<std::uint8_t
>(qBlue(val));
178 else if( m_orientation == MedicalImageAdaptor::Z_AXIS )
180 const size_t axialIndex =
static_cast<size_t>(
m_axialIndex->value());
181 const size_t zOffset = axialIndex * imageZOffset;
183 for(
size_t y = 0; y < size[1]; ++y )
185 const size_t yOffset = y * size[0];
186 const size_t zyOffset = zOffset + yOffset;
188 for(
size_t x = 0;
x < size[0]; ++
x )
190 const QRgb val = this->getQImageVal(zyOffset +
x, imgBuff, wlMin, tfWin, tf);
192 *pDest++ =
static_cast<std::uint8_t
>(qRed(val));
193 *pDest++ =
static_cast<std::uint8_t
>(qGreen(val));
194 *pDest++ =
static_cast<std::uint8_t
>(qBlue(val));
199 QPixmap m_pixmap = QPixmap::fromImage( *m_qimg );
200 m_pixmapItem->setPixmap(m_pixmap);
205 QRgb SNegato::getQImageVal(
const size_t index,
const short* buffer,
double wlMin,
double tfWin,
206 const fwData::TransferFunction::sptr& tf)
208 const short val16 = buffer[index];
210 double value = (val16 - wlMin) * tfWin;
212 const ::fwData::TransferFunction::TFColor color = tf->getInterpolatedColor(value);
215 return qRgb(static_cast<int>(color.r*255), static_cast<int>(color.g*255), static_cast<int>(color.b*255));
220 QImage* SNegato::createQImage()
222 ::fwData::Image::sptr img = this->getInOut< ::fwData::Image >(s_IMAGE_INOUT);
229 const ::fwData::Image::SizeType size = img->getSize();
230 const ::fwData::Image::SpacingType spacing = img->getSpacing();
231 const ::fwData::Image::OriginType origin = img->getOrigin();
233 double qImageSpacing[2];
234 double qImageOrigin[2];
237 switch ( m_orientation )
239 case MedicalImageAdaptor::X_AXIS:
241 qImageSize[0] =
static_cast<int>(size[1]);
242 qImageSize[1] =
static_cast<int>(size[2]);
243 qImageSpacing[0] = spacing[1];
244 qImageSpacing[1] = spacing[2];
245 qImageOrigin[0] = origin[1] - 0.5f*spacing[1];
246 qImageOrigin[1] = -( origin[2] + size[2] * spacing[2] - 0.5f*spacing[2]);
249 case MedicalImageAdaptor::Y_AXIS:
250 qImageSize[0] =
static_cast<int>(size[0]);
251 qImageSize[1] =
static_cast<int>(size[2]);
252 qImageSpacing[0] = spacing[0];
253 qImageSpacing[1] = spacing[2];
254 qImageOrigin[0] = origin[0] - 0.5f*spacing[0];
255 qImageOrigin[1] = -( origin[2] + size[2] * spacing[2] - 0.5f*spacing[2]);
258 case MedicalImageAdaptor::Z_AXIS:
259 qImageSize[0] =
static_cast<int>(size[0]);
260 qImageSize[1] =
static_cast<int>(size[1]);
261 qImageSpacing[0] = spacing[0];
262 qImageSpacing[1] = spacing[1];
263 qImageOrigin[0] = origin[0] - 0.5f*spacing[0];
264 qImageOrigin[1] = origin[1] - 0.5f*spacing[1];
268 SLM_FATAL(
"Unsupported value for m_orientation");
273 QImage* qimage =
new QImage(qImageSize[0], qImageSize[1], QImage::Format_RGB888);
276 m_pixmapItem->resetTransform();
277 m_pixmapItem->setTransform(QTransform::fromScale(qImageSpacing[0], qImageSpacing[1]),
true);
278 m_pixmapItem->setPos(qImageOrigin[0], qImageOrigin[1]);
281 m_layer->removeFromGroup( m_pixmapItem );
282 m_layer->addToGroup( m_pixmapItem );
294 ::fwData::TransferFunction::sptr tf = this->getInOut< ::fwData::TransferFunction >(s_TF_INOUT);
297 ::fwData::Image::sptr image = this->getInOut< ::fwData::Image >(s_IMAGE_INOUT);
301 m_pixmapItem =
new QGraphicsPixmapItem();
302 m_pixmapItem->setShapeMode( QGraphicsPixmapItem::BoundingRectShape );
303 m_pixmapItem->setTransformationMode(Qt::SmoothTransformation);
304 m_layer =
new QGraphicsItemGroup();
305 m_layer->resetTransform();
306 m_layer->addToGroup( m_pixmapItem );
311 m_qimg = this->createQImage();
312 this->updateBufferFromImage( m_qimg );
323 m_qimg = this->createQImage();
324 this->updateBufferFromImage( m_qimg );
331 if (key == s_TF_INOUT)
333 ::fwData::TransferFunction::sptr tf = this->getInOut< ::fwData::TransferFunction >(s_TF_INOUT);
334 ::fwData::Image::sptr image = this->getInOut< ::fwData::Image >(s_IMAGE_INOUT);
344 void SNegato::updateSliceIndex(
int axial,
int frontal,
int sagittal)
350 ::fwData::Image::sptr image = this->getInOut< ::fwData::Image >(s_IMAGE_INOUT);
352 this->updateBufferFromImage( m_qimg );
357 void SNegato::updateSliceType(
int from,
int to)
359 if (m_changeSliceTypeAllowed)
361 if( to == static_cast< int > ( m_orientation ) )
365 else if(from == static_cast<int>(m_orientation))
371 if ( m_orientation == MedicalImageAdaptor::Z_AXIS )
386 void SNegato::updateVisibility(
bool isVisible)
390 m_layer->setVisible(
true);
394 m_layer->setVisible(
false);
400 void SNegato::updateBuffer()
402 this->updateBufferFromImage(m_qimg);
409 this->updateBufferFromImage( m_qimg );
416 this->updateBufferFromImage( m_qimg );
437 if(_event.getType() == ::fwRenderQt::data::Event::KeyRelease)
440 if ( _event.getKey() == Qt::Key_R )
443 QRectF recImage = m_pixmapItem->sceneBoundingRect();
445 ::fwRenderQt::data::Viewport::sptr sceneViewport = this->
getScene2DRender()->getViewport();
447 float sceneWidth =
static_cast<float>(this->
getScene2DRender()->getView()->width());
448 float sceneHeight =
static_cast<float>(this->
getScene2DRender()->getView()->height());
450 float ratioYonXimage = recImage.height() / recImage.width();
451 float sceneRatio = sceneHeight / sceneWidth;
453 if ( sceneRatio > ratioYonXimage )
455 float widthViewPortNew = recImage.width();
456 float heightViewPortNew = widthViewPortNew * sceneRatio;
459 float newOrigineY = recImage.y() - ( heightViewPortNew - recImage.height() ) / 2.f;
461 sceneViewport->setX( recImage.x() );
462 sceneViewport->setY( newOrigineY );
463 sceneViewport->setWidth( widthViewPortNew );
464 sceneViewport->setHeight( heightViewPortNew );
468 float heightViewPortNew = recImage.height();
469 float widthViewPortNew = heightViewPortNew / sceneRatio;
472 float newOrigineX = recImage.x() - (widthViewPortNew - recImage.width() )/ 2.f;
474 sceneViewport->setX( newOrigineX );
475 sceneViewport->setY( recImage.y() );
476 sceneViewport->setWidth( widthViewPortNew );
477 sceneViewport->setHeight( heightViewPortNew );
484 if ( _event.getKey() == Qt::Key_F )
486 m_pixmapItem->setTransformationMode(Qt::FastTransformation);
491 if ( _event.getKey() == Qt::Key_S )
493 m_pixmapItem->setTransformationMode(Qt::SmoothTransformation);
499 coord.setX( coord.getX() / m_layer->scale());
500 coord.setY( coord.getY() / m_layer->scale());
502 if ( _event.getType() == ::fwRenderQt::data::Event::MouseButtonPress
503 && _event.getButton() == ::fwRenderQt::data::Event::RightButton
504 && _event.getModifier() == ::fwRenderQt::data::Event::NoModifier )
506 m_pointIsCaptured =
true;
507 m_oldCoord = _event.getCoord();
508 _event.setAccepted(
true);
510 else if ( m_pointIsCaptured )
512 if( _event.getType() == ::fwRenderQt::data::Event::MouseMove )
515 this->changeImageMinMaxFromCoord( m_oldCoord, newCoord );
516 m_oldCoord = newCoord;
517 _event.setAccepted(
true);
519 else if( _event.getButton() == ::fwRenderQt::data::Event::RightButton
520 && _event.getType() == ::fwRenderQt::data::Event::MouseButtonRelease )
522 m_pointIsCaptured =
false;
523 _event.setAccepted(
true);
532 ::fwData::Image::sptr image = this->getInOut< ::fwData::Image >(s_IMAGE_INOUT);
535 const double min = tf->getWLMinMax().first;
536 const double max = tf->getWLMinMax().second;
538 const double window = newCoord.getX() - m_oldCoord.getX();
539 const double level = newCoord.getY() - m_oldCoord.getY();
541 const double imgWindow = max - min;
542 const double imgLevel = min + imgWindow/2.0;
544 const double newImgLevel = imgLevel + level;
545 const double newImgWindow = imgWindow + imgWindow * window/100.0;
550 tf->setWindow(newImgWindow);
551 tf->setLevel(newImgLevel);
556 sig->asyncEmit( newImgWindow, newImgLevel);
Root class for all scene2d adaptors.
SCENE2D_API void stopping() override
Uninitialize the service activity. The stop() method is always invoked before destroying a service...
::fwRenderQt::data::Axis::sptr m_xAxis
The x Axis.
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_SLICE_INDEX_MODIFIED_SIG
Type of signal when image's buffer is added.
This class is a helper to define the connections of a service and its data.
SCENE2D_API::fwServices::IService::KeyConnectionsMap getAutoConnections() const override
Returns proposals to connect service slots to associated object signals, this method is used for obj/...
SCENE2D_API void processInteraction(::fwRenderQt::data::Event &_event) override
IAdaptor implementation to display one slice of an image.
Class allowing to block a Connection.
FWRENDERQT_API std::shared_ptr< ::fwRenderQt::SRender > getScene2DRender() const
Get the render that manages the IAdaptor.
virtual void swapping()
Swap the service from associated object to another object.
SCENE2D_API void starting() override
Initialize the service activity.
This bundles contains data and services used to display a 2D Qt scene.
virtual SCENE2D_API void updateTFPoints() override
Slot: updates the displayed image.
#define SLM_FATAL(message)
SCENE2D_API void updating() override
Perform some computations according to object (this service is attached to) attribute values and its ...
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_VISIBILITY_MODIFIED_SIG
Type of signal when image's buffer is added.
SCENE2D_API void configuring() override
Configure the service before starting. Apply the configuration to service.
#define SLM_ASSERT(message, cond)
work like 'assert' from 'cassert', with in addition a message logged by spylog (with FATAL loglevel) ...
::fwRenderQt::data::Axis::sptr m_yAxis
The y Axis.
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_BUFFER_MODIFIED_SIG
Type of signal when image's buffer is added.
FWRENDERQT_API void configureParams()
Parse the xml configuration for Axis, z value and opacity.
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_MODIFIED_SIG
Key in m_signals map of signal m_sigModified.
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_WINDOWING_MODIFIED_SIG
Type of signal when points are modified.
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_SLICE_TYPE_MODIFIED_SIG
Type of signal when image's buffer is added.
virtual SCENE2D_API void updateTFWindowing(double window, double level) override
Slot: updates the displayed image.
This class manage events on the scene 2D (mouse event, keyboard event , ...).
static FWSERVICES_APIconst::fwCom::Slots::SlotKeyType s_UPDATE_SLOT
Slot to call start method.
FWSERVICES_API ConfigType getConfigTree() const
Return the configuration, in an boost property tree.