Fraxinus  22.04-rc3
An IGT application
cxImageDefaultTFGenerator.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) SINTEF Department of Medical Technology.
5 All rights reserved.
6 
7 CustusX is released under a BSD 3-Clause license.
8 
9 See Lisence.txt (https://github.com/SINTEFMedtek/CustusX/blob/master/License.txt) for details.
10 =========================================================================*/
11 
13 
14 #include "vtkImageData.h"
15 #include "cxImage.h"
16 #include "cxImageLUT2D.h"
17 #include "cxImageTF3D.h"
18 #include "cxSettings.h"
19 
20 namespace cx
21 {
22 
24 {
25 
26 }
27 
29 {
30  // add shading for known preoperative modalities
31  if ((mImage->getModality() == imCT) || (mImage->getModality() == imMR))
32  mImage->setShadingOn(settings()->value("View/shadingOn").value<bool>());
33 }
34 
36 {
37  ImageLUT2DPtr tf(new ImageLUT2D());
38 
39  double_pair fullRange = this->getFullScalarRange();
40  double_pair range = this->guessInitialScalarRange();
41  double smin = range.first;
42  double smax = range.second;
43 
44  IntIntMap opacity;
45  opacity[fullRange.first - 1] = 0;
46  opacity[fullRange.first] = 255;
47  tf->resetAlpha(opacity);
48 
49  ColorMap colors;
50  colors[smin] = QColor(Qt::black);
51  colors[smax] = QColor(Qt::white);
52  tf->resetColor(colors);
53 
54  if (this->looksLikeBinaryImage())
55  tf->setLLR(smin+1);//Make zero transparent for binary volumes. Why is +1 needed? Is there an issue with LLR range?
56 
57  return tf;
58 }
59 
61 {
62  ImageTF3DPtr tf(new ImageTF3D());
63 
64  double_pair range = this->guessInitialScalarRange();
65 
66  double smin = range.first;
67  double smax = range.second;
68  double srange = smax - smin;
69 
70  IntIntMap opacity;
71  // Note the ordering: add in descending order to ensure zero is
72  // always written into smin, also for binary volumes
73  // Round is required for binary volumes.
74  opacity[int(std::lround(smin + 0.5*srange))] = 255;
75  opacity[int(std::lround(smin + 0.3*srange))] = int(std::lround(255.0 * 0.7));
76  opacity[int(std::lround(smin + 0.1*srange))] = 0;
77  tf->resetAlpha(opacity);
78 
79  ColorMap colors;
80  colors[int(std::lround(smin))] = QColor(Qt::black);
81  colors[int(std::lround(smax))] = QColor(Qt::white);
82  tf->resetColor(colors);
83 
84  return tf;
85 }
86 
87 bool ImageDefaultTFGenerator::hasValidInitialWindow() const
88 {
89  return mImage->getInitialWindowWidth()>0;
90 }
91 
92 double_pair ImageDefaultTFGenerator::guessInitialScalarRange() const
93 {
94  double_pair srange = this->getFullScalarRange();
95 
96  if (this->hasValidInitialWindow())
97  {
98  srange = this->getInitialWindowRange();
99  }
100  // no initial window: add heuristics for each modality
101  if (!this->hasValidInitialWindow())
102  {
103  if (this->isUnsignedChar())
104  {
105  srange.first = 0;
106  srange.second = 255;
107 
108  if (this->looksLikeBinaryImage())
109  {
110  srange.first = 0;
111  srange.second = 1;
112  return srange;
113  }
114  }
115  if (mImage->getModality() == imCT)
116  {
117  srange = this->guessCTRange();
118  }
119  if (mImage->getModality() == imMR)
120  {
121  srange = this->guessMRRange();
122  }
123  }
124 
125  srange = this->ensureNonZeroRoundedRange(srange);
126  return srange;
127 }
128 
129 bool ImageDefaultTFGenerator::isUnsignedChar() const
130 {
131  return mImage->getBaseVtkImageData()->GetScalarType() == VTK_UNSIGNED_CHAR;
132 }
133 
134 bool ImageDefaultTFGenerator::looksLikeBinaryImage() const
135 {
136  double_pair r = this->getFullScalarRange();
137  return similar(r.first, 0) && similar(r.second, 1);
138 }
139 
140 
141 double_pair ImageDefaultTFGenerator::ensureNonZeroRoundedRange(double_pair range) const
142 {
143  range.first = std::round(range.first);
144  range.second = std::round(range.second);
145  range.second = std::max(range.second, range.first+1);
146  return range;
147 }
148 
149 double_pair ImageDefaultTFGenerator::getFullScalarRange() const
150 {
151  double smin = mImage->getBaseVtkImageData()->GetScalarRange()[0];
152  double smax = mImage->getBaseVtkImageData()->GetScalarRange()[1];
153  return std::make_pair(smin, smax);
154 }
155 
156 double_pair ImageDefaultTFGenerator::getInitialWindowRange() const
157 {
158  double smin = mImage->getInitialWindowLevel() - mImage->getInitialWindowWidth()/2;
159  double smax = mImage->getInitialWindowLevel() + mImage->getInitialWindowWidth()/2;
160  return std::make_pair(smin, smax);
161 }
162 
163 double_pair ImageDefaultTFGenerator::guessCTRange() const
164 {
165  // signed: [-1024...3072]
166  // choose a default from lung to bone, approximately.
167  double smin = -500;
168  double smax = 900;
169 // if (0 >= mImage->getMin()) // unsigned: [0..4096]
170 // {
171 // int ct_signed2unsigned = 1024;
172 // smin += ct_signed2unsigned;
173 // smax += ct_signed2unsigned;
174 // }
175  return std::make_pair(smin, smax);
176 }
177 
178 double_pair ImageDefaultTFGenerator::guessMRRange() const
179 {
180  double_pair srange = this->getFullScalarRange();
181  srange.second *= 0.25; // usually lots of high-intensity noise of no interest
182  return srange;
183 }
184 
185 
186 } // namespace cx
Handler for the transfer functions used in 3d image volumes.
Definition: cxImageTF3D.h:51
imMR
boost::shared_ptr< class Image > ImagePtr
Definition: cxDicomWidget.h:27
Handling of color and opacity for 2D slices.
Definition: cxImageLUT2D.h:47
std::pair< double, double > double_pair
std::map< int, QColor > ColorMap
Definition: cxImage.h:36
boost::shared_ptr< class ImageLUT2D > ImageLUT2DPtr
Settings * settings()
Shortcut for accessing the settings instance.
Definition: cxSettings.cpp:21
std::map< int, int > IntIntMap
Definition: cxImage.h:35
bool similar(const CameraInfo &lhs, const CameraInfo &rhs, double tol)
imCT
boost::shared_ptr< class ImageTF3D > ImageTF3DPtr
Vector3D round(const Vector3D &a)
Definition: cxVector3D.cpp:75
Namespace for all CustusX production code.