comparison Framework/Deprecated/Radiography/RadiographyDicomLayer.cpp @ 1398:c5403d52078c

moved Radiography into Deprecated
author Alain Mazy <alain@mazy.be>
date Wed, 29 Apr 2020 20:43:09 +0200
parents Framework/Radiography/RadiographyDicomLayer.cpp@379c00958553
children 30deba7bc8e2
comparison
equal deleted inserted replaced
1397:1c2d065ba372 1398:c5403d52078c
1 /**
2 * Stone of Orthanc
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
4 * Department, University Hospital of Liege, Belgium
5 * Copyright (C) 2017-2020 Osimis S.A., Belgium
6 *
7 * This program is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU Affero General Public License
9 * as published by the Free Software Foundation, either version 3 of
10 * the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **/
20
21
22 #include "RadiographyDicomLayer.h"
23
24 #include "RadiographyScene.h"
25 #include "../Deprecated/Toolbox/DicomFrameConverter.h"
26
27 #include <Core/OrthancException.h>
28 #include <Core/Images/Image.h>
29 #include <Core/Images/ImageProcessing.h>
30 #include <Plugins/Samples/Common/DicomDatasetReader.h>
31 #include "../Toolbox/ImageGeometry.h"
32
33 static OrthancPlugins::DicomTag ConvertTag(const Orthanc::DicomTag& tag)
34 {
35 return OrthancPlugins::DicomTag(tag.GetGroup(), tag.GetElement());
36 }
37
38 namespace OrthancStone
39 {
40
41 void RadiographyDicomLayer::ApplyConverter()
42 {
43 if (source_.get() != NULL &&
44 converter_.get() != NULL)
45 {
46 converted_.reset(converter_->ConvertFrame(*source_));
47 }
48 }
49
50
51 RadiographyDicomLayer::RadiographyDicomLayer(const RadiographyScene& scene) :
52 RadiographyLayer(scene)
53 {
54
55 }
56
57 void RadiographyDicomLayer::SetDicomTags(const OrthancPlugins::FullOrthancDataset& dataset)
58 {
59 converter_.reset(new Deprecated::DicomFrameConverter);
60 converter_->ReadParameters(dataset);
61 ApplyConverter();
62
63 std::string tmp;
64 Vector pixelSpacing;
65
66 if (dataset.GetStringValue(tmp, ConvertTag(Orthanc::DICOM_TAG_PIXEL_SPACING)) &&
67 LinearAlgebra::ParseVector(pixelSpacing, tmp) &&
68 pixelSpacing.size() == 2)
69 {
70 SetPixelSpacing(pixelSpacing[0], pixelSpacing[1]);
71 }
72
73 OrthancPlugins::DicomDatasetReader reader(dataset);
74
75 unsigned int width, height;
76 if (!reader.GetUnsignedIntegerValue(width, ConvertTag(Orthanc::DICOM_TAG_COLUMNS)) ||
77 !reader.GetUnsignedIntegerValue(height, ConvertTag(Orthanc::DICOM_TAG_ROWS)))
78 {
79 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
80 }
81 else
82 {
83 SetSize(width, height);
84 }
85
86 if (dataset.GetStringValue(tmp, ConvertTag(Orthanc::DICOM_TAG_PHOTOMETRIC_INTERPRETATION)))
87 {
88 if (tmp == "MONOCHROME1")
89 {
90 SetPreferredPhotomotricDisplayMode(RadiographyPhotometricDisplayMode_Monochrome1);
91 }
92 else if (tmp == "MONOCHROME2")
93 {
94 SetPreferredPhotomotricDisplayMode(RadiographyPhotometricDisplayMode_Monochrome2);
95 }
96 }
97 }
98
99 void RadiographyDicomLayer::SetSourceImage(Orthanc::ImageAccessor* image) // Takes ownership
100 {
101 std::unique_ptr<Orthanc::ImageAccessor> raii(image);
102
103 if (image == NULL)
104 {
105 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
106 }
107
108 SetSize(image->GetWidth(), image->GetHeight());
109
110 #if __cplusplus < 201103L
111 source_.reset(raii.release());
112 #else
113 source_ = std::move(raii);
114 #endif
115
116 ApplyConverter();
117
118 BroadcastMessage(RadiographyLayer::LayerEditedMessage(*this));
119 }
120
121 void RadiographyDicomLayer::SetSourceImage(Orthanc::ImageAccessor* image, double newPixelSpacingX, double newPixelSpacingY, bool emitLayerEditedEvent) // Takes ownership
122 {
123 std::unique_ptr<Orthanc::ImageAccessor> raii(image);
124
125 if (image == NULL)
126 {
127 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
128 }
129
130 SetSize(image->GetWidth(), image->GetHeight(), false);
131
132 #if __cplusplus < 201103L
133 source_.reset(raii.release());
134 #else
135 source_ = std::move(raii);
136 #endif
137
138 ApplyConverter();
139
140 SetPixelSpacing(newPixelSpacingX, newPixelSpacingY, false);
141
142 if (emitLayerEditedEvent)
143 {
144 BroadcastMessage(RadiographyLayer::LayerEditedMessage(*this));
145 }
146 }
147
148
149 void RadiographyDicomLayer::SetDicomFrameConverter(Deprecated::DicomFrameConverter* converter)
150 {
151 converter_.reset(converter);
152 }
153
154 void RadiographyDicomLayer::Render(Orthanc::ImageAccessor& buffer,
155 const AffineTransform2D& viewTransform,
156 ImageInterpolation interpolation,
157 float windowCenter,
158 float windowWidth,
159 bool applyWindowing) const
160 {
161 if (converted_.get() != NULL)
162 {
163 if (converted_->GetFormat() != Orthanc::PixelFormat_Float32)
164 {
165 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
166 }
167
168 unsigned int cropX, cropY, cropWidth, cropHeight;
169 GetCrop(cropX, cropY, cropWidth, cropHeight);
170
171 AffineTransform2D t = AffineTransform2D::Combine(
172 viewTransform, GetTransform(),
173 AffineTransform2D::CreateOffset(cropX, cropY));
174
175 Orthanc::ImageAccessor cropped;
176 converted_->GetRegion(cropped, cropX, cropY, cropWidth, cropHeight);
177
178 unsigned int x1, y1, x2, y2;
179 if (!OrthancStone::GetProjectiveTransformExtent(x1, y1, x2, y2,
180 t.GetHomogeneousMatrix(),
181 cropped.GetWidth(),
182 cropped.GetHeight(),
183 buffer.GetWidth(),
184 buffer.GetHeight()))
185 {
186 return; // layer is outside the buffer
187 }
188
189 t.Apply(buffer, cropped, interpolation, false);
190
191 if (applyWindowing)
192 {
193 // apply windowing but stay in the range [0.0, 65535.0]
194 float w0 = windowCenter - windowWidth / 2.0f;
195 float w1 = windowCenter + windowWidth / 2.0f;
196
197 if (windowWidth >= 0.001f) // Avoid division by zero at (*)
198 {
199 float scaling = 1.0f / (w1 - w0) * 65535.0f;
200 for (unsigned int y = y1; y <= y2; y++)
201 {
202 float* p = reinterpret_cast<float*>(buffer.GetRow(y)) + x1;
203
204 for (unsigned int x = x1; x <= x2; x++, p++)
205 {
206 if (*p >= w1)
207 {
208 *p = 65535.0;
209 }
210 else if (*p <= w0)
211 {
212 *p = 0;
213 }
214 else
215 {
216 // https://en.wikipedia.org/wiki/Linear_interpolation
217 *p = scaling * (*p - w0); // (*)
218 }
219 }
220 }
221 }
222 }
223
224 }
225 }
226
227
228 bool RadiographyDicomLayer::GetDefaultWindowing(float& center,
229 float& width) const
230 {
231 if (converter_.get() != NULL &&
232 converter_->HasDefaultWindow())
233 {
234 center = static_cast<float>(converter_->GetDefaultWindowCenter());
235 width = static_cast<float>(converter_->GetDefaultWindowWidth());
236 return true;
237 }
238 else
239 {
240 return false;
241 }
242 }
243
244
245 bool RadiographyDicomLayer::GetRange(float& minValue,
246 float& maxValue) const
247 {
248 if (converted_.get() != NULL)
249 {
250 if (converted_->GetFormat() != Orthanc::PixelFormat_Float32)
251 {
252 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
253 }
254
255 Orthanc::ImageProcessing::GetMinMaxFloatValue(minValue, maxValue, *converted_);
256 return true;
257 }
258 else
259 {
260 return false;
261 }
262 }
263
264 }