Mercurial > hg > orthanc-stone
annotate UnitTestsSources/UnitTestsMain.cpp @ 69:1553b67b24e5 wasm
OrthancSynchronousWebService
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 22 May 2017 20:35:11 +0200 |
parents | 1526d38ef6da |
children | f73aed014bde |
rev | line source |
---|---|
20
946377d1c992
skeleton for unit tests
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
1 /** |
946377d1c992
skeleton for unit tests
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
2 * Stone of Orthanc |
946377d1c992
skeleton for unit tests
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics |
946377d1c992
skeleton for unit tests
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
4 * Department, University Hospital of Liege, Belgium |
40
7207a407bcd8
shared copyright with osimis
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
20
diff
changeset
|
5 * Copyright (C) 2017 Osimis, Belgium |
20
946377d1c992
skeleton for unit tests
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
6 * |
946377d1c992
skeleton for unit tests
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
7 * This program is free software: you can redistribute it and/or |
47 | 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. | |
20
946377d1c992
skeleton for unit tests
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
11 * |
946377d1c992
skeleton for unit tests
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
12 * This program is distributed in the hope that it will be useful, but |
946377d1c992
skeleton for unit tests
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
13 * WITHOUT ANY WARRANTY; without even the implied warranty of |
47 | 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 | |
20
946377d1c992
skeleton for unit tests
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. |
946377d1c992
skeleton for unit tests
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
19 **/ |
946377d1c992
skeleton for unit tests
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
20 |
946377d1c992
skeleton for unit tests
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
21 |
946377d1c992
skeleton for unit tests
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
22 #include "gtest/gtest.h" |
946377d1c992
skeleton for unit tests
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
23 |
946377d1c992
skeleton for unit tests
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
24 #include "../Resources/Orthanc/Core/Logging.h" |
69
1553b67b24e5
OrthancSynchronousWebService
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
68
diff
changeset
|
25 #include "../Framework/Toolbox/OrthancSynchronousWebService.h" |
65
885932a893de
OrthancFrameLayerSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
47
diff
changeset
|
26 #include "../Framework/Layers/OrthancFrameLayerSource.h" |
66 | 27 #include "../Framework/Widgets/LayerWidget.h" |
65
885932a893de
OrthancFrameLayerSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
47
diff
changeset
|
28 |
885932a893de
OrthancFrameLayerSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
47
diff
changeset
|
29 |
68 | 30 #include "../Resources/Orthanc/Core/Images/PngReader.h" |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
31 #include "../Framework/Toolbox/MessagingToolbox.h" |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
32 #include "../Framework/Toolbox/DicomFrameConverter.h" |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
33 |
68 | 34 #include <boost/lexical_cast.hpp> |
35 | |
65
885932a893de
OrthancFrameLayerSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
47
diff
changeset
|
36 namespace OrthancStone |
885932a893de
OrthancFrameLayerSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
47
diff
changeset
|
37 { |
68 | 38 class Slice |
39 { | |
40 private: | |
41 enum Type | |
42 { | |
43 Type_Invalid, | |
44 Type_OrthancInstance | |
45 // TODO A slice could come from some DICOM file (URL) | |
46 }; | |
47 | |
48 Type type_; | |
49 std::string orthancInstanceId_; | |
50 unsigned int frame_; | |
51 SliceGeometry geometry_; | |
52 double pixelSpacingX_; | |
53 double pixelSpacingY_; | |
54 double thickness_; | |
55 unsigned int width_; | |
56 unsigned int height_; | |
57 DicomFrameConverter converter_; | |
58 | |
59 public: | |
60 Slice() : type_(Type_Invalid) | |
61 { | |
62 } | |
63 | |
64 bool ParseOrthancFrame(const OrthancPlugins::IDicomDataset& dataset, | |
65 const std::string& instanceId, | |
66 unsigned int frame) | |
67 { | |
68 OrthancPlugins::DicomDatasetReader reader(dataset); | |
69 | |
70 unsigned int frameCount; | |
71 if (!reader.GetUnsignedIntegerValue(frameCount, OrthancPlugins::DICOM_TAG_NUMBER_OF_FRAMES)) | |
72 { | |
73 frameCount = 1; // Assume instance with one frame | |
74 } | |
75 | |
76 if (frame >= frameCount) | |
77 { | |
78 return false; | |
79 } | |
80 | |
81 if (!reader.GetDoubleValue(thickness_, OrthancPlugins::DICOM_TAG_SLICE_THICKNESS)) | |
82 { | |
83 thickness_ = 100.0 * std::numeric_limits<double>::epsilon(); | |
84 } | |
85 | |
86 GeometryToolbox::GetPixelSpacing(pixelSpacingX_, pixelSpacingY_, dataset); | |
87 | |
88 std::string position, orientation; | |
89 if (dataset.GetStringValue(position, OrthancPlugins::DICOM_TAG_IMAGE_POSITION_PATIENT) && | |
90 dataset.GetStringValue(orientation, OrthancPlugins::DICOM_TAG_IMAGE_ORIENTATION_PATIENT) && | |
91 reader.GetUnsignedIntegerValue(width_, OrthancPlugins::DICOM_TAG_COLUMNS) && | |
92 reader.GetUnsignedIntegerValue(height_, OrthancPlugins::DICOM_TAG_ROWS)) | |
93 { | |
94 orthancInstanceId_ = instanceId; | |
95 frame_ = frame; | |
96 geometry_ = SliceGeometry(position, orientation); | |
97 converter_.ReadParameters(dataset); | |
98 | |
99 type_ = Type_OrthancInstance; | |
100 return true; | |
101 } | |
102 else | |
103 { | |
104 return false; | |
105 } | |
106 } | |
107 | |
108 bool IsOrthancInstance() const | |
109 { | |
110 return type_ == Type_OrthancInstance; | |
111 } | |
112 | |
113 const std::string GetOrthancInstanceId() const | |
114 { | |
115 if (type_ != Type_OrthancInstance) | |
116 { | |
117 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
118 } | |
119 | |
120 return orthancInstanceId_; | |
121 } | |
122 | |
123 unsigned int GetFrame() const | |
124 { | |
125 if (type_ == Type_Invalid) | |
126 { | |
127 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
128 } | |
129 | |
130 return frame_; | |
131 } | |
132 | |
133 const SliceGeometry& GetGeometry() const | |
134 { | |
135 if (type_ == Type_Invalid) | |
136 { | |
137 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
138 } | |
139 | |
140 return geometry_; | |
141 } | |
142 | |
143 double GetThickness() const | |
144 { | |
145 if (type_ == Type_Invalid) | |
146 { | |
147 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
148 } | |
149 | |
150 return thickness_; | |
151 } | |
152 | |
153 double GetPixelSpacingX() const | |
154 { | |
155 if (type_ == Type_Invalid) | |
156 { | |
157 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
158 } | |
159 | |
160 return pixelSpacingX_; | |
161 } | |
162 | |
163 double GetPixelSpacingY() const | |
164 { | |
165 if (type_ == Type_Invalid) | |
166 { | |
167 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
168 } | |
169 | |
170 return pixelSpacingY_; | |
171 } | |
172 | |
173 unsigned int GetWidth() const | |
174 { | |
175 if (type_ == Type_Invalid) | |
176 { | |
177 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
178 } | |
179 | |
180 return width_; | |
181 } | |
182 | |
183 unsigned int GetHeight() const | |
184 { | |
185 if (type_ == Type_Invalid) | |
186 { | |
187 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
188 } | |
189 | |
190 return height_; | |
191 } | |
192 | |
193 const DicomFrameConverter& GetConverter() const | |
194 { | |
195 if (type_ == Type_Invalid) | |
196 { | |
197 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
198 } | |
199 | |
200 return converter_; | |
201 } | |
202 }; | |
203 | |
204 | |
205 class SliceSorter : public boost::noncopyable | |
206 { | |
207 private: | |
208 class SliceWithDepth : public boost::noncopyable | |
209 { | |
210 private: | |
211 Slice slice_; | |
212 double depth_; | |
213 | |
214 public: | |
215 SliceWithDepth(const Slice& slice) : | |
216 slice_(slice), | |
217 depth_(0) | |
218 { | |
219 } | |
220 | |
221 void SetNormal(const Vector& normal) | |
222 { | |
223 depth_ = boost::numeric::ublas::inner_prod | |
224 (slice_.GetGeometry().GetOrigin(), normal); | |
225 } | |
226 | |
227 double GetDepth() const | |
228 { | |
229 return depth_; | |
230 } | |
231 | |
232 const Slice& GetSlice() const | |
233 { | |
234 return slice_; | |
235 } | |
236 }; | |
237 | |
238 struct Comparator | |
239 { | |
240 bool operator() (const SliceWithDepth* const& a, | |
241 const SliceWithDepth* const& b) const | |
242 { | |
243 return a->GetDepth() < b->GetDepth(); | |
244 } | |
245 }; | |
246 | |
247 typedef std::vector<SliceWithDepth*> Slices; | |
248 | |
249 Slices slices_; | |
250 bool hasNormal_; | |
251 | |
252 public: | |
253 SliceSorter() : hasNormal_(false) | |
254 { | |
255 } | |
256 | |
257 ~SliceSorter() | |
258 { | |
259 for (size_t i = 0; i < slices_.size(); i++) | |
260 { | |
261 assert(slices_[i] != NULL); | |
262 delete slices_[i]; | |
263 } | |
264 } | |
265 | |
266 void Reserve(size_t count) | |
267 { | |
268 slices_.reserve(count); | |
269 } | |
270 | |
271 void AddSlice(const Slice& slice) | |
272 { | |
273 slices_.push_back(new SliceWithDepth(slice)); | |
274 } | |
275 | |
276 size_t GetSliceCount() const | |
277 { | |
278 return slices_.size(); | |
279 } | |
280 | |
281 const Slice& GetSlice(size_t i) const | |
282 { | |
283 if (i >= slices_.size()) | |
284 { | |
285 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
286 } | |
287 | |
288 assert(slices_[i] != NULL); | |
289 return slices_[i]->GetSlice(); | |
290 } | |
291 | |
292 void SetNormal(const Vector& normal) | |
293 { | |
294 for (size_t i = 0; i < slices_.size(); i++) | |
295 { | |
296 slices_[i]->SetNormal(normal); | |
297 } | |
298 | |
299 hasNormal_ = true; | |
300 } | |
301 | |
302 void Sort() | |
303 { | |
304 if (!hasNormal_) | |
305 { | |
306 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
307 } | |
308 | |
309 Comparator comparator; | |
310 std::sort(slices_.begin(), slices_.end(), comparator); | |
311 } | |
312 | |
313 void FilterNormal(const Vector& normal) | |
314 { | |
315 size_t pos = 0; | |
316 | |
317 for (size_t i = 0; i < slices_.size(); i++) | |
318 { | |
319 if (GeometryToolbox::IsParallel(normal, slices_[i]->GetSlice().GetGeometry().GetNormal())) | |
320 { | |
321 // This slice is compatible with the selected normal | |
322 slices_[pos] = slices_[i]; | |
323 pos += 1; | |
324 } | |
325 else | |
326 { | |
327 delete slices_[i]; | |
328 slices_[i] = NULL; | |
329 } | |
330 } | |
331 | |
332 slices_.resize(pos); | |
333 } | |
334 | |
335 bool SelectNormal(Vector& normal) const | |
336 { | |
337 std::vector<Vector> normalCandidates; | |
338 std::vector<unsigned int> normalCount; | |
339 | |
340 bool found = false; | |
341 | |
342 for (size_t i = 0; !found && i < GetSliceCount(); i++) | |
343 { | |
344 const Vector& normal = GetSlice(i).GetGeometry().GetNormal(); | |
345 | |
346 bool add = true; | |
347 for (size_t j = 0; add && j < normalCandidates.size(); j++) // (*) | |
348 { | |
349 if (GeometryToolbox::IsParallel(normal, normalCandidates[j])) | |
350 { | |
351 normalCount[j] += 1; | |
352 add = false; | |
353 } | |
354 } | |
355 | |
356 if (add) | |
357 { | |
358 if (normalCount.size() > 2) | |
359 { | |
360 // To get linear-time complexity in (*). This heuristics | |
361 // allows the series to have one single frame that is | |
362 // not parallel to the others (such a frame could be a | |
363 // generated preview) | |
364 found = false; | |
365 } | |
366 else | |
367 { | |
368 normalCandidates.push_back(normal); | |
369 normalCount.push_back(1); | |
370 } | |
371 } | |
372 } | |
373 | |
374 for (size_t i = 0; !found && i < normalCandidates.size(); i++) | |
375 { | |
376 unsigned int count = normalCount[i]; | |
377 if (count == GetSliceCount() || | |
378 count + 1 == GetSliceCount()) | |
379 { | |
380 normal = normalCandidates[i]; | |
381 found = true; | |
382 } | |
383 } | |
384 | |
385 return found; | |
386 } | |
387 }; | |
388 | |
389 | |
390 | |
391 class OrthancSliceLoader : | |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
392 public IWebService::ICallback // TODO move to PImpl |
66 | 393 { |
394 public: | |
395 class ICallback : public boost::noncopyable | |
396 { | |
397 public: | |
398 virtual ~ICallback() | |
399 { | |
400 } | |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
401 |
68 | 402 virtual void NotifyGeometryReady(const OrthancSliceLoader& loader) = 0; |
403 | |
404 virtual void NotifyGeometryError(const OrthancSliceLoader& loader) = 0; | |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
405 |
68 | 406 virtual void NotifySliceImageReady(const OrthancSliceLoader& loader, |
407 unsigned int sliceIndex, | |
408 const Slice& slice, | |
409 Orthanc::ImageAccessor* image) = 0; | |
410 | |
411 virtual void NotifySliceImageError(const OrthancSliceLoader& loader, | |
412 unsigned int sliceIndex, | |
413 const Slice& slice) = 0; | |
66 | 414 }; |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
415 |
66 | 416 private: |
68 | 417 enum State |
66 | 418 { |
68 | 419 State_Error, |
420 State_Initialization, | |
421 State_LoadingGeometry, | |
422 State_GeometryReady | |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
423 }; |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
424 |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
425 enum Mode |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
426 { |
68 | 427 Mode_SeriesGeometry, |
428 Mode_LoadImage | |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
429 }; |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
430 |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
431 class Operation : public Orthanc::IDynamicObject |
66 | 432 { |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
433 private: |
68 | 434 Mode mode_; |
435 unsigned int sliceIndex_; | |
436 const Slice* slice_; | |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
437 |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
438 Operation(Mode mode) : |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
439 mode_(mode) |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
440 { |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
441 } |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
442 |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
443 public: |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
444 Mode GetMode() const |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
445 { |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
446 return mode_; |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
447 } |
68 | 448 |
449 unsigned int GetSliceIndex() const | |
450 { | |
451 assert(mode_ == Mode_LoadImage); | |
452 return sliceIndex_; | |
453 } | |
454 | |
455 const Slice& GetSlice() const | |
456 { | |
457 assert(mode_ == Mode_LoadImage && slice_ != NULL); | |
458 return *slice_; | |
459 } | |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
460 |
68 | 461 static Operation* DownloadSeriesGeometry() |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
462 { |
68 | 463 return new Operation(Mode_SeriesGeometry); |
464 } | |
465 | |
466 static Operation* DownloadSliceImage(unsigned int sliceIndex, | |
467 const Slice& slice) | |
468 { | |
469 std::auto_ptr<Operation> tmp(new Operation(Mode_LoadImage)); | |
470 tmp->sliceIndex_ = sliceIndex; | |
471 tmp->slice_ = &slice; | |
472 return tmp.release(); | |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
473 } |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
474 }; |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
475 |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
476 ICallback& callback_; |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
477 IWebService& orthanc_; |
68 | 478 State state_; |
479 SliceSorter slices_; | |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
480 |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
481 |
68 | 482 void ParseSeriesGeometry(const void* answer, |
483 size_t size) | |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
484 { |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
485 Json::Value series; |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
486 if (!MessagingToolbox::ParseJson(series, answer, size) || |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
487 series.type() != Json::objectValue) |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
488 { |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
489 callback_.NotifyGeometryError(*this); |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
490 return; |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
491 } |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
492 |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
493 Json::Value::Members instances = series.getMemberNames(); |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
494 |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
495 slices_.Reserve(instances.size()); |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
496 |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
497 for (size_t i = 0; i < instances.size(); i++) |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
498 { |
68 | 499 OrthancPlugins::FullOrthancDataset dataset(series[instances[i]]); |
500 | |
501 Slice slice; | |
502 if (slice.ParseOrthancFrame(dataset, instances[i], 0 /* todo */)) | |
503 { | |
504 slices_.AddSlice(slice); | |
505 } | |
506 else | |
507 { | |
508 LOG(WARNING) << "Skipping invalid instance " << instances[i]; | |
509 } | |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
510 } |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
511 |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
512 bool ok = false; |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
513 |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
514 if (slices_.GetSliceCount() > 0) |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
515 { |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
516 Vector normal; |
68 | 517 if (slices_.SelectNormal(normal)) |
518 { | |
519 slices_.FilterNormal(normal); | |
520 slices_.SetNormal(normal); | |
521 slices_.Sort(); | |
522 ok = true; | |
523 } | |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
524 } |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
525 |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
526 if (ok) |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
527 { |
68 | 528 LOG(INFO) << "Loaded a series with " << slices_.GetSliceCount() << " slice(s)"; |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
529 callback_.NotifyGeometryReady(*this); |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
530 } |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
531 else |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
532 { |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
533 LOG(ERROR) << "This series is empty"; |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
534 callback_.NotifyGeometryError(*this); |
68 | 535 } |
536 } | |
537 | |
538 | |
539 void ParseSliceImage(const Operation& operation, | |
540 const void* answer, | |
541 size_t size) | |
542 { | |
543 std::auto_ptr<Orthanc::PngReader> image(new Orthanc::PngReader); | |
544 image->ReadFromMemory(answer, size); | |
545 | |
546 bool ok = (image->GetWidth() == operation.GetSlice().GetWidth() || | |
547 image->GetHeight() == operation.GetSlice().GetHeight()); | |
548 | |
549 if (ok && | |
550 operation.GetSlice().GetConverter().GetExpectedPixelFormat() == | |
551 Orthanc::PixelFormat_SignedGrayscale16) | |
552 { | |
553 if (image->GetFormat() == Orthanc::PixelFormat_Grayscale16) | |
554 { | |
555 image->SetFormat(Orthanc::PixelFormat_SignedGrayscale16); | |
556 } | |
557 else | |
558 { | |
559 ok = false; | |
560 } | |
561 } | |
562 | |
563 if (ok) | |
564 { | |
565 callback_.NotifySliceImageReady(*this, operation.GetSliceIndex(), | |
566 operation.GetSlice(), image.release()); | |
567 } | |
568 else | |
569 { | |
570 callback_.NotifySliceImageError(*this, operation.GetSliceIndex(), | |
571 operation.GetSlice()); | |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
572 } |
66 | 573 } |
574 | |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
575 |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
576 public: |
68 | 577 OrthancSliceLoader(ICallback& callback, |
578 IWebService& orthanc) : | |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
579 callback_(callback), |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
580 orthanc_(orthanc), |
68 | 581 state_(State_Initialization) |
582 { | |
583 } | |
584 | |
585 void ScheduleLoadSeries(const std::string& seriesId) | |
66 | 586 { |
68 | 587 if (state_ != State_Initialization) |
588 { | |
589 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
590 } | |
591 else | |
592 { | |
593 state_ = State_LoadingGeometry; | |
594 std::string uri = "/series/" + seriesId + "/instances-tags"; | |
595 orthanc_.ScheduleGetRequest(*this, uri, Operation::DownloadSeriesGeometry()); | |
596 } | |
597 } | |
598 | |
599 size_t GetSliceCount() const | |
600 { | |
601 if (state_ != State_GeometryReady) | |
602 { | |
603 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
604 } | |
605 | |
606 return slices_.GetSliceCount(); | |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
607 } |
66 | 608 |
68 | 609 const Slice& GetSlice(size_t index) const |
610 { | |
611 if (state_ != State_GeometryReady) | |
612 { | |
613 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
614 } | |
615 | |
616 return slices_.GetSlice(index); | |
617 } | |
618 | |
619 void ScheduleLoadSliceImage(size_t index) | |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
620 { |
68 | 621 if (state_ != State_GeometryReady) |
622 { | |
623 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
624 } | |
625 else | |
626 { | |
627 const Slice& slice = GetSlice(index); | |
628 | |
629 std::string uri = ("/instances/" + slice.GetOrthancInstanceId() + "/frames/" + | |
630 boost::lexical_cast<std::string>(slice.GetFrame())); | |
631 | |
632 switch (slice.GetConverter().GetExpectedPixelFormat()) | |
633 { | |
634 case Orthanc::PixelFormat_RGB24: | |
635 uri += "/preview"; | |
636 break; | |
637 | |
638 case Orthanc::PixelFormat_Grayscale16: | |
639 uri += "/image-uint16"; | |
640 break; | |
641 | |
642 case Orthanc::PixelFormat_SignedGrayscale16: | |
643 uri += "/image-int16"; | |
644 break; | |
645 | |
646 default: | |
647 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
648 } | |
649 | |
650 orthanc_.ScheduleGetRequest(*this, uri, Operation::DownloadSliceImage(index, slice)); | |
651 } | |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
652 } |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
653 |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
654 virtual void NotifySuccess(const std::string& uri, |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
655 const void* answer, |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
656 size_t answerSize, |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
657 Orthanc::IDynamicObject* payload) |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
658 { |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
659 std::auto_ptr<Operation> operation(dynamic_cast<Operation*>(payload)); |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
660 |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
661 switch (operation->GetMode()) |
66 | 662 { |
68 | 663 case Mode_SeriesGeometry: |
664 ParseSeriesGeometry(answer, answerSize); | |
665 state_ = State_GeometryReady; | |
666 break; | |
667 | |
668 case Mode_LoadImage: | |
669 ParseSliceImage(*operation, answer, answerSize); | |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
670 break; |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
671 |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
672 default: |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
673 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); |
66 | 674 } |
675 } | |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
676 |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
677 virtual void NotifyError(const std::string& uri, |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
678 Orthanc::IDynamicObject* payload) |
66 | 679 { |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
680 std::auto_ptr<Operation> operation(dynamic_cast<Operation*>(payload)); |
66 | 681 LOG(ERROR) << "Cannot download " << uri; |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
682 |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
683 switch (operation->GetMode()) |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
684 { |
68 | 685 case Mode_SeriesGeometry: |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
686 callback_.NotifyGeometryError(*this); |
68 | 687 state_ = State_Error; |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
688 break; |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
689 |
68 | 690 case Mode_LoadImage: |
691 callback_.NotifySliceImageError(*this, operation->GetSliceIndex(), operation->GetSlice()); | |
692 break; | |
693 | |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
694 default: |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
695 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
696 } |
66 | 697 } |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
698 }; |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
699 |
66 | 700 |
68 | 701 class Tata : public OrthancSliceLoader::ICallback |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
702 { |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
703 public: |
68 | 704 virtual void NotifyGeometryReady(const OrthancSliceLoader& loader) |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
705 { |
68 | 706 printf("Done\n"); |
707 } | |
708 | |
709 virtual void NotifyGeometryError(const OrthancSliceLoader& loader) | |
710 { | |
711 printf("Error\n"); | |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
712 } |
66 | 713 |
68 | 714 virtual void NotifySliceImageReady(const OrthancSliceLoader& loader, |
715 unsigned int sliceIndex, | |
716 const Slice& slice, | |
717 Orthanc::ImageAccessor* image) | |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
718 { |
68 | 719 std::auto_ptr<Orthanc::ImageAccessor> tmp(image); |
720 printf("Slice OK\n"); | |
721 } | |
722 | |
723 virtual void NotifySliceImageError(const OrthancSliceLoader& loader, | |
724 unsigned int sliceIndex, | |
725 const Slice& slice) | |
726 { | |
727 printf("ERROR 2\n"); | |
67
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
728 } |
acb60cbb8301
refactoring SeriesLoader
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
729 }; |
65
885932a893de
OrthancFrameLayerSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
47
diff
changeset
|
730 } |
885932a893de
OrthancFrameLayerSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
47
diff
changeset
|
731 |
885932a893de
OrthancFrameLayerSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
47
diff
changeset
|
732 |
885932a893de
OrthancFrameLayerSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
47
diff
changeset
|
733 TEST(Toto, Tutu) |
885932a893de
OrthancFrameLayerSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
47
diff
changeset
|
734 { |
885932a893de
OrthancFrameLayerSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
47
diff
changeset
|
735 Orthanc::WebServiceParameters web; |
69
1553b67b24e5
OrthancSynchronousWebService
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
68
diff
changeset
|
736 OrthancStone::OrthancSynchronousWebService orthanc(web); |
65
885932a893de
OrthancFrameLayerSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
47
diff
changeset
|
737 |
885932a893de
OrthancFrameLayerSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
47
diff
changeset
|
738 OrthancStone::Tata tata; |
68 | 739 OrthancStone::OrthancSliceLoader loader(tata, orthanc); |
740 //loader.ScheduleLoadSeries("c1c4cb95-05e3bd11-8da9f5bb-87278f71-0b2b43f5"); | |
741 loader.ScheduleLoadSeries("67f1b334-02c16752-45026e40-a5b60b6b-030ecab5"); | |
742 | |
743 printf(">> %d\n", loader.GetSliceCount()); | |
744 loader.ScheduleLoadSliceImage(31); | |
65
885932a893de
OrthancFrameLayerSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
47
diff
changeset
|
745 } |
885932a893de
OrthancFrameLayerSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
47
diff
changeset
|
746 |
885932a893de
OrthancFrameLayerSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
47
diff
changeset
|
747 |
20
946377d1c992
skeleton for unit tests
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
748 |
946377d1c992
skeleton for unit tests
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
749 int main(int argc, char **argv) |
946377d1c992
skeleton for unit tests
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
750 { |
946377d1c992
skeleton for unit tests
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
751 Orthanc::Logging::Initialize(); |
946377d1c992
skeleton for unit tests
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
752 Orthanc::Logging::EnableInfoLevel(true); |
946377d1c992
skeleton for unit tests
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
753 |
946377d1c992
skeleton for unit tests
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
754 ::testing::InitGoogleTest(&argc, argv); |
946377d1c992
skeleton for unit tests
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
755 int result = RUN_ALL_TESTS(); |
946377d1c992
skeleton for unit tests
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
756 |
946377d1c992
skeleton for unit tests
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
757 Orthanc::Logging::Finalize(); |
946377d1c992
skeleton for unit tests
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
758 |
946377d1c992
skeleton for unit tests
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
759 return result; |
946377d1c992
skeleton for unit tests
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
760 } |