Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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)