comparison Samples/Deprecated/Sdl/Loader.cpp @ 1348:eac254fb6791 broker

Moved Application/Samples/* to Application/Samples/Deprecated/* (remaining) + moved Samples/* to Samples/Deprecated/*
author Benjamin Golinvaux <bgo@osimis.io>
date Tue, 07 Apr 2020 14:31:28 +0200
parents Samples/Sdl/Loader.cpp@8a0a62189f46
children
comparison
equal deleted inserted replaced
1347:bfd77672d825 1348:eac254fb6791
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 "../../Framework/Loaders/DicomStructureSetLoader.h"
23 #include "../../Framework/Loaders/OrthancMultiframeVolumeLoader.h"
24 #include "../../Framework/Loaders/OrthancSeriesVolumeProgressiveLoader.h"
25 #include "../../Framework/Oracle/SleepOracleCommand.h"
26 #include "../../Framework/Oracle/ThreadedOracle.h"
27 #include "../../Framework/Scene2D/CairoCompositor.h"
28 #include "../../Framework/Scene2D/GrayscaleStyleConfigurator.h"
29 #include "../../Framework/Scene2D/LookupTableStyleConfigurator.h"
30 #include "../../Framework/StoneInitialization.h"
31 #include "../../Framework/Volumes/VolumeSceneLayerSource.h"
32 #include "../../Framework/Volumes/DicomVolumeImageMPRSlicer.h"
33 #include "../../Framework/Volumes/DicomVolumeImageReslicer.h"
34
35 // From Orthanc framework
36 #include <Core/Images/ImageProcessing.h>
37 #include <Core/Images/PngWriter.h>
38 #include <Core/Logging.h>
39 #include <Core/OrthancException.h>
40 #include <Core/SystemToolbox.h>
41
42
43 namespace OrthancStone
44 {
45 class NativeApplicationContext : public IMessageEmitter
46 {
47 private:
48 boost::shared_mutex mutex_;
49 MessageBroker broker_;
50 IObservable oracleObservable_;
51
52 public:
53 NativeApplicationContext() :
54 oracleObservable_(broker_)
55 {
56 }
57
58
59 virtual void EmitMessage(const IObserver& observer,
60 const IMessage& message) ORTHANC_OVERRIDE
61 {
62 try
63 {
64 boost::unique_lock<boost::shared_mutex> lock(mutex_);
65 oracleObservable_.EmitMessage(observer, message);
66 }
67 catch (Orthanc::OrthancException& e)
68 {
69 LOG(ERROR) << "Exception while emitting a message: " << e.What();
70 }
71 }
72
73
74 class ReaderLock : public boost::noncopyable
75 {
76 private:
77 NativeApplicationContext& that_;
78 boost::shared_lock<boost::shared_mutex> lock_;
79
80 public:
81 ReaderLock(NativeApplicationContext& that) :
82 that_(that),
83 lock_(that.mutex_)
84 {
85 }
86 };
87
88
89 class WriterLock : public boost::noncopyable
90 {
91 private:
92 NativeApplicationContext& that_;
93 boost::unique_lock<boost::shared_mutex> lock_;
94
95 public:
96 WriterLock(NativeApplicationContext& that) :
97 that_(that),
98 lock_(that.mutex_)
99 {
100 }
101
102 MessageBroker& GetBroker()
103 {
104 return that_.broker_;
105 }
106
107 IObservable& GetOracleObservable()
108 {
109 return that_.oracleObservable_;
110 }
111 };
112 };
113 }
114
115
116
117 class Toto : public OrthancStone::IObserver
118 {
119 private:
120 OrthancStone::CoordinateSystem3D plane_;
121 OrthancStone::IOracle& oracle_;
122 OrthancStone::Scene2D scene_;
123 std::unique_ptr<OrthancStone::VolumeSceneLayerSource> source1_, source2_, source3_;
124
125
126 void Refresh()
127 {
128 if (source1_.get() != NULL)
129 {
130 source1_->Update(plane_);
131 }
132
133 if (source2_.get() != NULL)
134 {
135 source2_->Update(plane_);
136 }
137
138 if (source3_.get() != NULL)
139 {
140 source3_->Update(plane_);
141 }
142
143 scene_.FitContent(1024, 768);
144
145 {
146 OrthancStone::CairoCompositor compositor(scene_, 1024, 768);
147 compositor.Refresh();
148
149 Orthanc::ImageAccessor accessor;
150 compositor.GetCanvas().GetReadOnlyAccessor(accessor);
151
152 Orthanc::Image tmp(Orthanc::PixelFormat_RGB24, accessor.GetWidth(), accessor.GetHeight(), false);
153 Orthanc::ImageProcessing::Convert(tmp, accessor);
154
155 static unsigned int count = 0;
156 char buf[64];
157 sprintf(buf, "scene-%06d.png", count++);
158
159 Orthanc::PngWriter writer;
160 writer.WriteToFile(buf, tmp);
161 }
162 }
163
164
165 void Handle(const OrthancStone::DicomVolumeImage::GeometryReadyMessage& message)
166 {
167 printf("Geometry ready\n");
168
169 plane_ = message.GetOrigin().GetGeometry().GetSagittalGeometry();
170 //plane_ = message.GetOrigin().GetGeometry().GetAxialGeometry();
171 //plane_ = message.GetOrigin().GetGeometry().GetCoronalGeometry();
172 plane_.SetOrigin(message.GetOrigin().GetGeometry().GetCoordinates(0.5f, 0.5f, 0.5f));
173
174 Refresh();
175 }
176
177
178 void Handle(const OrthancStone::SleepOracleCommand::TimeoutMessage& message)
179 {
180 if (message.GetOrigin().HasPayload())
181 {
182 printf("TIMEOUT! %d\n", dynamic_cast<const Orthanc::SingleValueObject<unsigned int>& >(message.GetOrigin().GetPayload()).GetValue());
183 }
184 else
185 {
186 printf("TIMEOUT\n");
187
188 Refresh();
189
190 /**
191 * The sleep() leads to a crash if the oracle is still running,
192 * while this object is destroyed. Always stop the oracle before
193 * destroying active objects. (*)
194 **/
195 // boost::this_thread::sleep(boost::posix_time::seconds(2));
196
197 oracle_.Schedule(*this, new OrthancStone::SleepOracleCommand(message.GetOrigin().GetDelay()));
198 }
199 }
200
201 void Handle(const OrthancStone::OrthancRestApiCommand::SuccessMessage& message)
202 {
203 Json::Value v;
204 message.ParseJsonBody(v);
205
206 printf("ICI [%s]\n", v.toStyledString().c_str());
207 }
208
209 void Handle(const OrthancStone::GetOrthancImageCommand::SuccessMessage& message)
210 {
211 printf("IMAGE %dx%d\n", message.GetImage().GetWidth(), message.GetImage().GetHeight());
212 }
213
214 void Handle(const OrthancStone::GetOrthancWebViewerJpegCommand::SuccessMessage& message)
215 {
216 printf("WebViewer %dx%d\n", message.GetImage().GetWidth(), message.GetImage().GetHeight());
217 }
218
219 void Handle(const OrthancStone::OracleCommandExceptionMessage& message)
220 {
221 printf("EXCEPTION: [%s] on command type %d\n", message.GetException().What(), message.GetCommand().GetType());
222
223 switch (message.GetCommand().GetType())
224 {
225 case OrthancStone::IOracleCommand::Type_GetOrthancWebViewerJpeg:
226 printf("URI: [%s]\n", dynamic_cast<const OrthancStone::GetOrthancWebViewerJpegCommand&>
227 (message.GetCommand()).GetUri().c_str());
228 break;
229
230 default:
231 break;
232 }
233 }
234
235 public:
236 Toto(OrthancStone::IOracle& oracle,
237 OrthancStone::IObservable& oracleObservable) :
238 IObserver(oracleObservable.GetBroker()),
239 oracle_(oracle)
240 {
241 oracleObservable.RegisterObserverCallback
242 (new OrthancStone::Callable
243 <Toto, OrthancStone::SleepOracleCommand::TimeoutMessage>(*this, &Toto::Handle));
244
245 oracleObservable.RegisterObserverCallback
246 (new OrthancStone::Callable
247 <Toto, OrthancStone::OrthancRestApiCommand::SuccessMessage>(*this, &Toto::Handle));
248
249 oracleObservable.RegisterObserverCallback
250 (new OrthancStone::Callable
251 <Toto, OrthancStone::GetOrthancImageCommand::SuccessMessage>(*this, &Toto::Handle));
252
253 oracleObservable.RegisterObserverCallback
254 (new OrthancStone::Callable
255 <Toto, OrthancStone::GetOrthancWebViewerJpegCommand::SuccessMessage>(*this, &Toto::Handle));
256
257 oracleObservable.RegisterObserverCallback
258 (new OrthancStone::Callable
259 <Toto, OrthancStone::OracleCommandExceptionMessage>(*this, &Toto::Handle));
260 }
261
262 void SetReferenceLoader(OrthancStone::IObservable& loader)
263 {
264 loader.RegisterObserverCallback
265 (new OrthancStone::Callable
266 <Toto, OrthancStone::DicomVolumeImage::GeometryReadyMessage>(*this, &Toto::Handle));
267 }
268
269 void SetVolume1(int depth,
270 const boost::shared_ptr<OrthancStone::IVolumeSlicer>& volume,
271 OrthancStone::ILayerStyleConfigurator* style)
272 {
273 source1_.reset(new OrthancStone::VolumeSceneLayerSource(scene_, depth, volume));
274
275 if (style != NULL)
276 {
277 source1_->SetConfigurator(style);
278 }
279 }
280
281 void SetVolume2(int depth,
282 const boost::shared_ptr<OrthancStone::IVolumeSlicer>& volume,
283 OrthancStone::ILayerStyleConfigurator* style)
284 {
285 source2_.reset(new OrthancStone::VolumeSceneLayerSource(scene_, depth, volume));
286
287 if (style != NULL)
288 {
289 source2_->SetConfigurator(style);
290 }
291 }
292
293 void SetStructureSet(int depth,
294 const boost::shared_ptr<OrthancStone::DicomStructureSetLoader>& volume)
295 {
296 source3_.reset(new OrthancStone::VolumeSceneLayerSource(scene_, depth, volume));
297 }
298
299 };
300
301
302 void Run(OrthancStone::NativeApplicationContext& context,
303 OrthancStone::ThreadedOracle& oracle)
304 {
305 // the oracle has been supplied with the context (as an IEmitter) upon
306 // creation
307 boost::shared_ptr<OrthancStone::DicomVolumeImage> ct(new OrthancStone::DicomVolumeImage);
308 boost::shared_ptr<OrthancStone::DicomVolumeImage> dose(new OrthancStone::DicomVolumeImage);
309
310
311 boost::shared_ptr<Toto> toto;
312 boost::shared_ptr<OrthancStone::OrthancSeriesVolumeProgressiveLoader> ctLoader;
313 boost::shared_ptr<OrthancStone::OrthancMultiframeVolumeLoader> doseLoader;
314 boost::shared_ptr<OrthancStone::DicomStructureSetLoader> rtstructLoader;
315
316 {
317 OrthancStone::NativeApplicationContext::WriterLock lock(context);
318 toto.reset(new Toto(oracle, lock.GetOracleObservable()));
319
320 // the oracle is used to schedule commands
321 // the oracleObservable is used by the loaders to:
322 // - request the broker (lifetime mgmt)
323 // - register the loader callbacks (called indirectly by the oracle)
324 ctLoader.reset(new OrthancStone::OrthancSeriesVolumeProgressiveLoader(ct, oracle, lock.GetOracleObservable()));
325 doseLoader.reset(new OrthancStone::OrthancMultiframeVolumeLoader(dose, oracle, lock.GetOracleObservable()));
326 rtstructLoader.reset(new OrthancStone::DicomStructureSetLoader(oracle, lock.GetOracleObservable()));
327 }
328
329
330 //toto->SetReferenceLoader(*ctLoader);
331 toto->SetReferenceLoader(*doseLoader);
332
333
334 #if 1
335 toto->SetVolume1(0, ctLoader, new OrthancStone::GrayscaleStyleConfigurator);
336 #else
337 {
338 boost::shared_ptr<OrthancStone::IVolumeSlicer> reslicer(new OrthancStone::DicomVolumeImageReslicer(ct));
339 toto->SetVolume1(0, reslicer, new OrthancStone::GrayscaleStyleConfigurator);
340 }
341 #endif
342
343
344 {
345 std::unique_ptr<OrthancStone::LookupTableStyleConfigurator> config(new OrthancStone::LookupTableStyleConfigurator);
346 config->SetLookupTable(Orthanc::EmbeddedResources::COLORMAP_HOT);
347
348 boost::shared_ptr<OrthancStone::DicomVolumeImageMPRSlicer> tmp(new OrthancStone::DicomVolumeImageMPRSlicer(dose));
349 toto->SetVolume2(1, tmp, config.release());
350 }
351
352 toto->SetStructureSet(2, rtstructLoader);
353
354 oracle.Schedule(*toto, new OrthancStone::SleepOracleCommand(100));
355
356 if (0)
357 {
358 Json::Value v = Json::objectValue;
359 v["Level"] = "Series";
360 v["Query"] = Json::objectValue;
361
362 std::unique_ptr<OrthancStone::OrthancRestApiCommand> command(new OrthancStone::OrthancRestApiCommand);
363 command->SetMethod(Orthanc::HttpMethod_Post);
364 command->SetUri("/tools/find");
365 command->SetBody(v);
366
367 oracle.Schedule(*toto, command.release());
368 }
369
370 if(0)
371 {
372 if (0)
373 {
374 std::unique_ptr<OrthancStone::GetOrthancImageCommand> command(new OrthancStone::GetOrthancImageCommand);
375 command->SetHttpHeader("Accept", std::string(Orthanc::EnumerationToString(Orthanc::MimeType_Jpeg)));
376 command->SetUri("/instances/6687cc73-07cae193-52ff29c8-f646cb16-0753ed92/preview");
377 oracle.Schedule(*toto, command.release());
378 }
379
380 if (0)
381 {
382 std::unique_ptr<OrthancStone::GetOrthancImageCommand> command(new OrthancStone::GetOrthancImageCommand);
383 command->SetHttpHeader("Accept", std::string(Orthanc::EnumerationToString(Orthanc::MimeType_Png)));
384 command->SetUri("/instances/6687cc73-07cae193-52ff29c8-f646cb16-0753ed92/preview");
385 oracle.Schedule(*toto, command.release());
386 }
387
388 if (0)
389 {
390 std::unique_ptr<OrthancStone::GetOrthancImageCommand> command(new OrthancStone::GetOrthancImageCommand);
391 command->SetHttpHeader("Accept", std::string(Orthanc::EnumerationToString(Orthanc::MimeType_Png)));
392 command->SetUri("/instances/6687cc73-07cae193-52ff29c8-f646cb16-0753ed92/image-uint16");
393 oracle.Schedule(*toto, command.release());
394 }
395
396 if (0)
397 {
398 std::unique_ptr<OrthancStone::GetOrthancImageCommand> command(new OrthancStone::GetOrthancImageCommand);
399 command->SetHttpHeader("Accept-Encoding", "gzip");
400 command->SetHttpHeader("Accept", std::string(Orthanc::EnumerationToString(Orthanc::MimeType_Pam)));
401 command->SetUri("/instances/6687cc73-07cae193-52ff29c8-f646cb16-0753ed92/image-uint16");
402 oracle.Schedule(*toto, command.release());
403 }
404
405 if (0)
406 {
407 std::unique_ptr<OrthancStone::GetOrthancImageCommand> command(new OrthancStone::GetOrthancImageCommand);
408 command->SetHttpHeader("Accept", std::string(Orthanc::EnumerationToString(Orthanc::MimeType_Pam)));
409 command->SetUri("/instances/6687cc73-07cae193-52ff29c8-f646cb16-0753ed92/image-uint16");
410 oracle.Schedule(*toto, command.release());
411 }
412
413 if (0)
414 {
415 std::unique_ptr<OrthancStone::GetOrthancWebViewerJpegCommand> command(new OrthancStone::GetOrthancWebViewerJpegCommand);
416 command->SetHttpHeader("Accept-Encoding", "gzip");
417 command->SetInstance("e6c7c20b-c9f65d7e-0d76f2e2-830186f2-3e3c600e");
418 command->SetQuality(90);
419 oracle.Schedule(*toto, command.release());
420 }
421
422
423 if (0)
424 {
425 for (unsigned int i = 0; i < 10; i++)
426 {
427 std::unique_ptr<OrthancStone::SleepOracleCommand> command(new OrthancStone::SleepOracleCommand(i * 1000));
428 command->SetPayload(new Orthanc::SingleValueObject<unsigned int>(42 * i));
429 oracle.Schedule(*toto, command.release());
430 }
431 }
432 }
433
434 // 2017-11-17-Anonymized
435 #if 0
436 // BGO data
437 ctLoader->LoadSeries("a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa"); // CT
438 doseLoader->LoadInstance("830a69ff-8e4b5ee3-b7f966c8-bccc20fb-d322dceb"); // RT-DOSE
439 //rtstructLoader->LoadInstance("54460695-ba3885ee-ddf61ac0-f028e31d-a6e474d9"); // RT-STRUCT
440 #else
441 //ctLoader->LoadSeries("cb3ea4d1-d08f3856-ad7b6314-74d88d77-60b05618"); // CT
442 //doseLoader->LoadInstance("41029085-71718346-811efac4-420e2c15-d39f99b6"); // RT-DOSE
443 //rtstructLoader->LoadInstance("83d9c0c3-913a7fee-610097d7-cbf0522d-fd75bee6"); // RT-STRUCT
444
445 // 2017-05-16
446 ctLoader->LoadSeries("a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa"); // CT
447 doseLoader->LoadInstance("eac822ef-a395f94e-e8121fe0-8411fef8-1f7bffad"); // RT-DOSE
448 rtstructLoader->LoadInstance("54460695-ba3885ee-ddf61ac0-f028e31d-a6e474d9"); // RT-STRUCT
449 #endif
450 // 2015-01-28-Multiframe
451 //doseLoader->LoadInstance("88f71e2a-5fad1c61-96ed14d6-5b3d3cf7-a5825279"); // Multiframe CT
452
453 // Delphine
454 //ctLoader->LoadSeries("5990e39c-51e5f201-fe87a54c-31a55943-e59ef80e"); // CT
455 //ctLoader->LoadSeries("67f1b334-02c16752-45026e40-a5b60b6b-030ecab5"); // Lung 1/10mm
456
457
458 {
459 LOG(WARNING) << "...Waiting for Ctrl-C...";
460
461 oracle.Start();
462
463 Orthanc::SystemToolbox::ServerBarrier();
464
465 /**
466 * WARNING => The oracle must be stopped BEFORE the objects using
467 * it are destroyed!!! This forces to wait for the completion of
468 * the running callback methods. Otherwise, the callbacks methods
469 * might still be running while their parent object is destroyed,
470 * resulting in crashes. This is very visible if adding a sleep(),
471 * as in (*).
472 **/
473
474 oracle.Stop();
475 }
476 }
477
478
479
480 /**
481 * IMPORTANT: The full arguments to "main()" are needed for SDL on
482 * Windows. Otherwise, one gets the linking error "undefined reference
483 * to `SDL_main'". https://wiki.libsdl.org/FAQWindows
484 **/
485 int main(int argc, char* argv[])
486 {
487 OrthancStone::StoneInitialize();
488 //Orthanc::Logging::EnableInfoLevel(true);
489
490 try
491 {
492 OrthancStone::NativeApplicationContext context;
493
494 OrthancStone::ThreadedOracle oracle(context);
495 //oracle.SetThreadsCount(1);
496
497 {
498 Orthanc::WebServiceParameters p;
499 //p.SetUrl("http://localhost:8043/");
500 p.SetCredentials("orthanc", "orthanc");
501 oracle.SetOrthancParameters(p);
502 }
503
504 //oracle.Start();
505
506 Run(context, oracle);
507
508 //oracle.Stop();
509 }
510 catch (Orthanc::OrthancException& e)
511 {
512 LOG(ERROR) << "EXCEPTION: " << e.What();
513 }
514
515 OrthancStone::StoneFinalize();
516
517 return 0;
518 }