Mercurial > hg > orthanc-stone
annotate Framework/Radiography/RadiographyScene.cpp @ 1038:692291406f6a
virtual Render
author | Alain Mazy <alain@mazy.be> |
---|---|
date | Mon, 07 Oct 2019 22:11:46 +0200 |
parents | 1b49e78d91d0 |
children | b537002f83a9 d33ae2b0db9d |
rev | line source |
---|---|
408 | 1 /** |
2 * Stone of Orthanc | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
439 | 5 * Copyright (C) 2017-2019 Osimis S.A., Belgium |
408 | 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 "RadiographyScene.h" | |
23 | |
430 | 24 #include "RadiographyAlphaLayer.h" |
25 #include "RadiographyDicomLayer.h" | |
26 #include "RadiographyTextLayer.h" | |
475
3c28542229a3
added a mask layer in the RadiographyWidget (to be cleaned)
am@osimis.io
parents:
440
diff
changeset
|
27 #include "RadiographyMaskLayer.h" |
732
c35e98d22764
move Deprecated classes to a separate folder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
726
diff
changeset
|
28 #include "../Deprecated/Toolbox/DicomFrameConverter.h" |
408 | 29 |
30 #include <Core/Images/Image.h> | |
31 #include <Core/Images/ImageProcessing.h> | |
32 #include <Core/Images/PamReader.h> | |
33 #include <Core/Images/PamWriter.h> | |
34 #include <Core/Images/PngWriter.h> | |
35 #include <Core/OrthancException.h> | |
36 #include <Core/Toolbox.h> | |
37 #include <Plugins/Samples/Common/DicomDatasetReader.h> | |
38 #include <Plugins/Samples/Common/FullOrthancDataset.h> | |
39 | |
412 | 40 #include <boost/math/special_functions/round.hpp> |
41 | |
408 | 42 |
43 namespace OrthancStone | |
44 { | |
45 RadiographyScene::LayerAccessor::LayerAccessor(RadiographyScene& scene, | |
46 size_t index) : | |
47 scene_(scene), | |
48 index_(index) | |
49 { | |
50 Layers::iterator layer = scene.layers_.find(index); | |
51 if (layer == scene.layers_.end()) | |
52 { | |
53 layer_ = NULL; | |
54 } | |
55 else | |
56 { | |
57 assert(layer->second != NULL); | |
58 layer_ = layer->second; | |
59 } | |
60 } | |
61 | |
426 | 62 |
408 | 63 RadiographyScene::LayerAccessor::LayerAccessor(RadiographyScene& scene, |
64 double x, | |
65 double y) : | |
66 scene_(scene), | |
67 index_(0) // Dummy initialization | |
68 { | |
69 if (scene.LookupLayer(index_, x, y)) | |
70 { | |
71 Layers::iterator layer = scene.layers_.find(index_); | |
426 | 72 |
408 | 73 if (layer == scene.layers_.end()) |
74 { | |
75 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
76 } | |
77 else | |
78 { | |
79 assert(layer->second != NULL); | |
80 layer_ = layer->second; | |
81 } | |
82 } | |
83 else | |
84 { | |
85 layer_ = NULL; | |
86 } | |
87 } | |
88 | |
89 | |
90 RadiographyScene& RadiographyScene::LayerAccessor::GetScene() const | |
91 { | |
92 if (IsValid()) | |
93 { | |
94 return scene_; | |
95 } | |
96 else | |
97 { | |
98 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
99 } | |
100 } | |
101 | |
102 | |
103 size_t RadiographyScene::LayerAccessor::GetIndex() const | |
104 { | |
105 if (IsValid()) | |
106 { | |
107 return index_; | |
108 } | |
109 else | |
110 { | |
111 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
112 } | |
113 } | |
114 | |
115 | |
410
6decc0ba9da5
rename RadiographyScene::Layer as RadiographyLayer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
409
diff
changeset
|
116 RadiographyLayer& RadiographyScene::LayerAccessor::GetLayer() const |
408 | 117 { |
118 if (IsValid()) | |
119 { | |
120 return *layer_; | |
121 } | |
122 else | |
123 { | |
124 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
125 } | |
426 | 126 } |
408 | 127 |
410
6decc0ba9da5
rename RadiographyScene::Layer as RadiographyLayer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
409
diff
changeset
|
128 RadiographyLayer& RadiographyScene::RegisterLayer(RadiographyLayer* layer) |
408 | 129 { |
130 if (layer == NULL) | |
131 { | |
132 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); | |
133 } | |
134 | |
410
6decc0ba9da5
rename RadiographyScene::Layer as RadiographyLayer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
409
diff
changeset
|
135 std::auto_ptr<RadiographyLayer> raii(layer); |
426 | 136 |
428
751fb354149e
ability to change the scene of the RadiographyWidget
am@osimis.io
parents:
426
diff
changeset
|
137 LOG(INFO) << "Registering layer: " << countLayers_; |
751fb354149e
ability to change the scene of the RadiographyWidget
am@osimis.io
parents:
426
diff
changeset
|
138 |
408 | 139 size_t index = countLayers_++; |
140 raii->SetIndex(index); | |
141 layers_[index] = raii.release(); | |
142 | |
623
42dadae61fa9
renamed IObservable::EmitMessage() as BroadcastMessage()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
605
diff
changeset
|
143 BroadcastMessage(GeometryChangedMessage(*this, *layer)); |
42dadae61fa9
renamed IObservable::EmitMessage() as BroadcastMessage()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
605
diff
changeset
|
144 BroadcastMessage(ContentChangedMessage(*this, *layer)); |
503
77e0eb83ff63
layers are now Observable and emitting LayerEdited messages
amazy
parents:
488
diff
changeset
|
145 layer->RegisterObserverCallback(new Callable<RadiographyScene, RadiographyLayer::LayerEditedMessage>(*this, &RadiographyScene::OnLayerEdited)); |
408 | 146 |
147 return *layer; | |
148 } | |
426 | 149 |
876 | 150 size_t RadiographyScene::GetApproximateMemoryUsage() const |
151 { | |
152 size_t size = 0; | |
153 for (Layers::const_iterator it = layers_.begin(); it != layers_.end(); it++) | |
154 { | |
155 size += it->second->GetApproximateMemoryUsage(); | |
156 } | |
157 return size; | |
158 } | |
159 | |
503
77e0eb83ff63
layers are now Observable and emitting LayerEdited messages
amazy
parents:
488
diff
changeset
|
160 void RadiographyScene::OnLayerEdited(const RadiographyLayer::LayerEditedMessage& message) |
77e0eb83ff63
layers are now Observable and emitting LayerEdited messages
amazy
parents:
488
diff
changeset
|
161 { |
623
42dadae61fa9
renamed IObservable::EmitMessage() as BroadcastMessage()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
605
diff
changeset
|
162 BroadcastMessage(RadiographyScene::LayerEditedMessage(*this, message.GetOrigin())); |
503
77e0eb83ff63
layers are now Observable and emitting LayerEdited messages
amazy
parents:
488
diff
changeset
|
163 } |
408 | 164 |
417
aee3d7941c9b
preparing to load images using DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
412
diff
changeset
|
165 RadiographyScene::RadiographyScene(MessageBroker& broker) : |
408 | 166 IObserver(broker), |
167 IObservable(broker), | |
168 countLayers_(0), | |
169 hasWindowing_(false), | |
170 windowingCenter_(0), // Dummy initialization | |
171 windowingWidth_(0) // Dummy initialization | |
172 { | |
173 } | |
174 | |
175 | |
176 RadiographyScene::~RadiographyScene() | |
177 { | |
178 for (Layers::iterator it = layers_.begin(); it != layers_.end(); it++) | |
179 { | |
180 assert(it->second != NULL); | |
181 delete it->second; | |
182 } | |
183 } | |
184 | |
739
be9c1530d40a
deprecating enum SliceImageQuality
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
732
diff
changeset
|
185 RadiographyPhotometricDisplayMode RadiographyScene::GetPreferredPhotomotricDisplayMode() const |
432
4eb96c6b4e96
improved handling of MONOCHROME1, background and invertion
am@osimis.io
parents:
431
diff
changeset
|
186 { |
4eb96c6b4e96
improved handling of MONOCHROME1, background and invertion
am@osimis.io
parents:
431
diff
changeset
|
187 // return the mode of the first layer who "cares" about its display mode (normaly, the one and only layer that is a DicomLayer) |
4eb96c6b4e96
improved handling of MONOCHROME1, background and invertion
am@osimis.io
parents:
431
diff
changeset
|
188 for (Layers::const_iterator it = layers_.begin(); it != layers_.end(); it++) |
4eb96c6b4e96
improved handling of MONOCHROME1, background and invertion
am@osimis.io
parents:
431
diff
changeset
|
189 { |
739
be9c1530d40a
deprecating enum SliceImageQuality
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
732
diff
changeset
|
190 if (it->second->GetPreferredPhotomotricDisplayMode() != RadiographyPhotometricDisplayMode_Default) |
432
4eb96c6b4e96
improved handling of MONOCHROME1, background and invertion
am@osimis.io
parents:
431
diff
changeset
|
191 { |
4eb96c6b4e96
improved handling of MONOCHROME1, background and invertion
am@osimis.io
parents:
431
diff
changeset
|
192 return it->second->GetPreferredPhotomotricDisplayMode(); |
4eb96c6b4e96
improved handling of MONOCHROME1, background and invertion
am@osimis.io
parents:
431
diff
changeset
|
193 } |
4eb96c6b4e96
improved handling of MONOCHROME1, background and invertion
am@osimis.io
parents:
431
diff
changeset
|
194 } |
4eb96c6b4e96
improved handling of MONOCHROME1, background and invertion
am@osimis.io
parents:
431
diff
changeset
|
195 |
739
be9c1530d40a
deprecating enum SliceImageQuality
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
732
diff
changeset
|
196 return RadiographyPhotometricDisplayMode_Default; |
432
4eb96c6b4e96
improved handling of MONOCHROME1, background and invertion
am@osimis.io
parents:
431
diff
changeset
|
197 } |
4eb96c6b4e96
improved handling of MONOCHROME1, background and invertion
am@osimis.io
parents:
431
diff
changeset
|
198 |
4eb96c6b4e96
improved handling of MONOCHROME1, background and invertion
am@osimis.io
parents:
431
diff
changeset
|
199 |
430 | 200 void RadiographyScene::GetLayersIndexes(std::vector<size_t>& output) const |
201 { | |
202 for (Layers::const_iterator it = layers_.begin(); it != layers_.end(); it++) | |
203 { | |
204 output.push_back(it->first); | |
205 } | |
206 } | |
207 | |
425 | 208 void RadiographyScene::RemoveLayer(size_t layerIndex) |
209 { | |
428
751fb354149e
ability to change the scene of the RadiographyWidget
am@osimis.io
parents:
426
diff
changeset
|
210 LOG(INFO) << "Removing layer: " << layerIndex; |
751fb354149e
ability to change the scene of the RadiographyWidget
am@osimis.io
parents:
426
diff
changeset
|
211 |
571
a29f9628369e
fix build on visual studio 2008
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
553
diff
changeset
|
212 Layers::iterator found = layers_.find(layerIndex); |
a29f9628369e
fix build on visual studio 2008
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
553
diff
changeset
|
213 |
a29f9628369e
fix build on visual studio 2008
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
553
diff
changeset
|
214 if (found == layers_.end()) |
425 | 215 { |
216 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
217 } | |
571
a29f9628369e
fix build on visual studio 2008
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
553
diff
changeset
|
218 else |
a29f9628369e
fix build on visual studio 2008
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
553
diff
changeset
|
219 { |
a29f9628369e
fix build on visual studio 2008
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
553
diff
changeset
|
220 assert(found->second != NULL); |
a29f9628369e
fix build on visual studio 2008
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
553
diff
changeset
|
221 delete found->second; |
a29f9628369e
fix build on visual studio 2008
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
553
diff
changeset
|
222 |
a29f9628369e
fix build on visual studio 2008
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
553
diff
changeset
|
223 layers_.erase(found); |
a29f9628369e
fix build on visual studio 2008
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
553
diff
changeset
|
224 countLayers_--; |
a29f9628369e
fix build on visual studio 2008
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
553
diff
changeset
|
225 |
a29f9628369e
fix build on visual studio 2008
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
553
diff
changeset
|
226 LOG(INFO) << "Removing layer, there are now : " << countLayers_ << " layers"; |
a29f9628369e
fix build on visual studio 2008
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
553
diff
changeset
|
227 } |
425 | 228 } |
229 | |
430 | 230 const RadiographyLayer& RadiographyScene::GetLayer(size_t layerIndex) const |
425 | 231 { |
571
a29f9628369e
fix build on visual studio 2008
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
553
diff
changeset
|
232 Layers::const_iterator found = layers_.find(layerIndex); |
a29f9628369e
fix build on visual studio 2008
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
553
diff
changeset
|
233 |
a29f9628369e
fix build on visual studio 2008
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
553
diff
changeset
|
234 if (found == layers_.end()) |
425 | 235 { |
236 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
237 } | |
571
a29f9628369e
fix build on visual studio 2008
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
553
diff
changeset
|
238 else |
a29f9628369e
fix build on visual studio 2008
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
553
diff
changeset
|
239 { |
a29f9628369e
fix build on visual studio 2008
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
553
diff
changeset
|
240 assert(found->second != NULL); |
a29f9628369e
fix build on visual studio 2008
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
553
diff
changeset
|
241 return *found->second; |
a29f9628369e
fix build on visual studio 2008
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
553
diff
changeset
|
242 } |
425 | 243 } |
408 | 244 |
245 bool RadiographyScene::GetWindowing(float& center, | |
246 float& width) const | |
247 { | |
248 if (hasWindowing_) | |
249 { | |
250 center = windowingCenter_; | |
251 width = windowingWidth_; | |
252 return true; | |
253 } | |
254 else | |
255 { | |
256 return false; | |
257 } | |
258 } | |
259 | |
260 | |
261 void RadiographyScene::GetWindowingWithDefault(float& center, | |
262 float& width) const | |
263 { | |
264 if (!GetWindowing(center, width)) | |
265 { | |
266 center = 128; | |
267 width = 256; | |
268 } | |
269 } | |
270 | |
271 | |
272 void RadiographyScene::SetWindowing(float center, | |
273 float width) | |
274 { | |
275 hasWindowing_ = true; | |
276 windowingCenter_ = center; | |
277 windowingWidth_ = width; | |
503
77e0eb83ff63
layers are now Observable and emitting LayerEdited messages
amazy
parents:
488
diff
changeset
|
278 |
623
42dadae61fa9
renamed IObservable::EmitMessage() as BroadcastMessage()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
605
diff
changeset
|
279 BroadcastMessage(RadiographyScene::WindowingChangedMessage(*this)); |
408 | 280 } |
281 | |
282 | |
410
6decc0ba9da5
rename RadiographyScene::Layer as RadiographyLayer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
409
diff
changeset
|
283 RadiographyLayer& RadiographyScene::LoadText(const Orthanc::Font& font, |
430 | 284 const std::string& utf8, |
285 RadiographyLayer::Geometry* geometry) | |
408 | 286 { |
503
77e0eb83ff63
layers are now Observable and emitting LayerEdited messages
amazy
parents:
488
diff
changeset
|
287 std::auto_ptr<RadiographyTextLayer> alpha(new RadiographyTextLayer(IObservable::GetBroker(), *this)); |
408 | 288 alpha->LoadText(font, utf8); |
430 | 289 if (geometry != NULL) |
290 { | |
291 alpha->SetGeometry(*geometry); | |
292 } | |
408 | 293 |
294 return RegisterLayer(alpha.release()); | |
295 } | |
296 | |
426 | 297 |
410
6decc0ba9da5
rename RadiographyScene::Layer as RadiographyLayer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
409
diff
changeset
|
298 RadiographyLayer& RadiographyScene::LoadTestBlock(unsigned int width, |
430 | 299 unsigned int height, |
300 RadiographyLayer::Geometry* geometry) | |
408 | 301 { |
302 std::auto_ptr<Orthanc::Image> block(new Orthanc::Image(Orthanc::PixelFormat_Grayscale8, width, height, false)); | |
303 | |
304 for (unsigned int padding = 0; | |
305 (width > 2 * padding) && (height > 2 * padding); | |
306 padding++) | |
307 { | |
308 uint8_t color; | |
309 if (255 > 10 * padding) | |
310 { | |
311 color = 255 - 10 * padding; | |
312 } | |
313 else | |
314 { | |
315 color = 0; | |
316 } | |
317 | |
318 Orthanc::ImageAccessor region; | |
319 block->GetRegion(region, padding, padding, width - 2 * padding, height - 2 * padding); | |
320 Orthanc::ImageProcessing::Set(region, color); | |
321 } | |
322 | |
430 | 323 return LoadAlphaBitmap(block.release(), geometry); |
324 } | |
325 | |
488 | 326 RadiographyLayer& RadiographyScene::LoadMask(const std::vector<Orthanc::ImageProcessing::ImagePoint>& corners, |
475
3c28542229a3
added a mask layer in the RadiographyWidget (to be cleaned)
am@osimis.io
parents:
440
diff
changeset
|
327 const RadiographyDicomLayer& dicomLayer, |
3c28542229a3
added a mask layer in the RadiographyWidget (to be cleaned)
am@osimis.io
parents:
440
diff
changeset
|
328 float foreground, |
3c28542229a3
added a mask layer in the RadiographyWidget (to be cleaned)
am@osimis.io
parents:
440
diff
changeset
|
329 RadiographyLayer::Geometry* geometry) |
3c28542229a3
added a mask layer in the RadiographyWidget (to be cleaned)
am@osimis.io
parents:
440
diff
changeset
|
330 { |
503
77e0eb83ff63
layers are now Observable and emitting LayerEdited messages
amazy
parents:
488
diff
changeset
|
331 std::auto_ptr<RadiographyMaskLayer> mask(new RadiographyMaskLayer(IObservable::GetBroker(), *this, dicomLayer, foreground)); |
475
3c28542229a3
added a mask layer in the RadiographyWidget (to be cleaned)
am@osimis.io
parents:
440
diff
changeset
|
332 mask->SetCorners(corners); |
3c28542229a3
added a mask layer in the RadiographyWidget (to be cleaned)
am@osimis.io
parents:
440
diff
changeset
|
333 if (geometry != NULL) |
3c28542229a3
added a mask layer in the RadiographyWidget (to be cleaned)
am@osimis.io
parents:
440
diff
changeset
|
334 { |
3c28542229a3
added a mask layer in the RadiographyWidget (to be cleaned)
am@osimis.io
parents:
440
diff
changeset
|
335 mask->SetGeometry(*geometry); |
3c28542229a3
added a mask layer in the RadiographyWidget (to be cleaned)
am@osimis.io
parents:
440
diff
changeset
|
336 } |
3c28542229a3
added a mask layer in the RadiographyWidget (to be cleaned)
am@osimis.io
parents:
440
diff
changeset
|
337 |
3c28542229a3
added a mask layer in the RadiographyWidget (to be cleaned)
am@osimis.io
parents:
440
diff
changeset
|
338 return RegisterLayer(mask.release()); |
3c28542229a3
added a mask layer in the RadiographyWidget (to be cleaned)
am@osimis.io
parents:
440
diff
changeset
|
339 } |
3c28542229a3
added a mask layer in the RadiographyWidget (to be cleaned)
am@osimis.io
parents:
440
diff
changeset
|
340 |
3c28542229a3
added a mask layer in the RadiographyWidget (to be cleaned)
am@osimis.io
parents:
440
diff
changeset
|
341 |
430 | 342 RadiographyLayer& RadiographyScene::LoadAlphaBitmap(Orthanc::ImageAccessor* bitmap, RadiographyLayer::Geometry *geometry) |
343 { | |
503
77e0eb83ff63
layers are now Observable and emitting LayerEdited messages
amazy
parents:
488
diff
changeset
|
344 std::auto_ptr<RadiographyAlphaLayer> alpha(new RadiographyAlphaLayer(IObservable::GetBroker(), *this)); |
430 | 345 alpha->SetAlpha(bitmap); |
346 if (geometry != NULL) | |
347 { | |
348 alpha->SetGeometry(*geometry); | |
349 } | |
408 | 350 |
351 return RegisterLayer(alpha.release()); | |
352 } | |
353 | |
553
92305ee35b1c
web-worker consequences: give access to lower level data
Alain Mazy <alain@mazy.be>
parents:
541
diff
changeset
|
354 RadiographyLayer& RadiographyScene::LoadDicomImage(Orthanc::ImageAccessor* dicomImage, // takes ownership |
92305ee35b1c
web-worker consequences: give access to lower level data
Alain Mazy <alain@mazy.be>
parents:
541
diff
changeset
|
355 const std::string& instance, |
92305ee35b1c
web-worker consequences: give access to lower level data
Alain Mazy <alain@mazy.be>
parents:
541
diff
changeset
|
356 unsigned int frame, |
714
d2c0e347ddc2
deprecating DicomFrameConverter
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
623
diff
changeset
|
357 Deprecated::DicomFrameConverter* converter, // takes ownership |
739
be9c1530d40a
deprecating enum SliceImageQuality
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
732
diff
changeset
|
358 RadiographyPhotometricDisplayMode preferredPhotometricDisplayMode, |
553
92305ee35b1c
web-worker consequences: give access to lower level data
Alain Mazy <alain@mazy.be>
parents:
541
diff
changeset
|
359 RadiographyLayer::Geometry* geometry) |
92305ee35b1c
web-worker consequences: give access to lower level data
Alain Mazy <alain@mazy.be>
parents:
541
diff
changeset
|
360 { |
92305ee35b1c
web-worker consequences: give access to lower level data
Alain Mazy <alain@mazy.be>
parents:
541
diff
changeset
|
361 RadiographyDicomLayer& layer = dynamic_cast<RadiographyDicomLayer&>(RegisterLayer(new RadiographyDicomLayer(IObservable::GetBroker(), *this))); |
92305ee35b1c
web-worker consequences: give access to lower level data
Alain Mazy <alain@mazy.be>
parents:
541
diff
changeset
|
362 |
92305ee35b1c
web-worker consequences: give access to lower level data
Alain Mazy <alain@mazy.be>
parents:
541
diff
changeset
|
363 layer.SetInstance(instance, frame); |
92305ee35b1c
web-worker consequences: give access to lower level data
Alain Mazy <alain@mazy.be>
parents:
541
diff
changeset
|
364 |
92305ee35b1c
web-worker consequences: give access to lower level data
Alain Mazy <alain@mazy.be>
parents:
541
diff
changeset
|
365 if (geometry != NULL) |
92305ee35b1c
web-worker consequences: give access to lower level data
Alain Mazy <alain@mazy.be>
parents:
541
diff
changeset
|
366 { |
92305ee35b1c
web-worker consequences: give access to lower level data
Alain Mazy <alain@mazy.be>
parents:
541
diff
changeset
|
367 layer.SetGeometry(*geometry); |
92305ee35b1c
web-worker consequences: give access to lower level data
Alain Mazy <alain@mazy.be>
parents:
541
diff
changeset
|
368 } |
92305ee35b1c
web-worker consequences: give access to lower level data
Alain Mazy <alain@mazy.be>
parents:
541
diff
changeset
|
369 |
92305ee35b1c
web-worker consequences: give access to lower level data
Alain Mazy <alain@mazy.be>
parents:
541
diff
changeset
|
370 layer.SetDicomFrameConverter(converter); |
92305ee35b1c
web-worker consequences: give access to lower level data
Alain Mazy <alain@mazy.be>
parents:
541
diff
changeset
|
371 layer.SetSourceImage(dicomImage); |
92305ee35b1c
web-worker consequences: give access to lower level data
Alain Mazy <alain@mazy.be>
parents:
541
diff
changeset
|
372 layer.SetPreferredPhotomotricDisplayMode(preferredPhotometricDisplayMode); |
92305ee35b1c
web-worker consequences: give access to lower level data
Alain Mazy <alain@mazy.be>
parents:
541
diff
changeset
|
373 |
92305ee35b1c
web-worker consequences: give access to lower level data
Alain Mazy <alain@mazy.be>
parents:
541
diff
changeset
|
374 return layer; |
587 | 375 } |
553
92305ee35b1c
web-worker consequences: give access to lower level data
Alain Mazy <alain@mazy.be>
parents:
541
diff
changeset
|
376 |
726
4f2416d519b4
moving layers, widgets and loaders to Deprecated namespace
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
714
diff
changeset
|
377 RadiographyLayer& RadiographyScene::LoadDicomFrame(Deprecated::OrthancApiClient& orthanc, |
417
aee3d7941c9b
preparing to load images using DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
412
diff
changeset
|
378 const std::string& instance, |
410
6decc0ba9da5
rename RadiographyScene::Layer as RadiographyLayer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
409
diff
changeset
|
379 unsigned int frame, |
430 | 380 bool httpCompression, |
381 RadiographyLayer::Geometry* geometry) | |
408 | 382 { |
503
77e0eb83ff63
layers are now Observable and emitting LayerEdited messages
amazy
parents:
488
diff
changeset
|
383 RadiographyDicomLayer& layer = dynamic_cast<RadiographyDicomLayer&>(RegisterLayer(new RadiographyDicomLayer(IObservable::GetBroker(), *this))); |
430 | 384 layer.SetInstance(instance, frame); |
385 | |
386 if (geometry != NULL) | |
387 { | |
388 layer.SetGeometry(*geometry); | |
389 } | |
408 | 390 |
391 { | |
726
4f2416d519b4
moving layers, widgets and loaders to Deprecated namespace
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
714
diff
changeset
|
392 Deprecated::IWebService::HttpHeaders headers; |
408 | 393 std::string uri = "/instances/" + instance + "/tags"; |
426 | 394 |
417
aee3d7941c9b
preparing to load images using DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
412
diff
changeset
|
395 orthanc.GetBinaryAsync( |
426 | 396 uri, headers, |
726
4f2416d519b4
moving layers, widgets and loaders to Deprecated namespace
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
714
diff
changeset
|
397 new Callable<RadiographyScene, Deprecated::OrthancApiClient::BinaryResponseReadyMessage> |
426 | 398 (*this, &RadiographyScene::OnTagsReceived), NULL, |
399 new Orthanc::SingleValueObject<size_t>(layer.GetIndex())); | |
408 | 400 } |
401 | |
402 { | |
726
4f2416d519b4
moving layers, widgets and loaders to Deprecated namespace
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
714
diff
changeset
|
403 Deprecated::IWebService::HttpHeaders headers; |
408 | 404 headers["Accept"] = "image/x-portable-arbitrarymap"; |
405 | |
406 if (httpCompression) | |
407 { | |
408 headers["Accept-Encoding"] = "gzip"; | |
409 } | |
426 | 410 |
408 | 411 std::string uri = ("/instances/" + instance + "/frames/" + |
412 boost::lexical_cast<std::string>(frame) + "/image-uint16"); | |
426 | 413 |
417
aee3d7941c9b
preparing to load images using DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
412
diff
changeset
|
414 orthanc.GetBinaryAsync( |
426 | 415 uri, headers, |
726
4f2416d519b4
moving layers, widgets and loaders to Deprecated namespace
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
714
diff
changeset
|
416 new Callable<RadiographyScene, Deprecated::OrthancApiClient::BinaryResponseReadyMessage> |
426 | 417 (*this, &RadiographyScene::OnFrameReceived), NULL, |
418 new Orthanc::SingleValueObject<size_t>(layer.GetIndex())); | |
408 | 419 } |
420 | |
421 return layer; | |
422 } | |
423 | |
417
aee3d7941c9b
preparing to load images using DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
412
diff
changeset
|
424 |
726
4f2416d519b4
moving layers, widgets and loaders to Deprecated namespace
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
714
diff
changeset
|
425 RadiographyLayer& RadiographyScene::LoadDicomWebFrame(Deprecated::IWebService& web) |
417
aee3d7941c9b
preparing to load images using DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
412
diff
changeset
|
426 { |
503
77e0eb83ff63
layers are now Observable and emitting LayerEdited messages
amazy
parents:
488
diff
changeset
|
427 RadiographyLayer& layer = RegisterLayer(new RadiographyDicomLayer(IObservable::GetBroker(), *this)); |
417
aee3d7941c9b
preparing to load images using DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
412
diff
changeset
|
428 |
426 | 429 |
417
aee3d7941c9b
preparing to load images using DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
412
diff
changeset
|
430 return layer; |
aee3d7941c9b
preparing to load images using DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
412
diff
changeset
|
431 } |
aee3d7941c9b
preparing to load images using DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
412
diff
changeset
|
432 |
aee3d7941c9b
preparing to load images using DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
412
diff
changeset
|
433 |
426 | 434 |
726
4f2416d519b4
moving layers, widgets and loaders to Deprecated namespace
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
714
diff
changeset
|
435 void RadiographyScene::OnTagsReceived(const Deprecated::OrthancApiClient::BinaryResponseReadyMessage& message) |
408 | 436 { |
437 size_t index = dynamic_cast<const Orthanc::SingleValueObject<size_t>&> | |
426 | 438 (message.GetPayload()).GetValue(); |
408 | 439 |
440 LOG(INFO) << "JSON received: " << message.GetUri().c_str() | |
441 << " (" << message.GetAnswerSize() << " bytes) for layer " << index; | |
426 | 442 |
408 | 443 Layers::iterator layer = layers_.find(index); |
444 if (layer != layers_.end()) | |
445 { | |
446 assert(layer->second != NULL); | |
426 | 447 |
408 | 448 OrthancPlugins::FullOrthancDataset dicom(message.GetAnswer(), message.GetAnswerSize()); |
430 | 449 dynamic_cast<RadiographyDicomLayer*>(layer->second)->SetDicomTags(dicom); |
408 | 450 |
451 float c, w; | |
452 if (!hasWindowing_ && | |
453 layer->second->GetDefaultWindowing(c, w)) | |
454 { | |
455 hasWindowing_ = true; | |
456 windowingCenter_ = c; | |
457 windowingWidth_ = w; | |
458 } | |
459 | |
623
42dadae61fa9
renamed IObservable::EmitMessage() as BroadcastMessage()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
605
diff
changeset
|
460 BroadcastMessage(GeometryChangedMessage(*this, *(layer->second))); |
408 | 461 } |
462 } | |
426 | 463 |
408 | 464 |
726
4f2416d519b4
moving layers, widgets and loaders to Deprecated namespace
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
714
diff
changeset
|
465 void RadiographyScene::OnFrameReceived(const Deprecated::OrthancApiClient::BinaryResponseReadyMessage& message) |
408 | 466 { |
467 size_t index = dynamic_cast<const Orthanc::SingleValueObject<size_t>&>(message.GetPayload()).GetValue(); | |
426 | 468 |
408 | 469 LOG(INFO) << "DICOM frame received: " << message.GetUri().c_str() |
470 << " (" << message.GetAnswerSize() << " bytes) for layer " << index; | |
426 | 471 |
408 | 472 Layers::iterator layer = layers_.find(index); |
473 if (layer != layers_.end()) | |
474 { | |
475 assert(layer->second != NULL); | |
476 | |
477 std::string content; | |
478 if (message.GetAnswerSize() > 0) | |
479 { | |
480 content.assign(reinterpret_cast<const char*>(message.GetAnswer()), message.GetAnswerSize()); | |
481 } | |
426 | 482 |
408 | 483 std::auto_ptr<Orthanc::PamReader> reader(new Orthanc::PamReader); |
484 reader->ReadFromMemory(content); | |
430 | 485 dynamic_cast<RadiographyDicomLayer*>(layer->second)->SetSourceImage(reader.release()); |
408 | 486 |
623
42dadae61fa9
renamed IObservable::EmitMessage() as BroadcastMessage()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
605
diff
changeset
|
487 BroadcastMessage(ContentChangedMessage(*this, *(layer->second))); |
408 | 488 } |
489 } | |
490 | |
491 | |
492 Extent2D RadiographyScene::GetSceneExtent() const | |
493 { | |
494 Extent2D extent; | |
495 | |
496 for (Layers::const_iterator it = layers_.begin(); | |
497 it != layers_.end(); ++it) | |
498 { | |
499 assert(it->second != NULL); | |
500 extent.Union(it->second->GetExtent()); | |
501 } | |
502 | |
503 return extent; | |
504 } | |
426 | 505 |
408 | 506 |
507 void RadiographyScene::Render(Orthanc::ImageAccessor& buffer, | |
409 | 508 const AffineTransform2D& viewTransform, |
408 | 509 ImageInterpolation interpolation) const |
510 { | |
511 // Render layers in the background-to-foreground order | |
512 for (size_t index = 0; index < countLayers_; index++) | |
513 { | |
514 Layers::const_iterator it = layers_.find(index); | |
515 if (it != layers_.end()) | |
516 { | |
517 assert(it->second != NULL); | |
518 it->second->Render(buffer, viewTransform, interpolation); | |
519 } | |
520 } | |
521 } | |
522 | |
523 | |
524 bool RadiographyScene::LookupLayer(size_t& index /* out */, | |
525 double x, | |
526 double y) const | |
527 { | |
528 // Render layers in the foreground-to-background order | |
529 for (size_t i = countLayers_; i > 0; i--) | |
530 { | |
531 index = i - 1; | |
532 Layers::const_iterator it = layers_.find(index); | |
533 if (it != layers_.end()) | |
534 { | |
535 assert(it->second != NULL); | |
536 if (it->second->Contains(x, y)) | |
537 { | |
538 return true; | |
539 } | |
540 } | |
541 } | |
542 | |
543 return false; | |
544 } | |
545 | |
426 | 546 |
408 | 547 void RadiographyScene::DrawBorder(CairoContext& context, |
548 unsigned int layer, | |
549 double zoom) | |
550 { | |
551 Layers::const_iterator found = layers_.find(layer); | |
426 | 552 |
408 | 553 if (found != layers_.end()) |
554 { | |
555 context.SetSourceColor(255, 0, 0); | |
556 found->second->DrawBorders(context, zoom); | |
557 } | |
558 } | |
559 | |
560 | |
561 void RadiographyScene::GetRange(float& minValue, | |
562 float& maxValue) const | |
563 { | |
564 bool first = true; | |
426 | 565 |
408 | 566 for (Layers::const_iterator it = layers_.begin(); |
567 it != layers_.end(); it++) | |
568 { | |
569 assert(it->second != NULL); | |
570 | |
571 float a, b; | |
572 if (it->second->GetRange(a, b)) | |
573 { | |
574 if (first) | |
575 { | |
576 minValue = a; | |
577 maxValue = b; | |
578 first = false; | |
579 } | |
580 else | |
581 { | |
582 minValue = std::min(a, minValue); | |
583 maxValue = std::max(b, maxValue); | |
584 } | |
585 } | |
586 } | |
587 | |
588 if (first) | |
589 { | |
590 minValue = 0; | |
591 maxValue = 0; | |
592 } | |
593 } | |
594 | |
481
159a465e27bd
reworked RadiographyScene export to export to an Orthanc::Image too
am@osimis.io
parents:
475
diff
changeset
|
595 Orthanc::Image* RadiographyScene::ExportToImage(double pixelSpacingX, |
159a465e27bd
reworked RadiographyScene export to export to an Orthanc::Image too
am@osimis.io
parents:
475
diff
changeset
|
596 double pixelSpacingY, |
159a465e27bd
reworked RadiographyScene export to export to an Orthanc::Image too
am@osimis.io
parents:
475
diff
changeset
|
597 ImageInterpolation interpolation, |
159a465e27bd
reworked RadiographyScene export to export to an Orthanc::Image too
am@osimis.io
parents:
475
diff
changeset
|
598 bool invert, |
159a465e27bd
reworked RadiographyScene export to export to an Orthanc::Image too
am@osimis.io
parents:
475
diff
changeset
|
599 int64_t maxValue /* for inversion */) |
426 | 600 { |
408 | 601 if (pixelSpacingX <= 0 || |
602 pixelSpacingY <= 0) | |
603 { | |
604 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
605 } | |
426 | 606 |
408 | 607 Extent2D extent = GetSceneExtent(); |
608 | |
928
1b49e78d91d0
fix for older compilers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
923
diff
changeset
|
609 int w = boost::math::iround(extent.GetWidth() / pixelSpacingX); |
1b49e78d91d0
fix for older compilers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
923
diff
changeset
|
610 int h = boost::math::iround(extent.GetHeight() / pixelSpacingY); |
408 | 611 |
612 if (w < 0 || h < 0) | |
613 { | |
614 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
615 } | |
616 | |
617 Orthanc::Image layers(Orthanc::PixelFormat_Float32, | |
618 static_cast<unsigned int>(w), | |
619 static_cast<unsigned int>(h), false); | |
620 | |
409 | 621 AffineTransform2D view = AffineTransform2D::Combine( |
426 | 622 AffineTransform2D::CreateScaling(1.0 / pixelSpacingX, 1.0 / pixelSpacingY), |
623 AffineTransform2D::CreateOffset(-extent.GetX1(), -extent.GetY1())); | |
624 | |
432
4eb96c6b4e96
improved handling of MONOCHROME1, background and invertion
am@osimis.io
parents:
431
diff
changeset
|
625 // wipe background before rendering |
4eb96c6b4e96
improved handling of MONOCHROME1, background and invertion
am@osimis.io
parents:
431
diff
changeset
|
626 Orthanc::ImageProcessing::Set(layers, 0); |
4eb96c6b4e96
improved handling of MONOCHROME1, background and invertion
am@osimis.io
parents:
431
diff
changeset
|
627 |
408 | 628 Render(layers, view, interpolation); |
629 | |
481
159a465e27bd
reworked RadiographyScene export to export to an Orthanc::Image too
am@osimis.io
parents:
475
diff
changeset
|
630 std::auto_ptr<Orthanc::Image> rendered(new Orthanc::Image(Orthanc::PixelFormat_Grayscale16, |
553
92305ee35b1c
web-worker consequences: give access to lower level data
Alain Mazy <alain@mazy.be>
parents:
541
diff
changeset
|
631 layers.GetWidth(), layers.GetHeight(), false)); |
481
159a465e27bd
reworked RadiographyScene export to export to an Orthanc::Image too
am@osimis.io
parents:
475
diff
changeset
|
632 |
159a465e27bd
reworked RadiographyScene export to export to an Orthanc::Image too
am@osimis.io
parents:
475
diff
changeset
|
633 Orthanc::ImageProcessing::Convert(*rendered, layers); |
159a465e27bd
reworked RadiographyScene export to export to an Orthanc::Image too
am@osimis.io
parents:
475
diff
changeset
|
634 if (invert) |
159a465e27bd
reworked RadiographyScene export to export to an Orthanc::Image too
am@osimis.io
parents:
475
diff
changeset
|
635 Orthanc::ImageProcessing::Invert(*rendered, maxValue); |
159a465e27bd
reworked RadiographyScene export to export to an Orthanc::Image too
am@osimis.io
parents:
475
diff
changeset
|
636 |
159a465e27bd
reworked RadiographyScene export to export to an Orthanc::Image too
am@osimis.io
parents:
475
diff
changeset
|
637 return rendered.release(); |
159a465e27bd
reworked RadiographyScene export to export to an Orthanc::Image too
am@osimis.io
parents:
475
diff
changeset
|
638 } |
159a465e27bd
reworked RadiographyScene export to export to an Orthanc::Image too
am@osimis.io
parents:
475
diff
changeset
|
639 |
159a465e27bd
reworked RadiographyScene export to export to an Orthanc::Image too
am@osimis.io
parents:
475
diff
changeset
|
640 |
587 | 641 Orthanc::Image* RadiographyScene::ExportToCreateDicomRequestAndImage(Json::Value& createDicomRequestContent, |
642 const Json::Value& dicomTags, | |
643 const std::string& parentOrthancId, | |
644 double pixelSpacingX, | |
645 double pixelSpacingY, | |
646 bool invert, | |
647 ImageInterpolation interpolation) | |
481
159a465e27bd
reworked RadiographyScene export to export to an Orthanc::Image too
am@osimis.io
parents:
475
diff
changeset
|
648 { |
541 | 649 LOG(INFO) << "Exporting RadiographyScene to DICOM"; |
650 | |
481
159a465e27bd
reworked RadiographyScene export to export to an Orthanc::Image too
am@osimis.io
parents:
475
diff
changeset
|
651 std::auto_ptr<Orthanc::Image> rendered(ExportToImage(pixelSpacingX, pixelSpacingY, interpolation)); // note: we don't invert the image in the pixels data because we'll set the PhotometricDisplayMode correctly in the DICOM tags |
408 | 652 |
483 | 653 createDicomRequestContent["Tags"] = dicomTags; |
408 | 654 |
739
be9c1530d40a
deprecating enum SliceImageQuality
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
732
diff
changeset
|
655 RadiographyPhotometricDisplayMode photometricMode = GetPreferredPhotomotricDisplayMode(); |
be9c1530d40a
deprecating enum SliceImageQuality
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
732
diff
changeset
|
656 if ((invert && photometricMode != RadiographyPhotometricDisplayMode_Monochrome2) || |
be9c1530d40a
deprecating enum SliceImageQuality
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
732
diff
changeset
|
657 (!invert && photometricMode == RadiographyPhotometricDisplayMode_Monochrome1)) |
436
04711a2e12cd
fix crop + export photometric interpretation correctly
am@osimis.io
parents:
432
diff
changeset
|
658 { |
483 | 659 createDicomRequestContent["Tags"]["PhotometricInterpretation"] = "MONOCHROME1"; |
436
04711a2e12cd
fix crop + export photometric interpretation correctly
am@osimis.io
parents:
432
diff
changeset
|
660 } |
04711a2e12cd
fix crop + export photometric interpretation correctly
am@osimis.io
parents:
432
diff
changeset
|
661 else |
04711a2e12cd
fix crop + export photometric interpretation correctly
am@osimis.io
parents:
432
diff
changeset
|
662 { |
483 | 663 createDicomRequestContent["Tags"]["PhotometricInterpretation"] = "MONOCHROME2"; |
436
04711a2e12cd
fix crop + export photometric interpretation correctly
am@osimis.io
parents:
432
diff
changeset
|
664 } |
408 | 665 |
666 // WARNING: The order of PixelSpacing is Y/X. We use "%0.8f" to | |
667 // avoid floating-point numbers to grow over 16 characters, | |
668 // which would be invalid according to DICOM standard | |
669 // ("dciodvfy" would complain). | |
670 char buf[32]; | |
671 sprintf(buf, "%0.8f\\%0.8f", pixelSpacingY, pixelSpacingX); | |
426 | 672 |
483 | 673 createDicomRequestContent["Tags"]["PixelSpacing"] = buf; |
408 | 674 |
675 float center, width; | |
676 if (GetWindowing(center, width)) | |
677 { | |
483 | 678 createDicomRequestContent["Tags"]["WindowCenter"] = |
426 | 679 boost::lexical_cast<std::string>(boost::math::iround(center)); |
408 | 680 |
483 | 681 createDicomRequestContent["Tags"]["WindowWidth"] = |
426 | 682 boost::lexical_cast<std::string>(boost::math::iround(width)); |
408 | 683 } |
684 | |
587 | 685 if (!parentOrthancId.empty()) |
686 { | |
687 createDicomRequestContent["Parent"] = parentOrthancId; | |
688 } | |
689 | |
690 return rendered.release(); | |
691 } | |
692 | |
693 | |
694 void RadiographyScene::ExportToCreateDicomRequest(Json::Value& createDicomRequestContent, | |
695 const Json::Value& dicomTags, | |
696 const std::string& parentOrthancId, | |
697 double pixelSpacingX, | |
698 double pixelSpacingY, | |
699 bool invert, | |
700 ImageInterpolation interpolation, | |
701 bool usePam) | |
702 { | |
703 LOG(INFO) << "Exporting RadiographyScene to DICOM"; | |
704 VLOG(1) << "Exporting RadiographyScene to: export to image"; | |
705 | |
706 std::auto_ptr<Orthanc::Image> rendered(ExportToCreateDicomRequestAndImage(createDicomRequestContent, dicomTags, parentOrthancId, pixelSpacingX, pixelSpacingY, invert, interpolation)); | |
707 | |
708 // convert the image into base64 for inclusing in the createDicomRequest | |
709 std::string base64; | |
710 | |
711 { | |
712 std::string content; | |
713 | |
714 if (usePam) | |
715 { | |
716 VLOG(1) << "Exporting RadiographyScene: convert to PAM"; | |
717 Orthanc::PamWriter writer; | |
718 writer.WriteToMemory(content, *rendered); | |
719 } | |
720 else | |
721 { | |
722 Orthanc::PngWriter writer; | |
723 writer.WriteToMemory(content, *rendered); | |
724 } | |
725 | |
726 VLOG(1) << "Exporting RadiographyScene: encoding to base64"; | |
727 Orthanc::Toolbox::EncodeBase64(base64, content); | |
728 } | |
426 | 729 |
408 | 730 // This is Data URI scheme: https://en.wikipedia.org/wiki/Data_URI_scheme |
426 | 731 createDicomRequestContent["Content"] = ("data:" + |
732 std::string(usePam ? Orthanc::MIME_PAM : Orthanc::MIME_PNG) + | |
733 ";base64," + base64); | |
481
159a465e27bd
reworked RadiographyScene export to export to an Orthanc::Image too
am@osimis.io
parents:
475
diff
changeset
|
734 |
541 | 735 VLOG(1) << "Exporting RadiographyScene: create-dicom request is ready"; |
484
7bf001b9d244
re-added ExportToCreateDicomRequest
Alain Mazy <alain@mazy.be>
parents:
483
diff
changeset
|
736 } |
7bf001b9d244
re-added ExportToCreateDicomRequest
Alain Mazy <alain@mazy.be>
parents:
483
diff
changeset
|
737 |
7bf001b9d244
re-added ExportToCreateDicomRequest
Alain Mazy <alain@mazy.be>
parents:
483
diff
changeset
|
738 |
726
4f2416d519b4
moving layers, widgets and loaders to Deprecated namespace
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
714
diff
changeset
|
739 void RadiographyScene::ExportDicom(Deprecated::OrthancApiClient& orthanc, |
484
7bf001b9d244
re-added ExportToCreateDicomRequest
Alain Mazy <alain@mazy.be>
parents:
483
diff
changeset
|
740 const Json::Value& dicomTags, |
7bf001b9d244
re-added ExportToCreateDicomRequest
Alain Mazy <alain@mazy.be>
parents:
483
diff
changeset
|
741 const std::string& parentOrthancId, |
7bf001b9d244
re-added ExportToCreateDicomRequest
Alain Mazy <alain@mazy.be>
parents:
483
diff
changeset
|
742 double pixelSpacingX, |
7bf001b9d244
re-added ExportToCreateDicomRequest
Alain Mazy <alain@mazy.be>
parents:
483
diff
changeset
|
743 double pixelSpacingY, |
7bf001b9d244
re-added ExportToCreateDicomRequest
Alain Mazy <alain@mazy.be>
parents:
483
diff
changeset
|
744 bool invert, |
7bf001b9d244
re-added ExportToCreateDicomRequest
Alain Mazy <alain@mazy.be>
parents:
483
diff
changeset
|
745 ImageInterpolation interpolation, |
7bf001b9d244
re-added ExportToCreateDicomRequest
Alain Mazy <alain@mazy.be>
parents:
483
diff
changeset
|
746 bool usePam) |
7bf001b9d244
re-added ExportToCreateDicomRequest
Alain Mazy <alain@mazy.be>
parents:
483
diff
changeset
|
747 { |
7bf001b9d244
re-added ExportToCreateDicomRequest
Alain Mazy <alain@mazy.be>
parents:
483
diff
changeset
|
748 Json::Value createDicomRequestContent; |
7bf001b9d244
re-added ExportToCreateDicomRequest
Alain Mazy <alain@mazy.be>
parents:
483
diff
changeset
|
749 |
7bf001b9d244
re-added ExportToCreateDicomRequest
Alain Mazy <alain@mazy.be>
parents:
483
diff
changeset
|
750 ExportToCreateDicomRequest(createDicomRequestContent, dicomTags, parentOrthancId, pixelSpacingX, pixelSpacingY, invert, interpolation, usePam); |
7bf001b9d244
re-added ExportToCreateDicomRequest
Alain Mazy <alain@mazy.be>
parents:
483
diff
changeset
|
751 |
481
159a465e27bd
reworked RadiographyScene export to export to an Orthanc::Image too
am@osimis.io
parents:
475
diff
changeset
|
752 orthanc.PostJsonAsyncExpectJson( |
159a465e27bd
reworked RadiographyScene export to export to an Orthanc::Image too
am@osimis.io
parents:
475
diff
changeset
|
753 "/tools/create-dicom", createDicomRequestContent, |
726
4f2416d519b4
moving layers, widgets and loaders to Deprecated namespace
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
714
diff
changeset
|
754 new Callable<RadiographyScene, Deprecated::OrthancApiClient::JsonResponseReadyMessage> |
481
159a465e27bd
reworked RadiographyScene export to export to an Orthanc::Image too
am@osimis.io
parents:
475
diff
changeset
|
755 (*this, &RadiographyScene::OnDicomExported), |
159a465e27bd
reworked RadiographyScene export to export to an Orthanc::Image too
am@osimis.io
parents:
475
diff
changeset
|
756 NULL, NULL); |
483 | 757 |
758 } | |
759 | |
760 | |
761 // Export using PAM is faster than using PNG, but requires Orthanc | |
762 // core >= 1.4.3 | |
726
4f2416d519b4
moving layers, widgets and loaders to Deprecated namespace
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
714
diff
changeset
|
763 void RadiographyScene::ExportDicom(Deprecated::OrthancApiClient& orthanc, |
483 | 764 const Orthanc::DicomMap& dicom, |
765 const std::string& parentOrthancId, | |
766 double pixelSpacingX, | |
767 double pixelSpacingY, | |
768 bool invert, | |
769 ImageInterpolation interpolation, | |
770 bool usePam) | |
771 { | |
772 std::set<Orthanc::DicomTag> tags; | |
773 dicom.GetTags(tags); | |
774 | |
775 Json::Value jsonTags = Json::objectValue; | |
776 | |
777 for (std::set<Orthanc::DicomTag>::const_iterator | |
778 tag = tags.begin(); tag != tags.end(); ++tag) | |
779 { | |
780 const Orthanc::DicomValue& value = dicom.GetValue(*tag); | |
781 if (!value.IsNull() && | |
782 !value.IsBinary()) | |
783 { | |
784 jsonTags[tag->Format()] = value.GetContent(); | |
785 } | |
786 } | |
787 | |
788 ExportDicom(orthanc, jsonTags, parentOrthancId, pixelSpacingX, pixelSpacingY, invert, interpolation, usePam); | |
408 | 789 } |
790 | |
726
4f2416d519b4
moving layers, widgets and loaders to Deprecated namespace
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
714
diff
changeset
|
791 void RadiographyScene::OnDicomExported(const Deprecated::OrthancApiClient::JsonResponseReadyMessage& message) |
408 | 792 { |
417
aee3d7941c9b
preparing to load images using DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
412
diff
changeset
|
793 LOG(INFO) << "DICOM export was successful: " |
408 | 794 << message.GetJson().toStyledString(); |
795 } | |
417
aee3d7941c9b
preparing to load images using DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
412
diff
changeset
|
796 |
aee3d7941c9b
preparing to load images using DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
412
diff
changeset
|
797 |
726
4f2416d519b4
moving layers, widgets and loaders to Deprecated namespace
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
714
diff
changeset
|
798 void RadiographyScene::OnDicomWebReceived(const Deprecated::IWebService::HttpRequestSuccessMessage& message) |
417
aee3d7941c9b
preparing to load images using DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
412
diff
changeset
|
799 { |
aee3d7941c9b
preparing to load images using DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
412
diff
changeset
|
800 LOG(INFO) << "DICOMweb WADO-RS received: " << message.GetAnswerSize() << " bytes"; |
418 | 801 |
726
4f2416d519b4
moving layers, widgets and loaders to Deprecated namespace
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
714
diff
changeset
|
802 const Deprecated::IWebService::HttpHeaders& h = message.GetAnswerHttpHeaders(); |
4f2416d519b4
moving layers, widgets and loaders to Deprecated namespace
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
714
diff
changeset
|
803 for (Deprecated::IWebService::HttpHeaders::const_iterator |
426 | 804 it = h.begin(); it != h.end(); ++it) |
418 | 805 { |
806 printf("[%s] = [%s]\n", it->first.c_str(), it->second.c_str()); | |
807 } | |
417
aee3d7941c9b
preparing to load images using DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
412
diff
changeset
|
808 } |
aee3d7941c9b
preparing to load images using DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
412
diff
changeset
|
809 |
408 | 810 } |