Medical Imaging Interaction Toolkit  2016.11.0
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,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
16 
18 
19 #include <QFileDialog>
20 #include <QFontMetrics>
22 #include <mitkRenderingManager.h>
25 #include <mitkUnstructuredGrid.h>
26 
28 
29 #include <vtkUnstructuredGrid.h>
30 
32  : QWidget(parent, f), deltaScale(1.0), deltaMax(1024), deltaMin(1)
33 {
34  histoGramm = nullptr;
35 
36  this->setupUi(this);
37 
38  // LevelWindow Tab
39  {
40  connect(m_CrossLevelWindow, SIGNAL(SignalDeltaMove(int, int)), this, SLOT(OnDeltaLevelWindow(int, int)));
41  }
42 
43  // Threshold Tab
44  {
45  connect(m_CrossThreshold, SIGNAL(SignalDeltaMove(int, int)), this, SLOT(OnDeltaThreshold(int, int)));
46  thDelta = 100;
47  }
48 
49  // Presets Tab
50  {
51  m_TransferFunctionComboBox->setVisible(false);
52 
53  connect(m_TransferFunctionComboBox, SIGNAL(activated(int)), this, SIGNAL(SignalTransferFunctionModeChanged(int)));
54  connect(m_TransferFunctionComboBox, SIGNAL(activated(int)), this, SLOT(OnPreset(int)));
55 
56  connect(m_SavePreset, SIGNAL(clicked()), this, SLOT(OnSavePreset()));
57 
58  connect(m_LoadPreset, SIGNAL(clicked()), this, SLOT(OnLoadPreset()));
59  }
60 
61  presetFileName = ".";
62 }
63 
65 {
66  m_TransferFunctionComboBox->setVisible(true);
67 
68  m_TransferFunctionComboBox->addItem(presetName);
69  return m_TransferFunctionComboBox->count() - 1;
70 }
71 
73 {
74  m_PresetTab->setEnabled(enable);
75 }
76 
78 {
79  m_ThresholdTab->setEnabled(enable);
80 }
81 
83 {
84  m_BellTab->setEnabled(enable);
85 }
86 
88 {
89  if (tfpToChange.IsNull())
90  return;
91 
93 
94  presetFileName = QFileDialog::getSaveFileName(
95  this, "Choose a filename to save the transfer function", presetFileName, "Transferfunction (*.xml)");
96 
97  if (!presetFileName.endsWith(".xml"))
98  presetFileName.append(".xml");
99 
100  MITK_INFO << "Saving Transferfunction under path: " << presetFileName.toStdString();
101 
103  {
104  QFontMetrics metrics(m_InfoPreset->font());
105  QString text = metrics.elidedText(presetFileName, Qt::ElideMiddle, m_InfoPreset->width());
106  m_InfoPreset->setText(QString("saved ") + text);
107  }
108  else
109  {
110  m_InfoPreset->setText(QString("saving failed"));
111  }
112 }
113 
115 {
116  if (tfpToChange.IsNull())
117  return;
118 
119  presetFileName = QFileDialog::getOpenFileName(
120  this, "Choose a file to open the transfer function from", presetFileName, "Transferfunction (*.xml)");
121 
122  MITK_INFO << "Loading Transferfunction from path: " << presetFileName.toStdString();
123 
126 
127  if (tf.IsNotNull())
128  {
129  tfpToChange->SetValue(tf);
130 
131  QFontMetrics metrics(m_InfoPreset->font());
132  QString text = metrics.elidedText(presetFileName, Qt::ElideMiddle, m_InfoPreset->width());
133  m_InfoPreset->setText(QString("loaded ") + text);
134 
136  emit SignalUpdateCanvas();
137  }
138 }
139 
141 {
142  // first item is only information
143  if (--mode == -1)
144  return;
145 
146  m_InfoPreset->setText(QString("selected ") + m_TransferFunctionComboBox->currentText());
147 
148  // revert to first item
149  m_TransferFunctionComboBox->setCurrentIndex(0);
150 }
151 
152 static double transformationGlocke(double x)
153 {
154  double z = 0.1;
155 
156  double a = 2 - 2 * z;
157 
158  double b = 2 * z - 1;
159 
160  x = a * x + b;
161 
162  return x;
163 }
164 
165 static double stepFunctionGlocke(double x)
166 {
167  x = 1 - (2 * x - 1.0); // map [0.5;1] to [0,1]
168  x = x * (3 * x - 2 * x * x); // apply smoothing function
169 
170  x = x * x;
171 
172  return x;
173 }
174 
176 {
177  return deltaScale * (double)d;
178 }
179 
181 {
182  if (tfpToChange.IsNull())
183  return;
184 
185  thPos += ScaleDelta(dx);
186  thDelta -= ScaleDelta(dy);
187 
188  if (thDelta < deltaMin)
189  thDelta = deltaMin;
190 
191  if (thDelta > deltaMax)
192  thDelta = deltaMax;
193 
194  if (thPos < histoMinimum)
196 
197  if (thPos > histoMaximum)
199 
200  std::stringstream ss;
201 
202  ss << "Click on the cross and move the mouse"
203  << "\n"
204  << "\n"
205  << "center at " << thPos << "\n"
206  << "width " << thDelta * 2;
207 
208  m_InfoLevelWindow->setText(QString(ss.str().c_str()));
209 
211 
212  // grayvalue->opacity
213  {
214  vtkPiecewiseFunction *f = tf->GetScalarOpacityFunction();
215  f->RemoveAllPoints();
216 
217  for (int r = 0; r <= 6; r++)
218  {
219  double relPos = (r / 6.0) * 0.5 + 0.5;
220  f->AddPoint(thPos + thDelta * (-transformationGlocke(relPos)), stepFunctionGlocke(relPos));
221  f->AddPoint(thPos + thDelta * (transformationGlocke(relPos)), stepFunctionGlocke(relPos));
222  }
223 
224  f->Modified();
225  }
226 
227  // gradient at grayvalue->opacity
228  {
229  vtkPiecewiseFunction *f = tf->GetGradientOpacityFunction();
230  f->RemoveAllPoints();
231 
232  f->AddPoint(0, 1.0);
233  f->Modified();
234  }
235 
236  tf->Modified();
237 
239  emit SignalUpdateCanvas();
240 }
241 
242 static double stepFunctionThreshold(double x)
243 {
244  x = 0.5 * x + 0.5; // map [-1;1] to [0,1]
245  x = x * (3 * x - 2 * x * x); // apply smoothing function
246 
247  x = x * x;
248 
249  return x;
250 }
251 
253 {
254  if (tfpToChange.IsNull())
255  return;
256 
257  thPos += ScaleDelta(dx);
258  thDelta += ScaleDelta(dy);
259 
260  if (thDelta < deltaMin)
261  thDelta = deltaMin;
262 
263  if (thDelta > deltaMax)
264  thDelta = deltaMax;
265 
266  if (thPos < histoMinimum)
268 
269  if (thPos > histoMaximum)
271 
272  std::stringstream ss;
273 
274  ss << "Click on the cross and move the mouse"
275  << "\n"
276  << "\n"
277  << "threshold at " << thPos << "\n"
278  << "width " << thDelta * 2;
279 
280  m_InfoThreshold->setText(QString(ss.str().c_str()));
281 
283 
284  // grayvalue->opacity
285  {
286  vtkPiecewiseFunction *f = tf->GetScalarOpacityFunction();
287  f->RemoveAllPoints();
288 
289  for (int r = 1; r <= 4; r++)
290  {
291  double relPos = r / 4.0;
292  f->AddPoint(thPos + thDelta * (-relPos), stepFunctionThreshold(-relPos));
293  f->AddPoint(thPos + thDelta * (relPos), stepFunctionThreshold(relPos));
294  }
295  f->Modified();
296  }
297 
298  // gradient at grayvalue->opacity
299  {
300  vtkPiecewiseFunction *f = tf->GetGradientOpacityFunction();
301  f->RemoveAllPoints();
302  f->AddPoint(0, 1.0);
303  f->Modified();
304  }
305 
306  tf->Modified();
308  emit SignalUpdateCanvas();
309 }
310 
312 {
313 }
314 
316 {
317  histoGramm = nullptr;
318 
319  if (node)
320  {
321  tfpToChange = dynamic_cast<mitk::TransferFunctionProperty *>(node->GetProperty("TransferFunction"));
322 
323  if (!tfpToChange)
324  node->SetProperty("TransferFunction", tfpToChange = mitk::TransferFunctionProperty::New());
325 
327 
328  if (mitk::Image *image = dynamic_cast<mitk::Image *>(node->GetData()))
329  {
330  mitk::ImageStatisticsHolder *statistics = image->GetStatistics();
331  histoMinimum = statistics->GetScalarValueMin();
332  histoMaximum = statistics->GetScalarValueMax();
333  }
334  else if (mitk::UnstructuredGrid *grid = dynamic_cast<mitk::UnstructuredGrid *>(node->GetData()))
335  {
336  double *range = grid->GetVtkUnstructuredGrid()->GetScalarRange();
337  histoMinimum = range[0];
338  histoMaximum = range[1];
339  double histoRange = histoMaximum - histoMinimum;
340  deltaMax = histoRange / 4.0;
341  deltaMin = histoRange / 400.0;
342  deltaScale = histoRange / 1024.0;
343  }
344  else
345  {
346  MITK_WARN << "QmitkTransferFunctonGeneratorWidget does not support " << node->GetData()->GetNameOfClass()
347  << " instances";
348  }
349 
350  thPos = (histoMinimum + histoMaximum) / 2.0;
351  }
352  else
353  {
354  tfpToChange = nullptr;
355  m_InfoPreset->setText(QString(""));
356  }
357 }
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:22
static double stepFunctionThreshold(double x)
static TransferFunction::Pointer DeserializeTransferFunction(const char *filePath)
BaseData * GetData() const
Get the data object (instance of BaseData, e.g., an Image) managed by this DataNode.
mitk::BaseProperty * GetProperty(const char *propertyKey, const mitk::BaseRenderer *renderer=nullptr) const
Get the property (instance of BaseProperty) with key propertyKey from the PropertyList of the rendere...
virtual ScalarType GetScalarValueMin(int t=0, unsigned int component=0)
Get the minimum for scalar images. Recomputation performed only when necessary.
#define MITK_WARN
Definition: mitkLogMacros.h:23
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:76
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 SetProperty(const char *propertyKey, BaseProperty *property, const mitk::BaseRenderer *renderer=nullptr)
Set the property (instance of BaseProperty) with key propertyKey in the PropertyList of the renderer ...
void RequestUpdateAll(RequestType type=REQUEST_UPDATE_ALL)
Class for nodes of the DataTree.
Definition: mitkDataNode.h:66
static double transformationGlocke(double x)