CustusX  16.5.0-rc9
An IGT application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
cxImageTFData.cpp
Go to the documentation of this file.
1 /*=========================================================================
2 This file is part of CustusX, an Image Guided Therapy Application.
3 
4 Copyright (c) 2008-2014, SINTEF Department of Medical Technology
5 All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 
10 1. Redistributions of source code must retain the above copyright notice,
11  this list of conditions and the following disclaimer.
12 
13 2. Redistributions in binary form must reproduce the above copyright notice,
14  this list of conditions and the following disclaimer in the documentation
15  and/or other materials provided with the distribution.
16 
17 3. Neither the name of the copyright holder nor the names of its contributors
18  may be used to endorse or promote products derived from this software
19  without specific prior written permission.
20 
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 =========================================================================*/
32 
33 
34 /*
35  * sscImageTFData.cpp
36  *
37  * Created on: Mar 15, 2011
38  * Author: christiana
39  */
40 
41 #include "cxImageTFData.h"
42 #include <iostream>
43 #include <QDomDocument>
44 #include <QStringList>
45 #include <vtkColorTransferFunction.h>
46 #include <vtkPiecewiseFunction.h>
47 #include <vtkLookupTable.h>
48 #include <vtkImageData.h>
49 
50 #include "cxVector3D.h"
51 #include "cxImageTF3D.h"
52 
53 #include "cxTypeConversions.h"
54 #include "cxLogger.h"
55 
56 namespace cx
57 {
58 
60 {
61 }
62 
64 {
65 }
66 
68 {
69  mOpacityMap = source->mOpacityMap;
70  mColorMap = source->mColorMap;
71 }
72 
73 void ImageTFData::addXml(QDomNode dataNode)
74 {
75  QDomDocument doc = dataNode.ownerDocument();
76 
77  QDomElement alphaNode = doc.createElement("alpha");
78  // Use QStringList to put all points in the same string instead of storing
79  // the points as separate nodes.
80  QStringList pointStringList;
81  // Add alpha points
82  for (IntIntMap::iterator opPoint = mOpacityMap.begin(); opPoint != mOpacityMap.end(); ++opPoint)
83  pointStringList.append(QString("%1=%2").arg(opPoint->first). arg(opPoint->second));
84  alphaNode.appendChild(doc.createTextNode(pointStringList.join(" ")));
85 
86  pointStringList.clear();
87  QDomElement colorNode = doc.createElement("color");
88  // Add color points
89  for (ColorMap::iterator colorPoint = mColorMap.begin(); colorPoint != mColorMap.end(); ++colorPoint)
90  pointStringList.append(QString("%1=%2/%3/%4").arg(colorPoint->first). arg(colorPoint->second.red()). arg(
91  colorPoint->second.green()). arg(colorPoint->second.blue()));
92  colorNode.appendChild(doc.createTextNode(pointStringList.join(" ")));
93 
94  dataNode.appendChild(alphaNode);
95  dataNode.appendChild(colorNode);
96 
97  QDomElement elem = dataNode.toElement();
98 }
99 
100 void ImageTFData::parseXml(QDomNode dataNode)
101 {
102  if (dataNode.isNull())
103  {
104  CX_LOG_WARNING() << "ImageTFData::parseXml empty data node";
105  return;
106  }
107 
108  QDomNode alphaNode = dataNode.namedItem("alpha");
109  // Read alpha node if it exists
110  if (!alphaNode.isNull() && !alphaNode.toElement().text().isEmpty())
111  {
112  QString alphaString = alphaNode.toElement().text();
113  mOpacityMap.clear();
114  QStringList alphaStringList = alphaString.split(" ", QString::SkipEmptyParts);
115  for (int i = 0; i < alphaStringList.size(); i++)
116  {
117  QStringList pointStringList = alphaStringList[i].split("=");
118  if (pointStringList.size() < 2)
119  continue;
120  addAlphaPoint(pointStringList[0].toInt(), pointStringList[1].toInt());
121  }
122  }
123  else
124  {
125  CX_LOG_WARNING() << "ImageTF3D::parseXml() found no alpha transferfunction";
126  }
127 
128  QDomNode colorNode = dataNode.namedItem("color");
129  // Read color node if it exists
130  if (!colorNode.isNull() && !colorNode.toElement().text().isEmpty())
131  {
132  mColorMap.clear();
133  QStringList colorStringList = colorNode.toElement().text().split(" ", QString::SkipEmptyParts);
134  for (int i = 0; i < colorStringList.size(); i++)
135  {
136  QStringList pointStringList = colorStringList[i].split("=");
137  QStringList valueStringList = pointStringList[1].split("/");
138  addColorPoint(pointStringList[0].toInt(), QColor(valueStringList[0].toInt(), valueStringList[1].toInt(),
139  valueStringList[2].toInt()));
140  }
141  }
142  else
143  {
144  CX_LOG_WARNING() << "ImageTF3D::parseXml() found no color transferfunction";
145  }
146 
147  this->internalsHaveChanged();
148 }
149 
156 void ImageTFData::unsignedCT(bool onLoad)
157 {
158 // //Signed after all. Don't do anyting
159 // if (this->getScalarMin() < 0)
160 // return;
161 
162  int modify = -1024;
163  if(onLoad)
164  modify = 1024;
165 
166 // std::cout << "unsignedCT shift " << modify << std::endl;
167  this->shift(modify);
168 }
169 
170 void ImageTFData::shift(int val)
171 {
172  this->shiftOpacity(val);
173  this->shiftColor(val, 0, 1);
174 
175  this->internalsHaveChanged();
176 }
177 
178 void ImageTFData::shiftColor(int shift, double center, double scale)
179 {
180  ColorMap newColorMap;
181  for (ColorMap::iterator it = mColorMap.begin(); it != mColorMap.end(); ++it)
182  {
183  double newVal = (it->first-center)*scale+center + shift;
184  int roundedVal = floor(newVal + 0.5);
185  newColorMap[roundedVal] = it->second;
186  }
187  mColorMap = newColorMap;
188 }
189 
191 {
192  IntIntMap newOpacipyMap;
193  for (IntIntMap::iterator it = mOpacityMap.begin(); it != mOpacityMap.end(); ++it)
194  {
195  newOpacipyMap[it->first + shift] = it->second;
196  }
197  mOpacityMap = newOpacipyMap;
198 }
199 
203 void ImageTFData::setLLR(double val)
204 {
205  double old = this->getLLR();
206  if (similar(old, val))
207  return;
208 
209  this->shiftOpacity(val-old);
210  this->internalsHaveChanged();
211 }
212 
213 double ImageTFData::getLLR() const
214 {
215  if (mOpacityMap.empty())
216  return 0;
217 
218  for (IntIntMap::const_iterator it = mOpacityMap.begin(); it != mOpacityMap.end(); ++it)
219  {
220  if (!similar(it->second, 0.0))
221  return it->first;
222  }
223  return mOpacityMap.begin()->first;
224 }
225 
226 void ImageTFData::setAlpha(double val)
227 {
228  double old = this->getAlpha();
229  if (similar(old, val))
230  return;
231 
232  if (similar(old, 0.0))
233  {
234  // degenerate case: we have lost all info, simpl add input val to all but the first entry
235  for (IntIntMap::iterator it = mOpacityMap.begin(); it != mOpacityMap.end(); ++it)
236  {
237  if (it==mOpacityMap.begin() && mOpacityMap.size()>1)
238  continue; // heuristic: assume first entry should stay at zero
239  it->second += val*255;
240  }
241  }
242  else
243  {
244  double scale = val/old;
245  for (IntIntMap::iterator it = mOpacityMap.begin(); it != mOpacityMap.end(); ++it)
246  {
247  it->second *= scale;
248  }
249  }
250 
251  this->internalsHaveChanged();
252 }
253 
254 double ImageTFData::getAlpha() const
255 {
256  double amax = 0;
257  for (IntIntMap::const_iterator it = mOpacityMap.begin(); it != mOpacityMap.end(); ++it)
258  {
259  amax = std::max<double>(it->second, amax);
260  }
261  return amax/255;
262 }
263 
267 void ImageTFData::setWindow(double val)
268 {
269  double old = this->getWindow();
270  val = std::max(1.0, val);
271 
272  if (similar(old, val))
273  return;
274 
275  double scale = val/old;
276  this->shiftColor(0, this->getLevel(), scale);
277 
278  this->internalsHaveChanged();
279 }
280 
282 {
283  if (mColorMap.empty())
284  return 0;
285  return mColorMap.rbegin()->first - mColorMap.begin()->first;
286 // return mWindow;
287 }
288 
292 void ImageTFData::setLevel(double val)
293 {
294  double old = this->getLevel();
295  if (similar(old, val))
296  return;
297  double shift = val-old;
298 
299  this->shiftColor(shift, 0.0, 1.0);
300 
301 // mLevel = val;
302  this->internalsHaveChanged();
303 }
304 
305 double ImageTFData::getLevel() const
306 {
307  if (mColorMap.empty())
308  return 0;
309  int a = mColorMap.begin()->first;
310  int b = mColorMap.rbegin()->first;
311  return a + (b-a)/2;
312 // return mLevel;
313 }
314 
316 {
317  return mOpacityMap;
318 }
320 {
321  return mColorMap;
322 }
323 void ImageTFData::addAlphaPoint(int alphaPosition, int alphaValue)
324 {
325  //mOpacityMapPtr->insert(std::pair<int, int>(alphaPosition, alphaValue));
326  mOpacityMap[alphaPosition] = alphaValue;
327  this->internalsHaveChanged();
328 }
329 void ImageTFData::removeAlphaPoint(int alphaPosition)
330 {
331  mOpacityMap.erase(alphaPosition);
332  this->internalsHaveChanged();
333 }
334 void ImageTFData::moveAlphaPoint(int oldpos, int newpos, int alphaValue)
335 {
336  mOpacityMap.erase(oldpos);
337  mOpacityMap[newpos] = alphaValue;
338  this->internalsHaveChanged();
339 }
340 void ImageTFData::addColorPoint(int colorPosition, QColor colorValue)
341 {
342  mColorMap[colorPosition] = colorValue;
343  //mColorMapPtr->insert(std::pair<int, QColor>(colorPosition, colorValue));
344  this->internalsHaveChanged();
345 }
346 void ImageTFData::removeColorPoint(int colorPosition)
347 {
348  mColorMap.erase(colorPosition);
349  this->internalsHaveChanged();
350 }
351 
352 void ImageTFData::moveColorPoint(int oldpos, int newpos, QColor colorValue)
353 {
354  mColorMap.erase(oldpos);
355  mColorMap[newpos] = colorValue;
356  this->internalsHaveChanged();
357 }
358 
360 {
361  mOpacityMap = val;
362  this->internalsHaveChanged();
363 }
364 
366 {
367  mColorMap = val;
368  this->internalsHaveChanged();
369 }
370 
372 {
373  vtkColorTransferFunctionPtr tf = vtkColorTransferFunctionPtr::New();
374  this->fillColorTFFromMap(tf);
375  return tf;
376 }
377 
379 {
380  vtkPiecewiseFunctionPtr tf = vtkPiecewiseFunctionPtr::New();
381  this->fillOpacityTFFromMap(tf);
382  return tf;
383 }
384 
386 {
387  tf->SetColorSpaceToRGB();
388  tf->RemoveAllPoints();
389  for (ColorMap::const_iterator iter = mColorMap.begin(); iter != mColorMap.end(); ++iter)
390  {
391  QColor c = iter->second;
392  tf->AddRGBPoint(iter->first, c.redF(), c.greenF(), c.blueF());
393  }
394 }
395 
397 {
398  tf->RemoveAllPoints();
399  for (IntIntMap::const_iterator iter = mOpacityMap.begin(); iter != mOpacityMap.end(); ++iter)
400  tf->AddPoint(iter->first, iter->second / 255.0);
401 // tf->Update();
402 }
403 
404 }
void setLLR(double val)
range [scalarMin..scalarMax]
IntIntMap mOpacityMap
double getLLR() const
virtual ~ImageTFData()
void unsignedCT(bool onLoad)
void shiftColor(int shift, double center, double scale)
virtual void addXml(QDomNode dataNode)
adds xml information about the transferfunction and its variabels
void fillOpacityTFFromMap(vtkPiecewiseFunctionPtr tf) const
virtual void parseXml(QDomNode dataNode)
Use a XML node to load data.
vtkColorTransferFunctionPtr generateColorTF() const
void shift(int val)
shift the transfter function index values by the input amount. Used for signed/unsigned conversion...
vtkSmartPointer< class vtkPiecewiseFunction > vtkPiecewiseFunctionPtr
void resetColor(ColorMap val)
void setAlpha(double val)
range [0..1]
bool similar(const DoubleBoundingBox3D &a, const DoubleBoundingBox3D &b, double tol)
double getAlpha() const
ColorMap getColorMap()
vtkSmartPointer< class vtkColorTransferFunction > vtkColorTransferFunctionPtr
void removeAlphaPoint(int alphaPosition)
Remove point from the opacity transfer function.
std::map< int, QColor > ColorMap
Definition: cxImage.h:57
void setWindow(double val)
range [1..scalarMax-scalarMin]
void moveColorPoint(int oldpos, int newpos, QColor colorValue)
void removeColorPoint(int colorPosition)
Remove point from the color transfer function.
vtkPiecewiseFunctionPtr generateOpacityTF() const
double getLevel() const
virtual void internalsHaveChanged()
void resetAlpha(IntIntMap val)
std::map< int, int > IntIntMap
Definition: cxImage.h:56
IntIntMap getOpacityMap()
Data class for Transfer Function info, either 2D or 3D.
Definition: cxImageTFData.h:97
#define CX_LOG_WARNING
Definition: cxLogger.h:113
void setLevel(double val)
range [scalarMin..scalarMax]
ColorMap mColorMap
void addAlphaPoint(int alphaPosition, int alphaValue)
Add point to the opacity transfer function.
void moveAlphaPoint(int oldpos, int newpos, int alphaValue)
double getWindow() const
void shiftOpacity(int shift)
void addColorPoint(int colorPosition, QColor colorValue)
Add point to the color transfer function.
void deepCopy(ImageTFData *source)
void fillColorTFFromMap(vtkColorTransferFunctionPtr tf) const