comparison Applications/Samples/Deprecated/SingleVolumeApplication.h @ 1347:bfd77672d825 broker

Moved Application/Samples/* to Application/Samples/Deprecated/*
author Benjamin Golinvaux <bgo@osimis.io>
date Tue, 07 Apr 2020 14:29:01 +0200
parents Applications/Samples/SingleVolumeApplication.h@8a0a62189f46
children c53a4667f895
comparison
equal deleted inserted replaced
1346:df8bf351c23f 1347:bfd77672d825
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 #pragma once
23
24 #include "SampleApplicationBase.h"
25 #include "../../Framework/dev.h"
26 #include "../../Framework/Layers/LineMeasureTracker.h"
27 #include "../../Framework/Layers/CircleMeasureTracker.h"
28
29 #include <Core/Toolbox.h>
30 #include <Core/Logging.h>
31
32 #include <Plugins/Samples/Common/OrthancHttpConnection.h> // TODO REMOVE
33 #include "../../Framework/Layers/DicomStructureSetSlicer.h" // TODO REMOVE
34 #include "../../Framework/Toolbox/MessagingToolbox.h" // TODO REMOVE
35
36 namespace OrthancStone
37 {
38 namespace Samples
39 {
40 class SingleVolumeApplication : public SampleApplicationBase
41 {
42 private:
43 class Interactor : public VolumeImageInteractor
44 {
45 private:
46 SliceViewerWidget& widget_;
47 size_t layer_;
48
49 protected:
50 virtual void NotifySliceContentChange(const ISlicedVolume& volume,
51 const size_t& sliceIndex,
52 const Slice& slice)
53 {
54 const OrthancVolumeImage& image = dynamic_cast<const OrthancVolumeImage&>(volume);
55
56 RenderStyle s = widget_.GetLayerStyle(layer_);
57
58 if (image.FitWindowingToRange(s, slice.GetConverter()))
59 {
60 //printf("Windowing: %f => %f\n", s.customWindowCenter_, s.customWindowWidth_);
61 widget_.SetLayerStyle(layer_, s);
62 }
63 }
64
65 virtual void MouseOver(CairoContext& context,
66 WorldSceneWidget& widget,
67 const ViewportGeometry& view,
68 double x,
69 double y,
70 IStatusBar* statusBar)
71 {
72 const SliceViewerWidget& w = dynamic_cast<const SliceViewerWidget&>(widget);
73 Vector p = w.GetSlice().MapSliceToWorldCoordinates(x, y);
74 printf("%f %f %f\n", p[0], p[1], p[2]);
75 }
76
77 public:
78 Interactor(OrthancVolumeImage& volume,
79 SliceViewerWidget& widget,
80 VolumeProjection projection,
81 size_t layer) :
82 VolumeImageInteractor(volume, widget, projection),
83 widget_(widget),
84 layer_(layer)
85 {
86 }
87 };
88
89
90 public:
91 virtual void DeclareStartupOptions(boost::program_options::options_description& options)
92 {
93 boost::program_options::options_description generic("Sample options");
94 generic.add_options()
95 ("series", boost::program_options::value<std::string>(),
96 "Orthanc ID of the series")
97 ("instance", boost::program_options::value<std::string>(),
98 "Orthanc ID of a multi-frame instance that describes a 3D volume")
99 ("threads", boost::program_options::value<unsigned int>()->default_value(3),
100 "Number of download threads")
101 ("projection", boost::program_options::value<std::string>()->default_value("axial"),
102 "Projection of interest (can be axial, sagittal or coronal)")
103 ("reverse", boost::program_options::value<bool>()->default_value(false),
104 "Reverse the normal direction of the volume")
105 ;
106
107 options.add(generic);
108 }
109
110 virtual void Initialize(IStatusBar& statusBar,
111 const boost::program_options::variables_map& parameters)
112 {
113 using namespace OrthancStone;
114
115 if (parameters.count("series") > 1 ||
116 parameters.count("instance") > 1)
117 {
118 LOG(ERROR) << "Only one series or instance is allowed";
119 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
120 }
121
122 if (parameters.count("series") == 1 &&
123 parameters.count("instance") == 1)
124 {
125 LOG(ERROR) << "Cannot specify both a series and an instance";
126 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
127 }
128
129 std::string series;
130 if (parameters.count("series") == 1)
131 {
132 series = parameters["series"].as<std::string>();
133 }
134
135 std::string instance;
136 if (parameters.count("instance") == 1)
137 {
138 instance = parameters["instance"].as<std::string>();
139 }
140
141 if (series.empty() &&
142 instance.empty())
143 {
144 LOG(ERROR) << "The series ID or instance ID is missing";
145 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
146 }
147
148 //unsigned int threads = parameters["threads"].as<unsigned int>();
149 //bool reverse = parameters["reverse"].as<bool>();
150
151 std::string tmp = parameters["projection"].as<std::string>();
152 Orthanc::Toolbox::ToLowerCase(tmp);
153
154 VolumeProjection projection;
155 if (tmp == "axial")
156 {
157 projection = VolumeProjection_Axial;
158 }
159 else if (tmp == "sagittal")
160 {
161 projection = VolumeProjection_Sagittal;
162 }
163 else if (tmp == "coronal")
164 {
165 projection = VolumeProjection_Coronal;
166 }
167 else
168 {
169 LOG(ERROR) << "Unknown projection: " << tmp;
170 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
171 }
172
173 std::unique_ptr<SliceViewerWidget> widget(new SliceViewerWidget);
174
175 #if 1
176 std::unique_ptr<OrthancVolumeImage> volume(new OrthancVolumeImage(context.GetWebService(), true));
177 if (series.empty())
178 {
179 volume->ScheduleLoadInstance(instance);
180 }
181 else
182 {
183 volume->ScheduleLoadSeries(series);
184 }
185
186 widget->AddLayer(new VolumeImageMPRSlicer(*volume));
187
188 context_->AddInteractor(new Interactor(*volume, *widget, projection, 0));
189 context_->AddSlicedVolume(volume.release());
190
191 if (1)
192 {
193 RenderStyle s;
194 //s.drawGrid_ = true;
195 s.alpha_ = 1;
196 s.windowing_ = ImageWindowing_Bone;
197 widget->SetLayerStyle(0, s);
198 }
199 else
200 {
201 RenderStyle s;
202 s.alpha_ = 1;
203 s.applyLut_ = true;
204 s.lut_ = Orthanc::EmbeddedResources::COLORMAP_JET;
205 s.interpolation_ = ImageInterpolation_Bilinear;
206 widget->SetLayerStyle(0, s);
207 }
208 #else
209 std::unique_ptr<OrthancVolumeImage> ct(new OrthancVolumeImage(context_->GetWebService(), false));
210 //ct->ScheduleLoadSeries("15a6f44a-ac7b88fe-19c462d9-dddd918e-b01550d8"); // 0178023P
211 //ct->ScheduleLoadSeries("dd069910-4f090474-7d2bba07-e5c10783-f9e4fb1d");
212 //ct->ScheduleLoadSeries("a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa"); // IBA
213 //ct->ScheduleLoadSeries("03677739-1d8bca40-db1daf59-d74ff548-7f6fc9c0"); // 0522c0001 TCIA
214 ct->ScheduleLoadSeries("295e8a13-dfed1320-ba6aebb2-9a13e20f-1b3eb953"); // Captain
215
216 std::unique_ptr<OrthancVolumeImage> pet(new OrthancVolumeImage(context_->GetWebService(), true));
217 //pet->ScheduleLoadSeries("48d2997f-8e25cd81-dd715b64-bd79cdcc-e8fcee53"); // 0178023P
218 //pet->ScheduleLoadSeries("aabad2e7-80702b5d-e599d26c-4f13398e-38d58a9e");
219 //pet->ScheduleLoadInstance("830a69ff-8e4b5ee3-b7f966c8-bccc20fb-d322dceb"); // IBA 1
220 //pet->ScheduleLoadInstance("337876a1-a68a9718-f15abccd-38faafa1-b99b496a"); // IBA 2
221 //pet->ScheduleLoadInstance("830a69ff-8e4b5ee3-b7f966c8-bccc20fb-d322dceb"); // IBA 3
222 //pet->ScheduleLoadInstance("269f26f4-0c83eeeb-2e67abbd-5467a40f-f1bec90c"); // 0522c0001 TCIA
223 pet->ScheduleLoadInstance("f080888c-0ab7528a-f7d9c28c-84980eb1-ff3b0ae6"); // Captain 1
224 //pet->ScheduleLoadInstance("4f78055b-6499a2c5-1e089290-394acc05-3ec781c1"); // Captain 2
225
226 std::unique_ptr<StructureSetLoader> rtStruct(new StructureSetLoader(context_->GetWebService()));
227 //rtStruct->ScheduleLoadInstance("c2ebc17b-6b3548db-5e5da170-b8ecab71-ea03add3"); // 0178023P
228 //rtStruct->ScheduleLoadInstance("54460695-ba3885ee-ddf61ac0-f028e31d-a6e474d9"); // IBA
229 //rtStruct->ScheduleLoadInstance("17cd032b-ad92a438-ca05f06a-f9e96668-7e3e9e20"); // 0522c0001 TCIA
230 rtStruct->ScheduleLoadInstance("96c889ab-29fe5c54-dda6e66c-3949e4da-58f90d75"); // Captain
231
232 widget->AddLayer(new VolumeImageMPRSlicer(*ct));
233 widget->AddLayer(new VolumeImageMPRSlicer(*pet));
234 widget->AddLayer(new DicomStructureSetSlicer(*rtStruct));
235
236 context_->AddInteractor(new Interactor(*pet, *widget, projection, 1));
237 //context_->AddInteractor(new VolumeImageInteractor(*ct, *widget, projection));
238
239 context_->AddSlicedVolume(ct.release());
240 context_->AddSlicedVolume(pet.release());
241 context_->AddVolumeLoader(rtStruct.release());
242
243 {
244 RenderStyle s;
245 //s.drawGrid_ = true;
246 s.alpha_ = 1;
247 s.windowing_ = ImageWindowing_Bone;
248 widget->SetLayerStyle(0, s);
249 }
250
251 {
252 RenderStyle s;
253 //s.drawGrid_ = true;
254 s.SetColor(255, 0, 0); // Draw missing PET layer in red
255 s.alpha_ = 0.5;
256 s.applyLut_ = true;
257 s.lut_ = Orthanc::EmbeddedResources::COLORMAP_JET;
258 s.interpolation_ = ImageInterpolation_Bilinear;
259 s.windowing_ = ImageWindowing_Custom;
260 s.customWindowCenter_ = 0;
261 s.customWindowWidth_ = 128;
262 widget->SetLayerStyle(1, s);
263 }
264 #endif
265
266
267 statusBar.SetMessage("Use the keys \"b\", \"l\" and \"d\" to change Hounsfield windowing");
268 statusBar.SetMessage("Use the keys \"t\" to track the (X,Y,Z) mouse coordinates");
269 statusBar.SetMessage("Use the keys \"m\" to measure distances");
270 statusBar.SetMessage("Use the keys \"c\" to draw circles");
271
272 widget->SetTransmitMouseOver(true);
273 context_->SetCentralWidget(widget.release());
274 }
275 };
276 }
277 }