7 #include "uiImageQt/WindowLevel.hpp" 9 #include <fwCom/Signal.hpp> 10 #include <fwCom/Signal.hxx> 11 #include <fwCom/Signals.hpp> 13 #include <fwCore/base.hpp> 15 #include <fwData/Composite.hpp> 16 #include <fwData/Image.hpp> 17 #include <fwData/TransferFunction.hpp> 19 #include <fwDataTools/fieldHelper/Image.hpp> 20 #include <fwDataTools/fieldHelper/MedicalImageHelpers.hpp> 21 #include <fwDataTools/helper/Composite.hpp> 23 #include <fwGuiQt/container/QtContainer.hpp> 24 #include <fwGuiQt/widget/QRangeSlider.hpp> 26 #include <fwRuntime/operations.hpp> 28 #include <fwServices/macros.hpp> 30 #include <boost/math/special_functions/fpclassify.hpp> 32 #include <QApplication> 34 #include <QDoubleValidator> 35 #include <QGridLayout> 39 #include <QSignalMapper> 40 #include <QToolButton> 50 static const ::fwServices::IService::KeyType s_IMAGE_INOUT =
"image";
51 static const ::fwServices::IService::KeyType s_TF_INOUT =
"tf";
56 m_widgetDynamicRangeMin(-1024),
57 m_widgetDynamicRangeWidth(4000),
58 m_autoWindowing(false),
59 m_enableSquareTF(true)
74 ::fwData::Image::sptr image = this->getInOut< ::fwData::Image >(s_IMAGE_INOUT);
75 SLM_ASSERT(
"inout '" + s_IMAGE_INOUT +
"' is not defined.", image);
78 ::fwGuiQt::container::QtContainer::sptr qtContainer = ::fwGuiQt::container::QtContainer::dynamicCast(
79 this->getContainer() );
81 QGridLayout* layout =
new QGridLayout();
83 m_valueTextMin =
new QLineEdit();
84 QDoubleValidator* minValidator =
new QDoubleValidator(m_valueTextMin);
85 m_valueTextMin->setValidator(minValidator);
87 m_valueTextMax =
new QLineEdit();
88 QDoubleValidator* maxValidator =
new QDoubleValidator(m_valueTextMax);
89 m_valueTextMax->setValidator(maxValidator);
91 m_rangeSlider = new ::fwGuiQt::widget::QRangeSlider();
93 m_toggleTFButton =
new QToolButton();
97 ico.addPixmap(QPixmap(QString::fromStdString(squareIcon)), QIcon::Normal, QIcon::On);
98 ico.addPixmap(QPixmap(QString::fromStdString(rampIcon)), QIcon::Normal, QIcon::Off);
99 m_toggleTFButton->setIcon(ico);
100 m_toggleTFButton->setCheckable(
true);
101 m_toggleTFButton->setVisible(m_enableSquareTF);
103 m_toggleAutoButton =
new QToolButton();
106 icon.addFile(QString::fromStdString(windo), QSize(), QIcon::Normal, QIcon::On);
108 icon.addFile(QString::fromStdString(nowindo), QSize(), QIcon::Normal, QIcon::Off);
109 m_toggleAutoButton->setIcon(icon);
110 m_toggleAutoButton->setToolTip(
"Automatic Windowing");
111 m_toggleAutoButton->setCheckable(
true);
112 m_toggleAutoButton->setChecked(m_autoWindowing);
114 m_dynamicRangeSelection =
new QToolButton();
115 m_dynamicRangeSelection->setPopupMode(QToolButton::InstantPopup);
117 m_dynamicRangeMenu =
new QMenu(m_dynamicRangeSelection);
118 QAction* action1 = m_dynamicRangeMenu->addAction(
"-1024; 1023" );
119 QAction* action2 = m_dynamicRangeMenu->addAction(
"-100; 300" );
120 QAction* action3 = m_dynamicRangeMenu->addAction(
"Fit W/L" );
121 QAction* action4 = m_dynamicRangeMenu->addAction(
"Fit Data" );
123 m_dynamicRangeSelection->setMenu(m_dynamicRangeMenu);
125 action1->setData(QVariant(1));
126 action2->setData(QVariant(2));
127 action3->setData(QVariant(3));
128 action4->setData(QVariant(4));
131 layout->addWidget( m_rangeSlider, 0, 0, 1, -1 );
132 layout->addWidget( m_valueTextMin, 1, 0 );
133 layout->addWidget( m_toggleTFButton, 1, 1 );
134 layout->addWidget( m_toggleAutoButton, 1, 2 );
135 layout->addWidget( m_dynamicRangeSelection, 1, 3 );
136 layout->addWidget( m_valueTextMax, 1, 4 );
138 qtContainer->setLayout( layout );
140 m_dynamicRangeSignalMapper =
new QSignalMapper(
this);
142 QObject::connect(m_valueTextMin, SIGNAL(editingFinished()),
this, SLOT(onTextEditingFinished()));
143 QObject::connect(m_valueTextMax, SIGNAL(editingFinished()),
this, SLOT(onTextEditingFinished()));
144 QObject::connect(m_rangeSlider, SIGNAL(sliderRangeEdited(
double,
double)),
this,
145 SLOT(onWindowLevelWidgetChanged(
double,
double)));
146 QObject::connect(m_toggleTFButton, SIGNAL(toggled(
bool)),
this, SLOT(onToggleTF(
bool)));
147 QObject::connect(m_toggleAutoButton, SIGNAL(toggled(
bool)),
this, SLOT(onToggleAutoWL(
bool)));
148 QObject::connect(m_dynamicRangeSelection, SIGNAL(triggered(QAction*)),
this,
149 SLOT(onDynamicRangeSelectionChanged(QAction*)));
151 ::fwData::TransferFunction::sptr tf = this->getInOut < ::fwData::TransferFunction >(s_TF_INOUT);
162 QObject::disconnect(m_dynamicRangeSelection, SIGNAL(triggered(QAction*)),
this,
163 SLOT(onDynamicRangeSelectionChanged(QAction*)));
164 QObject::disconnect(m_toggleTFButton, SIGNAL(toggled(
bool)),
this, SLOT(onToggleTF(
bool)));
165 QObject::disconnect(m_rangeSlider, SIGNAL(sliderRangeEdited(
double,
double)),
this,
166 SLOT(onWindowLevelWidgetChanged(
double,
double)));
167 QObject::disconnect(m_valueTextMin, SIGNAL(editingFinished()),
this,
168 SLOT(onTextEditingFinished()));
169 QObject::disconnect(m_valueTextMax, SIGNAL(editingFinished()),
this,
170 SLOT(onTextEditingFinished()));
183 if (srvConfig.count(
"config.<xmlattr>"))
185 const ConfigType config = srvConfig.get_child(
"config.<xmlattr>");
187 const std::string autoWindowing = config.get(
"autoWindowing",
"no");
188 SLM_ASSERT(
"Bad value for 'autoWindowing' attribute. It must be 'yes' or 'no'!",
189 autoWindowing ==
"yes" || autoWindowing ==
"no");
190 m_autoWindowing = (autoWindowing ==
"yes");
192 const std::string enableSquareTF = config.get(
"enableSquareTF",
"yes");
193 SLM_ASSERT(
"Bad value for 'enableSquareTF' attribute. It must be 'yes' or 'no'!",
194 enableSquareTF ==
"yes" || enableSquareTF ==
"no");
195 m_enableSquareTF = (enableSquareTF ==
"yes");
203 ::fwData::Image::sptr image = this->getInOut< ::fwData::Image >(s_IMAGE_INOUT);
204 SLM_ASSERT(
"inout '" + s_IMAGE_INOUT +
"' is not defined.", image);
217 this->updateImageWindowLevel(min, max);
221 SLM_ASSERT(
"TransferFunction null pointer", pTF);
222 ::fwData::TransferFunction::TFValuePairType minMax = pTF->getWLMinMax();
223 this->onImageWindowLevelChanged( minMax.first, minMax.second );
231 if (key == s_TF_INOUT)
233 ::fwData::TransferFunction::sptr tf = this->getInOut< ::fwData::TransferFunction >(s_TF_INOUT);
235 ::fwData::Image::sptr image = this->getInOut< ::fwData::Image >(s_IMAGE_INOUT);
256 SLM_ASSERT(
"TransferFunction null pointer", pTF);
257 ::fwData::TransferFunction::TFValuePairType minMax = pTF->getWLMinMax();
258 this->onImageWindowLevelChanged( minMax.first, minMax.second );
265 _sstream <<
"Window level editor";
270 WindowLevel::WindowLevelMinMaxType WindowLevel::getImageWindowMinMax()
273 SLM_ASSERT(
"TransferFunction null pointer", pTF);
275 return pTF->getWLMinMax();
279 void WindowLevel::updateWidgetMinMax(
double _imageMin,
double _imageMax)
281 double rangeMin = this->fromWindowLevel(_imageMin);
282 double rangeMax = this->fromWindowLevel(_imageMax);
284 m_rangeSlider->setPos(rangeMin, rangeMax);
289 double WindowLevel::fromWindowLevel(
double val)
291 double valMin = m_widgetDynamicRangeMin;
292 double valMax = valMin + m_widgetDynamicRangeWidth;
294 valMin = std::min(val, valMin);
295 valMax = std::max(val, valMax);
297 this->setWidgetDynamicRange(valMin, valMax);
299 double res = (val - m_widgetDynamicRangeMin) / m_widgetDynamicRangeWidth;
305 double WindowLevel::toWindowLevel(
double _val)
307 return m_widgetDynamicRangeMin + m_widgetDynamicRangeWidth * _val;
312 void WindowLevel::updateImageWindowLevel(
double _imageMin,
double _imageMax)
316 this->
getTransferFunction()->setWLMinMax( ::fwData::TransferFunction::TFValuePairType(_imageMin,
322 sig->asyncEmit( tf->getWindow(), tf->getLevel());
328 void WindowLevel::onWindowLevelWidgetChanged(
double _min,
double _max)
330 double imageMin = this->toWindowLevel(_min);
331 double imageMax = this->toWindowLevel(_max);
332 this->updateImageWindowLevel(imageMin, imageMax);
333 this->updateTextWindowLevel(imageMin, imageMax);
338 void WindowLevel::onDynamicRangeSelectionChanged(QAction* action)
340 WindowLevelMinMaxType wl = this->getImageWindowMinMax();
341 double min = m_widgetDynamicRangeMin;
342 double max = m_widgetDynamicRangeWidth + min;
343 int index = action->data().toInt();
345 ::fwData::Image::sptr image = this->getInOut< ::fwData::Image >(s_IMAGE_INOUT);
346 SLM_ASSERT(
"inout '" + s_IMAGE_INOUT +
"' is not defined.", image);
361 min = std::min(wl.first, wl.second);
362 max = std::max(wl.first, wl.second);
370 SLM_ASSERT(
"Unknown range selector index", 0);
373 this->setWidgetDynamicRange(min, max);
374 this->updateWidgetMinMax(wl.first, wl.second);
379 void WindowLevel::onImageWindowLevelChanged(
double _imageMin,
double _imageMax)
381 this->updateWidgetMinMax( _imageMin, _imageMax );
382 this->updateTextWindowLevel( _imageMin, _imageMax );
387 void WindowLevel::updateTextWindowLevel(
double _imageMin,
double _imageMax)
389 m_valueTextMin->setText(QString(
"%1").arg(_imageMin));
390 m_valueTextMax->setText(QString(
"%1").arg(_imageMax));
395 void WindowLevel::onToggleTF(
bool squareTF)
398 ::fwData::TransferFunction::sptr newTF;
402 newTF = ::fwData::TransferFunction::New();
404 newTF->setName(
"SquareTF");
405 newTF->addTFColor(0.0, color);
406 newTF->addTFColor(1.0, color);
407 newTF->setIsClamped(
true);
413 newTF = m_previousTF;
417 newTF = ::fwData::TransferFunction::createDefaultTF();
421 newTF->setWindow( currentTF->getWindow() );
422 newTF->setLevel( currentTF->getLevel() );
426 currentTF->deepCopy(newTF);
439 void WindowLevel::onToggleAutoWL(
bool autoWL)
441 m_autoWindowing = autoWL;
445 ::fwData::Image::sptr image = this->getInOut< ::fwData::Image >(s_IMAGE_INOUT);
446 SLM_ASSERT(
"inout '" + s_IMAGE_INOUT +
"' is not defined.", image);
449 this->updateImageWindowLevel(min, max);
450 this->onImageWindowLevelChanged(min, max);
456 void WindowLevel::onTextEditingFinished()
459 if(this->getWidgetDoubleValue(m_valueTextMin, min) && this->getWidgetDoubleValue(m_valueTextMax, max))
461 this->updateWidgetMinMax( min, max );
462 this->updateImageWindowLevel(min, max);
468 bool WindowLevel::getWidgetDoubleValue(QLineEdit* widget,
double& val)
471 val = widget->text().toDouble(&ok);
476 palette.setBrush(QPalette::Base, QBrush(Qt::red));
480 palette.setBrush(QPalette::Base, QApplication::palette().brush(QPalette::Base));
482 widget->setPalette(palette);
488 void WindowLevel::setWidgetDynamicRange(
double min,
double max)
490 if(fabs(max - min) < 1.e-05)
494 m_widgetDynamicRangeMin = min;
495 m_widgetDynamicRangeWidth = max - min;
497 m_dynamicRangeSelection->setText(QString(
"%1, %2 ").arg(min).arg(max));
This class is a helper to define the connections of a service and its data.
virtual UIIMAGEQT_API void updateTFPoints() override
Slot: Updates the slider position.
FWGUI_API void setEnabled(bool isEnabled)
SLOT: enable/disable the container.
virtual void configuring() override
Parse the xml configuration.
virtual void updating() override
Update editor information from the image.
Class allowing to block a Connection.
virtual UIIMAGEQT_API ~WindowLevel() noexcept
Destructor. Do nothing.
Defines the service interface managing the editor service for object.
FWGUI_API void destroy()
Stops sub-views and toobar services. Destroys view, sub-views and toolbar containers.
virtual UIIMAGEQT_API void info(std::ostream &_sstream) override
Overrides.
virtual void starting() override
Install the layout.
virtual void swapping()
Swap the service from associated object to another object.
The namespace uiImageQt contains several editors on image written with Qt. This namespace is included...
virtual void stopping() override
Destroy the layout.
#define SLM_ASSERT(message, cond)
work like 'assert' from 'cassert', with in addition a message logged by spylog (with FATAL loglevel) ...
static FWDATA_API::fwData::Object::sptr copy(const ::fwData::Object::csptr &source)
return a copy of the source. if source is a null pointer, return a null pointer.
FWGUI_API void create()
Creates view, sub-views and toolbar containers. Manages sub-views and toobar services.
WindowLevel service allows to change the min / max value of windowing.
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.
FWRUNTIME_API::boost::filesystem::path getBundleResourceFilePath(const std::string &bundleIdentifier, const ::boost::filesystem::path &path) noexcept
Retrieve a filesystem valid path for a path relative to the bundle having the specified identifier...
UIIMAGEQT_API WindowLevel() noexcept
Constructor. Do nothing.
This class defines an image.
Macro for deep and shallow copies.
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_WINDOWING_MODIFIED_SIG
Type of signal when points are modified.
virtual UIIMAGEQT_API KeyConnectionsMap getAutoConnections() const override
Returns proposals to connect service slots to associated object signals, this method is used for obj/...
static FWSERVICES_APIconst::fwCom::Slots::SlotKeyType s_UPDATE_SLOT
Slot to call start method.
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_POINTS_MODIFIED_SIG
Type of signal when points are modified.
FWGUI_API void initialize()
Initialize managers.
virtual UIIMAGEQT_API void updateTFWindowing(double window, double level) override
Slot: Updates the slider position.
FWSERVICES_API ConfigType getConfigTree() const
Return the configuration, in an boost property tree.