CustusX  15.8
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 
55 namespace cx
56 {
57 
59 {
60 }
61 
63 {
64 }
65 
67 {
68  mOpacityMap = source->mOpacityMap;
69  mColorMap = source->mColorMap;
70 }
71 
72 void ImageTFData::addXml(QDomNode dataNode)
73 {
74  QDomDocument doc = dataNode.ownerDocument();
75 
76  QDomElement alphaNode = doc.createElement("alpha");
77  // Use QStringList to put all points in the same string instead of storing
78  // the points as separate nodes.
79  QStringList pointStringList;
80  // Add alpha points
81  for (IntIntMap::iterator opPoint = mOpacityMap.begin(); opPoint != mOpacityMap.end(); ++opPoint)
82  pointStringList.append(QString("%1=%2").arg(opPoint->first). arg(opPoint->second));
83  alphaNode.appendChild(doc.createTextNode(pointStringList.join(" ")));
84 
85  pointStringList.clear();
86  QDomElement colorNode = doc.createElement("color");
87  // Add color points
88  for (ColorMap::iterator colorPoint = mColorMap.begin(); colorPoint != mColorMap.end(); ++colorPoint)
89  pointStringList.append(QString("%1=%2/%3/%4").arg(colorPoint->first). arg(colorPoint->second.red()). arg(
90  colorPoint->second.green()). arg(colorPoint->second.blue()));
91  colorNode.appendChild(doc.createTextNode(pointStringList.join(" ")));
92 
93  dataNode.appendChild(alphaNode);
94  dataNode.appendChild(colorNode);
95 
96  QDomElement elem = dataNode.toElement();
97 }
98 
99 void ImageTFData::parseXml(QDomNode dataNode)
100 {
101  if (dataNode.isNull())
102  return;
103 
104  QDomNode alphaNode = dataNode.namedItem("alpha");
105  // Read alpha node if it exists
106  if (!alphaNode.isNull() && !alphaNode.toElement().text().isEmpty())
107  {
108  QString alphaString = alphaNode.toElement().text();
109  mOpacityMap.clear();
110  QStringList alphaStringList = alphaString.split(" ", QString::SkipEmptyParts);
111  for (int i = 0; i < alphaStringList.size(); i++)
112  {
113  QStringList pointStringList = alphaStringList[i].split("=");
114  if (pointStringList.size() < 2)
115  continue;
116  addAlphaPoint(pointStringList[0].toInt(), pointStringList[1].toInt());
117  }
118  }
119  else
120  {
121  std::cout << "Warning: ImageTF3D::parseXml() found no alpha transferfunction";
122  std::cout << std::endl;
123  }
124 
125  QDomNode colorNode = dataNode.namedItem("color");
126  // Read color node if it exists
127  if (!colorNode.isNull() && !colorNode.toElement().text().isEmpty())
128  {
129  mColorMap.clear();
130  QStringList colorStringList = colorNode.toElement().text().split(" ", QString::SkipEmptyParts);
131  for (int i = 0; i < colorStringList.size(); i++)
132  {
133  QStringList pointStringList = colorStringList[i].split("=");
134  QStringList valueStringList = pointStringList[1].split("/");
135  addColorPoint(pointStringList[0].toInt(), QColor(valueStringList[0].toInt(), valueStringList[1].toInt(),
136  valueStringList[2].toInt()));
137  }
138  }
139  else
140  {
141  std::cout << "Warning: ImageTF3D::parseXml() found no color transferfunction";
142  std::cout << std::endl;
143  }
144 
145  this->internalsHaveChanged();
146 }
147 
154 void ImageTFData::unsignedCT(bool onLoad)
155 {
156 // //Signed after all. Don't do anyting
157 // if (this->getScalarMin() < 0)
158 // return;
159 
160  int modify = -1024;
161  if(onLoad)
162  modify = 1024;
163 
164 // std::cout << "unsignedCT shift " << modify << std::endl;
165  this->shift(modify);
166 }
167 
168 void ImageTFData::shift(int val)
169 {
170  this->shiftOpacity(val);
171  this->shiftColor(val, 0, 1);
172 
173  this->internalsHaveChanged();
174 }
175 
176 void ImageTFData::shiftColor(int shift, double center, double scale)
177 {
178  ColorMap newColorMap;
179  for (ColorMap::iterator it = mColorMap.begin(); it != mColorMap.end(); ++it)
180  {
181  double newVal = (it->first-center)*scale+center + shift;
182  int roundedVal = floor(newVal + 0.5);
183  newColorMap[roundedVal] = it->second;
184  }
185  mColorMap = newColorMap;
186 }
187 
189 {
190  IntIntMap newOpacipyMap;
191  for (IntIntMap::iterator it = mOpacityMap.begin(); it != mOpacityMap.end(); ++it)
192  {
193  newOpacipyMap[it->first + shift] = it->second;
194  }
195  mOpacityMap = newOpacipyMap;
196 }
197 
201 void ImageTFData::setLLR(double val)
202 {
203  double old = this->getLLR();
204  if (similar(old, val))
205  return;
206 
207  this->shiftOpacity(val-old);
208  this->internalsHaveChanged();
209 }
210 
211 double ImageTFData::getLLR() const
212 {
213  if (mOpacityMap.empty())
214  return 0;
215 
216  for (IntIntMap::const_iterator it = mOpacityMap.begin(); it != mOpacityMap.end(); ++it)
217  {
218  if (!similar(it->second, 0.0))
219  return it->first;
220  }
221  return mOpacityMap.begin()->first;
222 }
223 
224 void ImageTFData::setAlpha(double val)
225 {
226  double old = this->getAlpha();
227  if (similar(old, val))
228  return;
229 
230  if (similar(old, 0.0))
231  {
232  // degenerate case: we have lost all info, simpl add input val to all but the first entry
233  for (IntIntMap::iterator it = mOpacityMap.begin(); it != mOpacityMap.end(); ++it)
234  {
235  if (it==mOpacityMap.begin() && mOpacityMap.size()>1)
236  continue; // heuristic: assume first entry should stay at zero
237  it->second += val*255;
238  }
239  }
240  else
241  {
242  double scale = val/old;
243  for (IntIntMap::iterator it = mOpacityMap.begin(); it != mOpacityMap.end(); ++it)
244  {
245  it->second *= scale;
246  }
247  }
248 
249  this->internalsHaveChanged();
250 }
251 
252 double ImageTFData::getAlpha() const
253 {
254  double amax = 0;
255  for (IntIntMap::const_iterator it = mOpacityMap.begin(); it != mOpacityMap.end(); ++it)
256  {
257  amax = std::max<double>(it->second, amax);
258  }
259  return amax/255;
260 }
261 
265 void ImageTFData::setWindow(double val)
266 {
267  double old = this->getWindow();
268  val = std::max(1.0, val);
269 
270  if (similar(old, val))
271  return;
272 
273  double scale = val/old;
274  this->shiftColor(0, this->getLevel(), scale);
275 
276  this->internalsHaveChanged();
277 }
278 
280 {
281  if (mColorMap.empty())
282  return 0;
283  return mColorMap.rbegin()->first - mColorMap.begin()->first;
284 // return mWindow;
285 }
286 
290 void ImageTFData::setLevel(double val)
291 {
292  double old = this->getLevel();
293  if (similar(old, val))
294  return;
295  double shift = val-old;
296 
297  this->shiftColor(shift, 0.0, 1.0);
298 
299 // mLevel = val;
300  this->internalsHaveChanged();
301 }
302 
303 double ImageTFData::getLevel() const
304 {
305  if (mColorMap.empty())
306  return 0;
307  int a = mColorMap.begin()->first;
308  int b = mColorMap.rbegin()->first;
309  return a + (b-a)/2;
310 // return mLevel;
311 }
312 
314 {
315  return mOpacityMap;
316 }
318 {
319  return mColorMap;
320 }
321 void ImageTFData::addAlphaPoint(int alphaPosition, int alphaValue)
322 {
323  //mOpacityMapPtr->insert(std::pair<int, int>(alphaPosition, alphaValue));
324  mOpacityMap[alphaPosition] = alphaValue;
325  this->internalsHaveChanged();
326 }
327 void ImageTFData::removeAlphaPoint(int alphaPosition)
328 {
329  mOpacityMap.erase(alphaPosition);
330  this->internalsHaveChanged();
331 }
332 void ImageTFData::moveAlphaPoint(int oldpos, int newpos, int alphaValue)
333 {
334  mOpacityMap.erase(oldpos);
335  mOpacityMap[newpos] = alphaValue;
336  this->internalsHaveChanged();
337 }
338 void ImageTFData::addColorPoint(int colorPosition, QColor colorValue)
339 {
340  mColorMap[colorPosition] = colorValue;
341  //mColorMapPtr->insert(std::pair<int, QColor>(colorPosition, colorValue));
342  this->internalsHaveChanged();
343 }
344 void ImageTFData::removeColorPoint(int colorPosition)
345 {
346  mColorMap.erase(colorPosition);
347  this->internalsHaveChanged();
348 }
349 
350 void ImageTFData::moveColorPoint(int oldpos, int newpos, QColor colorValue)
351 {
352  mColorMap.erase(oldpos);
353  mColorMap[newpos] = colorValue;
354  this->internalsHaveChanged();
355 }
356 
358 {
359  mOpacityMap = val;
360  this->internalsHaveChanged();
361 }
362 
364 {
365  mColorMap = val;
366  this->internalsHaveChanged();
367 }
368 
370 {
371  vtkColorTransferFunctionPtr tf = vtkColorTransferFunctionPtr::New();
372  this->fillColorTFFromMap(tf);
373  return tf;
374 }
375 
377 {
378  vtkPiecewiseFunctionPtr tf = vtkPiecewiseFunctionPtr::New();
379  this->fillOpacityTFFromMap(tf);
380  return tf;
381 }
382 
384 {
385  tf->SetColorSpaceToRGB();
386  tf->RemoveAllPoints();
387  for (ColorMap::const_iterator iter = mColorMap.begin(); iter != mColorMap.end(); ++iter)
388  {
389  QColor c = iter->second;
390  tf->AddRGBPoint(iter->first, c.redF(), c.greenF(), c.blueF());
391  }
392 }
393 
395 {
396  tf->RemoveAllPoints();
397  for (IntIntMap::const_iterator iter = mOpacityMap.begin(); iter != mOpacityMap.end(); ++iter)
398  tf->AddPoint(iter->first, iter->second / 255.0);
399 // tf->Update();
400 }
401 
402 }
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
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