Medical Imaging Interaction Toolkit  2018.4.99-389bf124
Medical Imaging Interaction Toolkit
QmitkTransferFunctionGeneratorWidget.cpp
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
14 
15 #include <QFileDialog>
16 #include <QFontMetrics>
18 #include <mitkRenderingManager.h>
21 #include <mitkUnstructuredGrid.h>
22 
24 
25 #include <vtkUnstructuredGrid.h>
26 
28  : QWidget(parent, f), deltaScale(1.0), deltaMax(1024), deltaMin(1)
29 {
30  histoGramm = nullptr;
31 
32  this->setupUi(this);
33 
34  // LevelWindow Tab
35  {
36  connect(m_CrossLevelWindow, SIGNAL(SignalDeltaMove(int, int)), this, SLOT(OnDeltaLevelWindow(int, int)));
37  }
38 
39  // Threshold Tab
40  {
41  connect(m_CrossThreshold, SIGNAL(SignalDeltaMove(int, int)), this, SLOT(OnDeltaThreshold(int, int)));
42  thDelta = 100;
43  }
44 
45  // Presets Tab
46  {
47  m_TransferFunctionComboBox->setVisible(false);
48 
49  connect(m_TransferFunctionComboBox, SIGNAL(activated(int)), this, SIGNAL(SignalTransferFunctionModeChanged(int)));
50  connect(m_TransferFunctionComboBox, SIGNAL(activated(int)), this, SLOT(OnPreset(int)));
51 
52  connect(m_SavePreset, SIGNAL(clicked()), this, SLOT(OnSavePreset()));
53 
54  connect(m_LoadPreset, SIGNAL(clicked()), this, SLOT(OnLoadPreset()));
55  }
56 
57  presetFileName = ".";
58 }
59 
61 {
62  m_TransferFunctionComboBox->setVisible(true);
63 
64  m_TransferFunctionComboBox->addItem(presetName);
65  return m_TransferFunctionComboBox->count() - 1;
66 }
67 
69 {
70  m_PresetTab->setEnabled(enable);
71 }
72 
74 {
75  m_ThresholdTab->setEnabled(enable);
76 }
77 
79 {
80  m_BellTab->setEnabled(enable);
81 }
82 
84 {
85  if (tfpToChange.IsNull())
86  return;
87 
89 
90  presetFileName = QFileDialog::getSaveFileName(
91  this, "Choose a filename to save the transfer function", presetFileName, "Transferfunction (*.xml)");
92 
93  if (!presetFileName.endsWith(".xml"))
94  presetFileName.append(".xml");
95 
96  MITK_INFO << "Saving Transferfunction under path: " << presetFileName.toStdString();
97 
99  {
100  QFontMetrics metrics(m_InfoPreset->font());
101  QString text = metrics.elidedText(presetFileName, Qt::ElideMiddle, m_InfoPreset->width());
102  m_InfoPreset->setText(QString("saved ") + text);
103  }
104  else
105  {
106  m_InfoPreset->setText(QString("saving failed"));
107  }
108 }
109 
111 {
112  if (tfpToChange.IsNull())
113  return;
114 
115  presetFileName = QFileDialog::getOpenFileName(
116  this, "Choose a file to open the transfer function from", presetFileName, "Transferfunction (*.xml)");
117 
118  MITK_INFO << "Loading Transferfunction from path: " << presetFileName.toStdString();
119 
122 
123  if (tf.IsNotNull())
124  {
125  tfpToChange->SetValue(tf);
126 
127  QFontMetrics metrics(m_InfoPreset->font());
128  QString text = metrics.elidedText(presetFileName, Qt::ElideMiddle, m_InfoPreset->width());
129  m_InfoPreset->setText(QString("loaded ") + text);
130 
132  emit SignalUpdateCanvas();
133  }
134 }
135 
137 {
138  // first item is only information
139  if (--mode == -1)
140  return;
141 
142  m_InfoPreset->setText(QString("selected ") + m_TransferFunctionComboBox->currentText());
143 
144  // revert to first item
145  m_TransferFunctionComboBox->setCurrentIndex(0);
146 }
147 
148 static double transformationGlocke(double x)
149 {
150  double z = 0.1;
151 
152  double a = 2 - 2 * z;
153 
154  double b = 2 * z - 1;
155 
156  x = a * x + b;
157 
158  return x;
159 }
160 
161 static double stepFunctionGlocke(double x)
162 {
163  x = 1 - (2 * x - 1.0); // map [0.5;1] to [0,1]
164  x = x * (3 * x - 2 * x * x); // apply smoothing function
165 
166  x = x * x;
167 
168  return x;
169 }
170 
172 {
173  return deltaScale * (double)d;
174 }
175 
177 {
178  if (tfpToChange.IsNull())
179  return;
180 
181  thPos += ScaleDelta(dx);
182  thDelta -= ScaleDelta(dy);
183 
184  if (thDelta < deltaMin)
185  thDelta = deltaMin;
186 
187  if (thDelta > deltaMax)
188  thDelta = deltaMax;
189 
190  if (thPos < histoMinimum)
192 
193  if (thPos > histoMaximum)
195 
196  std::stringstream ss;
197 
198  ss << "Click on the cross and move the mouse"
199  << "\n"
200  << "\n"
201  << "center at " << thPos << "\n"
202  << "width " << thDelta * 2;
203 
204  m_InfoLevelWindow->setText(QString(ss.str().c_str()));
205 
207 
208  // grayvalue->opacity
209  {
210  vtkPiecewiseFunction *f = tf->GetScalarOpacityFunction();
211  f->RemoveAllPoints();
212 
213  for (int r = 0; r <= 6; r++)
214  {
215  double relPos = (r / 6.0) * 0.5 + 0.5;
216  f->AddPoint(thPos + thDelta * (-transformationGlocke(relPos)), stepFunctionGlocke(relPos));
217  f->AddPoint(thPos + thDelta * (transformationGlocke(relPos)), stepFunctionGlocke(relPos));
218  }
219 
220  f->Modified();
221  }
222 
223  // gradient at grayvalue->opacity
224  {
225  vtkPiecewiseFunction *f = tf->GetGradientOpacityFunction();
226  f->RemoveAllPoints();
227 
228  f->AddPoint(0, 1.0);
229  f->Modified();
230  }
231 
232  tf->Modified();
233 
235  emit SignalUpdateCanvas();
236 }
237 
238 static double stepFunctionThreshold(double x)
239 {
240  x = 0.5 * x + 0.5; // map [-1;1] to [0,1]
241  x = x * (3 * x - 2 * x * x); // apply smoothing function
242 
243  x = x * x;
244 
245  return x;
246 }
247 
249 {
250  if (tfpToChange.IsNull())
251  return;
252 
253  thPos += ScaleDelta(dx);
254  thDelta += ScaleDelta(dy);
255 
256  if (thDelta < deltaMin)
257  thDelta = deltaMin;
258 
259  if (thDelta > deltaMax)
260  thDelta = deltaMax;
261 
262  if (thPos < histoMinimum)
264 
265  if (thPos > histoMaximum)
267 
268  std::stringstream ss;
269 
270  ss << "Click on the cross and move the mouse"
271  << "\n"
272  << "\n"
273  << "threshold at " << thPos << "\n"
274  << "width " << thDelta * 2;
275 
276  m_InfoThreshold->setText(QString(ss.str().c_str()));
277 
279 
280  // grayvalue->opacity
281  {
282  vtkPiecewiseFunction *f = tf->GetScalarOpacityFunction();
283  f->RemoveAllPoints();
284 
285  for (int r = 1; r <= 4; r++)
286  {
287  double relPos = r / 4.0;
288  f->AddPoint(thPos + thDelta * (-relPos), stepFunctionThreshold(-relPos));
289  f->AddPoint(thPos + thDelta * (relPos), stepFunctionThreshold(relPos));
290  }
291  f->Modified();
292  }
293 
294  // gradient at grayvalue->opacity
295  {
296  vtkPiecewiseFunction *f = tf->GetGradientOpacityFunction();
297  f->RemoveAllPoints();
298  f->AddPoint(0, 1.0);
299  f->Modified();
300  }
301 
302  tf->Modified();
304  emit SignalUpdateCanvas();
305 }
306 
308 {
309 }
310 
312 {
313  histoGramm = nullptr;
314 
315  if (node)
316  {
317  tfpToChange = dynamic_cast<mitk::TransferFunctionProperty *>(node->GetProperty("TransferFunction"));
318 
319  if (!tfpToChange)
320  node->SetProperty("TransferFunction", tfpToChange = mitk::TransferFunctionProperty::New());
321 
323 
324  if (mitk::Image *image = dynamic_cast<mitk::Image *>(node->GetData()))
325  {
326  mitk::ImageStatisticsHolder *statistics = image->GetStatistics();
327  histoMinimum = statistics->GetScalarValueMin();
328  histoMaximum = statistics->GetScalarValueMax();
329  }
330  else if (mitk::UnstructuredGrid *grid = dynamic_cast<mitk::UnstructuredGrid *>(node->GetData()))
331  {
332  double *range = grid->GetVtkUnstructuredGrid()->GetScalarRange();
333  histoMinimum = range[0];
334  histoMaximum = range[1];
335  double histoRange = histoMaximum - histoMinimum;
336  deltaMax = histoRange / 4.0;
337  deltaMin = histoRange / 400.0;
338  deltaScale = histoRange / 1024.0;
339  }
340  else
341  {
342  MITK_WARN << "QmitkTransferFunctonGeneratorWidget does not support " << node->GetData()->GetNameOfClass()
343  << " instances";
344  }
345 
346  thPos = (histoMinimum + histoMaximum) / 2.0;
347  }
348  else
349  {
350  tfpToChange = nullptr;
351  m_InfoPreset->setText(QString(""));
352  }
353 }
mitk::BaseProperty * GetProperty(const char *propertyKey, const mitk::BaseRenderer *renderer=nullptr, bool fallBackOnDataProperties=true) const
Get the property (instance of BaseProperty) with key propertyKey from the PropertyList of the rendere...
The TransferFunctionProperty class Property class for the mitk::TransferFunction. ...
static bool SerializeTransferFunction(const char *filename, TransferFunction::Pointer tf)
static double stepFunctionGlocke(double x)
#define MITK_INFO
Definition: mitkLogMacros.h:18
static double stepFunctionThreshold(double x)
static TransferFunction::Pointer DeserializeTransferFunction(const char *filePath)
virtual ScalarType GetScalarValueMin(int t=0, unsigned int component=0)
Get the minimum for scalar images. Recomputation performed only when necessary.
void SetProperty(const std::string &propertyKey, BaseProperty *property, const std::string &contextName="", bool fallBackOnDefaultContext=false) override
Add new or change existent property.
BaseData * GetData() const
Get the data object (instance of BaseData, e.g., an Image) managed by this DataNode.
#define MITK_WARN
Definition: mitkLogMacros.h:19
static RenderingManager * GetInstance()
virtual ScalarType GetScalarValueMax(int t=0, unsigned int component=0)
Get the maximum for scalar images. Recomputation performed only when necessary.
mitk::TransferFunctionProperty::Pointer tfpToChange
Image class for storing images.
Definition: mitkImage.h:72
mitk::Image::Pointer image
QmitkTransferFunctionGeneratorWidget(QWidget *parent=nullptr, Qt::WindowFlags f=nullptr)
Class holding the statistics informations about a single mitk::Image.
Class for storing unstructured grids (vtkUnstructuredGrid)
void RequestUpdateAll(RequestType type=REQUEST_UPDATE_ALL)
Class for nodes of the DataTree.
Definition: mitkDataNode.h:57
static double transformationGlocke(double x)