Mercurial > hg > orthanc-stone
comparison OrthancStone/Sources/Loaders/OrthancSeriesVolumeProgressiveLoader.cpp @ 1640:52b8b96cb55f
cleaning namespaces
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 10 Nov 2020 16:55:22 +0100 |
parents | 8563ea5d8ae4 |
children | 9ac2a65d4172 |
comparison
equal
deleted
inserted
replaced
1639:5cdc5b98f14d | 1640:52b8b96cb55f |
---|---|
34 #include <OrthancException.h> | 34 #include <OrthancException.h> |
35 | 35 |
36 | 36 |
37 namespace OrthancStone | 37 namespace OrthancStone |
38 { | 38 { |
39 using OrthancStone::ILoadersContext; | 39 class OrthancSeriesVolumeProgressiveLoader::ExtractedSlice : public DicomVolumeImageMPRSlicer::Slice |
40 | |
41 class OrthancSeriesVolumeProgressiveLoader::ExtractedSlice : public OrthancStone::DicomVolumeImageMPRSlicer::Slice | |
42 { | 40 { |
43 private: | 41 private: |
44 const OrthancSeriesVolumeProgressiveLoader& that_; | 42 const OrthancSeriesVolumeProgressiveLoader& that_; |
45 | 43 |
46 public: | 44 public: |
47 ExtractedSlice(const OrthancSeriesVolumeProgressiveLoader& that, | 45 ExtractedSlice(const OrthancSeriesVolumeProgressiveLoader& that, |
48 const OrthancStone::CoordinateSystem3D& plane) : | 46 const CoordinateSystem3D& plane) : |
49 OrthancStone::DicomVolumeImageMPRSlicer::Slice(*that.volume_, plane), | 47 DicomVolumeImageMPRSlicer::Slice(*that.volume_, plane), |
50 that_(that) | 48 that_(that) |
51 { | 49 { |
52 if (IsValid()) | 50 if (IsValid()) |
53 { | 51 { |
54 if (GetProjection() == OrthancStone::VolumeProjection_Axial) | 52 if (GetProjection() == VolumeProjection_Axial) |
55 { | 53 { |
56 // For coronal and sagittal projections, we take the global | 54 // For coronal and sagittal projections, we take the global |
57 // revision of the volume because even if a single slice changes, | 55 // revision of the volume because even if a single slice changes, |
58 // this means the projection will yield a different result --> | 56 // this means the projection will yield a different result --> |
59 // we must increase the revision as soon as any slice changes | 57 // we must increase the revision as soon as any slice changes |
60 SetRevision(that_.seriesGeometry_.GetSliceRevision(GetSliceIndex())); | 58 SetRevision(that_.seriesGeometry_.GetSliceRevision(GetSliceIndex())); |
61 } | 59 } |
62 | 60 |
63 if (that_.strategy_.get() != NULL && | 61 if (that_.strategy_.get() != NULL && |
64 GetProjection() == OrthancStone::VolumeProjection_Axial) | 62 GetProjection() == VolumeProjection_Axial) |
65 { | 63 { |
66 that_.strategy_->SetCurrent(GetSliceIndex()); | 64 that_.strategy_->SetCurrent(GetSliceIndex()); |
67 } | 65 } |
68 } | 66 } |
69 } | 67 } |
70 }; | 68 }; |
71 | 69 |
72 void OrthancSeriesVolumeProgressiveLoader::SeriesGeometry::CheckSlice( | 70 void OrthancSeriesVolumeProgressiveLoader::SeriesGeometry::CheckSlice( |
73 size_t index, const OrthancStone::DicomInstanceParameters& reference) const | 71 size_t index, const DicomInstanceParameters& reference) const |
74 { | 72 { |
75 const OrthancStone::DicomInstanceParameters& slice = *slices_[index]; | 73 const DicomInstanceParameters& slice = *slices_[index]; |
76 | 74 |
77 if (!OrthancStone::GeometryToolbox::IsParallel( | 75 if (!GeometryToolbox::IsParallel( |
78 reference.GetGeometry().GetNormal(), | 76 reference.GetGeometry().GetNormal(), |
79 slice.GetGeometry().GetNormal())) | 77 slice.GetGeometry().GetNormal())) |
80 { | 78 { |
81 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadGeometry, | 79 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadGeometry, |
82 "A slice in the volume image is not parallel to the others"); | 80 "A slice in the volume image is not parallel to the others"); |
93 { | 91 { |
94 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageSize, | 92 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageSize, |
95 "The width/height of slices are not constant in the volume image"); | 93 "The width/height of slices are not constant in the volume image"); |
96 } | 94 } |
97 | 95 |
98 if (!OrthancStone::LinearAlgebra::IsNear(reference.GetPixelSpacingX(), slice.GetPixelSpacingX()) || | 96 if (!LinearAlgebra::IsNear(reference.GetPixelSpacingX(), slice.GetPixelSpacingX()) || |
99 !OrthancStone::LinearAlgebra::IsNear(reference.GetPixelSpacingY(), slice.GetPixelSpacingY())) | 97 !LinearAlgebra::IsNear(reference.GetPixelSpacingY(), slice.GetPixelSpacingY())) |
100 { | 98 { |
101 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadGeometry, | 99 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadGeometry, |
102 "The pixel spacing of the slices change across the volume image"); | 100 "The pixel spacing of the slices change across the volume image"); |
103 } | 101 } |
104 } | 102 } |
116 } | 114 } |
117 } | 115 } |
118 | 116 |
119 if (slices_.size() != 0) | 117 if (slices_.size() != 0) |
120 { | 118 { |
121 const OrthancStone::DicomInstanceParameters& reference = *slices_[0]; | 119 const DicomInstanceParameters& reference = *slices_[0]; |
122 | 120 |
123 for (size_t i = 1; i < slices_.size(); i++) | 121 for (size_t i = 1; i < slices_.size(); i++) |
124 { | 122 { |
125 CheckSlice(i, reference); | 123 CheckSlice(i, reference); |
126 } | 124 } |
160 } | 158 } |
161 | 159 |
162 | 160 |
163 // WARNING: The payload of "slices" must be of class "DicomInstanceParameters" | 161 // WARNING: The payload of "slices" must be of class "DicomInstanceParameters" |
164 // (called with the slices created in LoadGeometry) | 162 // (called with the slices created in LoadGeometry) |
165 void OrthancSeriesVolumeProgressiveLoader::SeriesGeometry::ComputeGeometry(OrthancStone::SlicesSorter& slices) | 163 void OrthancSeriesVolumeProgressiveLoader::SeriesGeometry::ComputeGeometry(SlicesSorter& slices) |
166 { | 164 { |
167 Clear(); | 165 Clear(); |
168 | 166 |
169 if (!slices.Sort()) | 167 if (!slices.Sort()) |
170 { | 168 { |
172 "Cannot sort the 3D slices of a DICOM series"); | 170 "Cannot sort the 3D slices of a DICOM series"); |
173 } | 171 } |
174 | 172 |
175 if (slices.GetSlicesCount() == 0) | 173 if (slices.GetSlicesCount() == 0) |
176 { | 174 { |
177 geometry_.reset(new OrthancStone::VolumeImageGeometry); | 175 geometry_.reset(new VolumeImageGeometry); |
178 } | 176 } |
179 else | 177 else |
180 { | 178 { |
181 slices_.reserve(slices.GetSlicesCount()); | 179 slices_.reserve(slices.GetSlicesCount()); |
182 slicesRevision_.resize(slices.GetSlicesCount(), 0); | 180 slicesRevision_.resize(slices.GetSlicesCount(), 0); |
183 | 181 |
184 for (size_t i = 0; i < slices.GetSlicesCount(); i++) | 182 for (size_t i = 0; i < slices.GetSlicesCount(); i++) |
185 { | 183 { |
186 const OrthancStone::DicomInstanceParameters& slice = | 184 const DicomInstanceParameters& slice = |
187 dynamic_cast<const OrthancStone::DicomInstanceParameters&>(slices.GetSlicePayload(i)); | 185 dynamic_cast<const DicomInstanceParameters&>(slices.GetSlicePayload(i)); |
188 slices_.push_back(new OrthancStone::DicomInstanceParameters(slice)); | 186 slices_.push_back(new DicomInstanceParameters(slice)); |
189 } | 187 } |
190 | 188 |
191 CheckVolume(); | 189 CheckVolume(); |
192 | 190 |
193 double spacingZ; | 191 double spacingZ; |
194 | 192 |
195 if (slices.ComputeSpacingBetweenSlices(spacingZ)) | 193 if (slices.ComputeSpacingBetweenSlices(spacingZ)) |
196 { | 194 { |
197 LOG(TRACE) << "Computed spacing between slices: " << spacingZ << "mm"; | 195 LOG(TRACE) << "Computed spacing between slices: " << spacingZ << "mm"; |
198 | 196 |
199 const OrthancStone::DicomInstanceParameters& parameters = *slices_[0]; | 197 const DicomInstanceParameters& parameters = *slices_[0]; |
200 | 198 |
201 geometry_.reset(new OrthancStone::VolumeImageGeometry); | 199 geometry_.reset(new VolumeImageGeometry); |
202 geometry_->SetSizeInVoxels(parameters.GetImageInformation().GetWidth(), | 200 geometry_->SetSizeInVoxels(parameters.GetImageInformation().GetWidth(), |
203 parameters.GetImageInformation().GetHeight(), | 201 parameters.GetImageInformation().GetHeight(), |
204 static_cast<unsigned int>(slices.GetSlicesCount())); | 202 static_cast<unsigned int>(slices.GetSlicesCount())); |
205 geometry_->SetAxialGeometry(slices.GetSliceGeometry(0)); | 203 geometry_->SetAxialGeometry(slices.GetSliceGeometry(0)); |
206 geometry_->SetVoxelDimensions(parameters.GetPixelSpacingX(), | 204 geometry_->SetVoxelDimensions(parameters.GetPixelSpacingX(), |
213 } | 211 } |
214 } | 212 } |
215 } | 213 } |
216 | 214 |
217 | 215 |
218 const OrthancStone::VolumeImageGeometry& OrthancSeriesVolumeProgressiveLoader::SeriesGeometry::GetImageGeometry() const | 216 const VolumeImageGeometry& OrthancSeriesVolumeProgressiveLoader::SeriesGeometry::GetImageGeometry() const |
219 { | 217 { |
220 if (!HasGeometry()) | 218 if (!HasGeometry()) |
221 { | 219 { |
222 LOG(ERROR) << "OrthancSeriesVolumeProgressiveLoader::SeriesGeometry::GetImageGeometry(): (!HasGeometry())"; | 220 LOG(ERROR) << "OrthancSeriesVolumeProgressiveLoader::SeriesGeometry::GetImageGeometry(): (!HasGeometry())"; |
223 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | 221 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); |
228 return *geometry_; | 226 return *geometry_; |
229 } | 227 } |
230 } | 228 } |
231 | 229 |
232 | 230 |
233 const OrthancStone::DicomInstanceParameters& OrthancSeriesVolumeProgressiveLoader::SeriesGeometry::GetSliceParameters(size_t index) const | 231 const DicomInstanceParameters& OrthancSeriesVolumeProgressiveLoader::SeriesGeometry::GetSliceParameters(size_t index) const |
234 { | 232 { |
235 CheckSliceIndex(index); | 233 CheckSliceIndex(index); |
236 return *slices_[index]; | 234 return *slices_[index]; |
237 } | 235 } |
238 | 236 |
249 CheckSliceIndex(index); | 247 CheckSliceIndex(index); |
250 slicesRevision_[index] ++; | 248 slicesRevision_[index] ++; |
251 } | 249 } |
252 | 250 |
253 | 251 |
254 static unsigned int GetSliceIndexPayload(const OrthancStone::OracleCommandBase& command) | 252 static unsigned int GetSliceIndexPayload(const OracleCommandBase& command) |
255 { | 253 { |
256 assert(command.HasPayload()); | 254 assert(command.HasPayload()); |
257 return dynamic_cast< const Orthanc::SingleValueObject<unsigned int>& >(command.GetPayload()).GetValue(); | 255 return dynamic_cast< const Orthanc::SingleValueObject<unsigned int>& >(command.GetPayload()).GetValue(); |
258 } | 256 } |
259 | 257 |
270 { | 268 { |
271 ORTHANC_ASSERT(quality == QUALITY_00, "INTERNAL ERROR. quality != QUALITY_00 in " | 269 ORTHANC_ASSERT(quality == QUALITY_00, "INTERNAL ERROR. quality != QUALITY_00 in " |
272 << "OrthancSeriesVolumeProgressiveLoader::ScheduleNextSliceDownload"); | 270 << "OrthancSeriesVolumeProgressiveLoader::ScheduleNextSliceDownload"); |
273 } | 271 } |
274 | 272 |
275 const OrthancStone::DicomInstanceParameters& slice = seriesGeometry_.GetSliceParameters(sliceIndex); | 273 const DicomInstanceParameters& slice = seriesGeometry_.GetSliceParameters(sliceIndex); |
276 | 274 |
277 const std::string& instance = slice.GetOrthancInstanceIdentifier(); | 275 const std::string& instance = slice.GetOrthancInstanceIdentifier(); |
278 if (instance.empty()) | 276 if (instance.empty()) |
279 { | 277 { |
280 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | 278 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); |
281 } | 279 } |
282 | 280 |
283 std::unique_ptr<OrthancStone::OracleCommandBase> command; | 281 std::unique_ptr<OracleCommandBase> command; |
284 | 282 |
285 if (!progressiveQuality_ || quality == QUALITY_02) | 283 if (!progressiveQuality_ || quality == QUALITY_02) |
286 { | 284 { |
287 std::unique_ptr<OrthancStone::GetOrthancImageCommand> tmp(new OrthancStone::GetOrthancImageCommand); | 285 std::unique_ptr<GetOrthancImageCommand> tmp(new GetOrthancImageCommand); |
288 // TODO: review the following comment. | 286 // TODO: review the following comment. |
289 // - Commented out by bgo on 2019-07-19 | reason: Alain has seen cases | 287 // - Commented out by bgo on 2019-07-19 | reason: Alain has seen cases |
290 // where gzipping the uint16 image took 11 sec to produce 5mb. | 288 // where gzipping the uint16 image took 11 sec to produce 5mb. |
291 // The unzipped request was much much faster. | 289 // The unzipped request was much much faster. |
292 // - Re-enabled on 2019-07-30. Reason: in Web Assembly, the browser | 290 // - Re-enabled on 2019-07-30. Reason: in Web Assembly, the browser |
302 // << " URI = " << tmp->GetUri(); | 300 // << " URI = " << tmp->GetUri(); |
303 command.reset(tmp.release()); | 301 command.reset(tmp.release()); |
304 } | 302 } |
305 else // progressive mode is true AND quality is not final (different from QUALITY_02 | 303 else // progressive mode is true AND quality is not final (different from QUALITY_02 |
306 { | 304 { |
307 std::unique_ptr<OrthancStone::GetOrthancWebViewerJpegCommand> tmp( | 305 std::unique_ptr<GetOrthancWebViewerJpegCommand> tmp( |
308 new OrthancStone::GetOrthancWebViewerJpegCommand); | 306 new GetOrthancWebViewerJpegCommand); |
309 | 307 |
310 // TODO: review the following comment. Commented out by bgo on 2019-07-19 | 308 // TODO: review the following comment. Commented out by bgo on 2019-07-19 |
311 // (gzip for jpeg seems overkill) | 309 // (gzip for jpeg seems overkill) |
312 //tmp->SetHttpHeader("Accept-Encoding", "gzip"); | 310 //tmp->SetHttpHeader("Accept-Encoding", "gzip"); |
313 tmp->SetInstance(instance); | 311 tmp->SetInstance(instance); |
320 } | 318 } |
321 | 319 |
322 command->AcquirePayload(new Orthanc::SingleValueObject<unsigned int>(sliceIndex)); | 320 command->AcquirePayload(new Orthanc::SingleValueObject<unsigned int>(sliceIndex)); |
323 | 321 |
324 { | 322 { |
325 std::unique_ptr<OrthancStone::ILoadersContext::ILock> lock(loadersContext_.Lock()); | 323 std::unique_ptr<ILoadersContext::ILock> lock(loadersContext_.Lock()); |
326 boost::shared_ptr<IObserver> observer(GetSharedObserver()); | 324 boost::shared_ptr<IObserver> observer(GetSharedObserver()); |
327 lock->Schedule(observer, sliceSchedulingPriority_, command.release()); | 325 lock->Schedule(observer, sliceSchedulingPriority_, command.release()); |
328 } | 326 } |
329 } | 327 } |
330 else | 328 else |
336 } | 334 } |
337 | 335 |
338 /** | 336 /** |
339 This is called in response to GET "/series/XXXXXXXXXXXXX/instances-tags" | 337 This is called in response to GET "/series/XXXXXXXXXXXXX/instances-tags" |
340 */ | 338 */ |
341 void OrthancSeriesVolumeProgressiveLoader::LoadGeometry(const OrthancStone::OrthancRestApiCommand::SuccessMessage& message) | 339 void OrthancSeriesVolumeProgressiveLoader::LoadGeometry(const OrthancRestApiCommand::SuccessMessage& message) |
342 { | 340 { |
343 Json::Value body; | 341 Json::Value body; |
344 message.ParseJsonBody(body); | 342 message.ParseJsonBody(body); |
345 | 343 |
346 if (body.type() != Json::objectValue) | 344 if (body.type() != Json::objectValue) |
349 } | 347 } |
350 | 348 |
351 { | 349 { |
352 Json::Value::Members instances = body.getMemberNames(); | 350 Json::Value::Members instances = body.getMemberNames(); |
353 | 351 |
354 OrthancStone::SlicesSorter slices; | 352 SlicesSorter slices; |
355 | 353 |
356 for (size_t i = 0; i < instances.size(); i++) | 354 for (size_t i = 0; i < instances.size(); i++) |
357 { | 355 { |
358 Orthanc::DicomMap dicom; | 356 Orthanc::DicomMap dicom; |
359 dicom.FromDicomAsJson(body[instances[i]]); | 357 dicom.FromDicomAsJson(body[instances[i]]); |
360 | 358 |
361 std::unique_ptr<OrthancStone::DicomInstanceParameters> instance(new OrthancStone::DicomInstanceParameters(dicom)); | 359 std::unique_ptr<DicomInstanceParameters> instance(new DicomInstanceParameters(dicom)); |
362 instance->SetOrthancInstanceIdentifier(instances[i]); | 360 instance->SetOrthancInstanceIdentifier(instances[i]); |
363 | 361 |
364 // the 3D plane corresponding to the slice | 362 // the 3D plane corresponding to the slice |
365 OrthancStone::CoordinateSystem3D geometry = instance->GetGeometry(); | 363 CoordinateSystem3D geometry = instance->GetGeometry(); |
366 slices.AddSlice(geometry, instance.release()); | 364 slices.AddSlice(geometry, instance.release()); |
367 | 365 |
368 if (slicePostProcessor_) | 366 if (slicePostProcessor_) |
369 slicePostProcessor_->ProcessCTDicomSlice(dicom); | 367 slicePostProcessor_->ProcessCTDicomSlice(dicom); |
370 } | 368 } |
378 { | 376 { |
379 volume_->Initialize(seriesGeometry_.GetImageGeometry(), Orthanc::PixelFormat_Grayscale8); | 377 volume_->Initialize(seriesGeometry_.GetImageGeometry(), Orthanc::PixelFormat_Grayscale8); |
380 } | 378 } |
381 else | 379 else |
382 { | 380 { |
383 const OrthancStone::DicomInstanceParameters& parameters = seriesGeometry_.GetSliceParameters(0); | 381 const DicomInstanceParameters& parameters = seriesGeometry_.GetSliceParameters(0); |
384 | 382 |
385 volume_->Initialize(seriesGeometry_.GetImageGeometry(), parameters.GetExpectedPixelFormat()); | 383 volume_->Initialize(seriesGeometry_.GetImageGeometry(), parameters.GetExpectedPixelFormat()); |
386 volume_->SetDicomParameters(parameters); | 384 volume_->SetDicomParameters(parameters); |
387 volume_->GetPixelData().Clear(); | 385 volume_->GetPixelData().Clear(); |
388 | 386 |
390 // QUALITY_02... Otherwise, it's only QUALITY_00 | 388 // QUALITY_02... Otherwise, it's only QUALITY_00 |
391 unsigned int maxQuality = QUALITY_00; | 389 unsigned int maxQuality = QUALITY_00; |
392 if (progressiveQuality_) | 390 if (progressiveQuality_) |
393 maxQuality = QUALITY_02; | 391 maxQuality = QUALITY_02; |
394 | 392 |
395 strategy_.reset(new OrthancStone::BasicFetchingStrategy( | 393 strategy_.reset(new BasicFetchingStrategy( |
396 sorter_->CreateSorter(static_cast<unsigned int>(slicesCount)), | 394 sorter_->CreateSorter(static_cast<unsigned int>(slicesCount)), |
397 maxQuality)); | 395 maxQuality)); |
398 | 396 |
399 assert(simultaneousDownloads_ != 0); | 397 assert(simultaneousDownloads_ != 0); |
400 for (unsigned int i = 0; i < simultaneousDownloads_; i++) | 398 for (unsigned int i = 0; i < simultaneousDownloads_; i++) |
403 } | 401 } |
404 } | 402 } |
405 | 403 |
406 slicesQuality_.resize(slicesCount, 0); | 404 slicesQuality_.resize(slicesCount, 0); |
407 | 405 |
408 BroadcastMessage(OrthancStone::DicomVolumeImage::GeometryReadyMessage(*volume_)); | 406 BroadcastMessage(DicomVolumeImage::GeometryReadyMessage(*volume_)); |
409 } | 407 } |
410 | 408 |
411 | 409 |
412 void OrthancSeriesVolumeProgressiveLoader::SetSliceContent(unsigned int sliceIndex, | 410 void OrthancSeriesVolumeProgressiveLoader::SetSliceContent(unsigned int sliceIndex, |
413 const Orthanc::ImageAccessor& image, | 411 const Orthanc::ImageAccessor& image, |
423 } | 421 } |
424 | 422 |
425 if (quality >= slicesQuality_[sliceIndex]) | 423 if (quality >= slicesQuality_[sliceIndex]) |
426 { | 424 { |
427 { | 425 { |
428 OrthancStone::ImageBuffer3D::SliceWriter writer(volume_->GetPixelData(), | 426 ImageBuffer3D::SliceWriter writer(volume_->GetPixelData(), |
429 OrthancStone::VolumeProjection_Axial, | 427 VolumeProjection_Axial, |
430 sliceIndex); | 428 sliceIndex); |
431 | 429 |
432 Orthanc::ImageProcessing::Copy(writer.GetAccessor(), image); | 430 Orthanc::ImageProcessing::Copy(writer.GetAccessor(), image); |
433 } | 431 } |
434 | 432 |
435 volume_->IncrementRevision(); | 433 volume_->IncrementRevision(); |
436 seriesGeometry_.IncrementSliceRevision(sliceIndex); | 434 seriesGeometry_.IncrementSliceRevision(sliceIndex); |
437 slicesQuality_[sliceIndex] = quality; | 435 slicesQuality_[sliceIndex] = quality; |
438 | 436 |
439 BroadcastMessage(OrthancStone::DicomVolumeImage::ContentUpdatedMessage(*volume_)); | 437 BroadcastMessage(DicomVolumeImage::ContentUpdatedMessage(*volume_)); |
440 } | 438 } |
441 LOG(TRACE) << "SetSliceContent sliceIndex = " << sliceIndex << " -- will " | 439 LOG(TRACE) << "SetSliceContent sliceIndex = " << sliceIndex << " -- will " |
442 << " now call ScheduleNextSliceDownload()"; | 440 << " now call ScheduleNextSliceDownload()"; |
443 ScheduleNextSliceDownload(); | 441 ScheduleNextSliceDownload(); |
444 } | 442 } |
445 | 443 |
446 void OrthancSeriesVolumeProgressiveLoader::LoadBestQualitySliceContent( | 444 void OrthancSeriesVolumeProgressiveLoader::LoadBestQualitySliceContent( |
447 const OrthancStone::GetOrthancImageCommand::SuccessMessage& message) | 445 const GetOrthancImageCommand::SuccessMessage& message) |
448 { | 446 { |
449 unsigned int quality = QUALITY_00; | 447 unsigned int quality = QUALITY_00; |
450 if (progressiveQuality_) | 448 if (progressiveQuality_) |
451 quality = QUALITY_02; | 449 quality = QUALITY_02; |
452 | 450 |
454 message.GetImage(), | 452 message.GetImage(), |
455 quality); | 453 quality); |
456 } | 454 } |
457 | 455 |
458 void OrthancSeriesVolumeProgressiveLoader::LoadJpegSliceContent( | 456 void OrthancSeriesVolumeProgressiveLoader::LoadJpegSliceContent( |
459 const OrthancStone::GetOrthancWebViewerJpegCommand::SuccessMessage& message) | 457 const GetOrthancWebViewerJpegCommand::SuccessMessage& message) |
460 { | 458 { |
461 ORTHANC_ASSERT(progressiveQuality_, "INTERNAL ERROR: OrthancSeriesVolumeProgressiveLoader::LoadJpegSliceContent" | 459 ORTHANC_ASSERT(progressiveQuality_, "INTERNAL ERROR: OrthancSeriesVolumeProgressiveLoader::LoadJpegSliceContent" |
462 << " called while progressiveQuality_ is false!"); | 460 << " called while progressiveQuality_ is false!"); |
463 | 461 |
464 LOG(TRACE) << "OrthancSeriesVolumeProgressiveLoader::LoadJpegSliceContent"; | 462 LOG(TRACE) << "OrthancSeriesVolumeProgressiveLoader::LoadJpegSliceContent"; |
465 unsigned int quality; | 463 unsigned int quality; |
466 | 464 |
467 switch (dynamic_cast<const OrthancStone::GetOrthancWebViewerJpegCommand&>(message.GetOrigin()).GetQuality()) | 465 switch (dynamic_cast<const GetOrthancWebViewerJpegCommand&>(message.GetOrigin()).GetQuality()) |
468 { | 466 { |
469 case 50: | 467 case 50: |
470 quality = QUALITY_00; | 468 quality = QUALITY_00; |
471 break; | 469 break; |
472 | 470 |
507 medadataSchedulingPriority_ = p; | 505 medadataSchedulingPriority_ = p; |
508 sliceSchedulingPriority_ = p; | 506 sliceSchedulingPriority_ = p; |
509 } | 507 } |
510 | 508 |
511 OrthancSeriesVolumeProgressiveLoader::OrthancSeriesVolumeProgressiveLoader( | 509 OrthancSeriesVolumeProgressiveLoader::OrthancSeriesVolumeProgressiveLoader( |
512 OrthancStone::ILoadersContext& loadersContext, | 510 ILoadersContext& loadersContext, |
513 boost::shared_ptr<OrthancStone::DicomVolumeImage> volume, | 511 boost::shared_ptr<DicomVolumeImage> volume, |
514 bool progressiveQuality) | 512 bool progressiveQuality) |
515 : loadersContext_(loadersContext) | 513 : loadersContext_(loadersContext) |
516 , active_(false) | 514 , active_(false) |
517 , progressiveQuality_(progressiveQuality) | 515 , progressiveQuality_(progressiveQuality) |
518 , simultaneousDownloads_(4) | 516 , simultaneousDownloads_(4) |
519 , volume_(volume) | 517 , volume_(volume) |
520 , sorter_(new OrthancStone::BasicFetchingItemsSorter::Factory) | 518 , sorter_(new BasicFetchingItemsSorter::Factory) |
521 , volumeImageReadyInHighQuality_(false) | 519 , volumeImageReadyInHighQuality_(false) |
522 , medadataSchedulingPriority_(0) | 520 , medadataSchedulingPriority_(0) |
523 , sliceSchedulingPriority_(0) | 521 , sliceSchedulingPriority_(0) |
524 { | 522 { |
525 } | 523 } |
526 | 524 |
527 boost::shared_ptr<OrthancSeriesVolumeProgressiveLoader> | 525 boost::shared_ptr<OrthancSeriesVolumeProgressiveLoader> |
528 OrthancSeriesVolumeProgressiveLoader::Create( | 526 OrthancSeriesVolumeProgressiveLoader::Create( |
529 OrthancStone::ILoadersContext& loadersContext, | 527 ILoadersContext& loadersContext, |
530 boost::shared_ptr<OrthancStone::DicomVolumeImage> volume, | 528 boost::shared_ptr<DicomVolumeImage> volume, |
531 bool progressiveQuality) | 529 bool progressiveQuality) |
532 { | 530 { |
533 std::unique_ptr<OrthancStone::ILoadersContext::ILock> lock(loadersContext.Lock()); | 531 std::unique_ptr<ILoadersContext::ILock> lock(loadersContext.Lock()); |
534 | 532 |
535 boost::shared_ptr<OrthancSeriesVolumeProgressiveLoader> obj( | 533 boost::shared_ptr<OrthancSeriesVolumeProgressiveLoader> obj( |
536 new OrthancSeriesVolumeProgressiveLoader( | 534 new OrthancSeriesVolumeProgressiveLoader( |
537 loadersContext, volume, progressiveQuality)); | 535 loadersContext, volume, progressiveQuality)); |
538 | 536 |
539 obj->Register<OrthancStone::OrthancRestApiCommand::SuccessMessage>( | 537 obj->Register<OrthancRestApiCommand::SuccessMessage>( |
540 lock->GetOracleObservable(), | 538 lock->GetOracleObservable(), |
541 &OrthancSeriesVolumeProgressiveLoader::LoadGeometry); | 539 &OrthancSeriesVolumeProgressiveLoader::LoadGeometry); |
542 | 540 |
543 obj->Register<OrthancStone::GetOrthancImageCommand::SuccessMessage>( | 541 obj->Register<GetOrthancImageCommand::SuccessMessage>( |
544 lock->GetOracleObservable(), | 542 lock->GetOracleObservable(), |
545 &OrthancSeriesVolumeProgressiveLoader::LoadBestQualitySliceContent); | 543 &OrthancSeriesVolumeProgressiveLoader::LoadBestQualitySliceContent); |
546 | 544 |
547 obj->Register<OrthancStone::GetOrthancWebViewerJpegCommand::SuccessMessage>( | 545 obj->Register<GetOrthancWebViewerJpegCommand::SuccessMessage>( |
548 lock->GetOracleObservable(), | 546 lock->GetOracleObservable(), |
549 &OrthancSeriesVolumeProgressiveLoader::LoadJpegSliceContent); | 547 &OrthancSeriesVolumeProgressiveLoader::LoadJpegSliceContent); |
550 | 548 |
551 return obj; | 549 return obj; |
552 } | 550 } |
584 } | 582 } |
585 else | 583 else |
586 { | 584 { |
587 active_ = true; | 585 active_ = true; |
588 | 586 |
589 std::unique_ptr<OrthancStone::OrthancRestApiCommand> command(new OrthancStone::OrthancRestApiCommand); | 587 std::unique_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand); |
590 command->SetUri("/series/" + seriesId + "/instances-tags"); | 588 command->SetUri("/series/" + seriesId + "/instances-tags"); |
591 { | 589 { |
592 std::unique_ptr<OrthancStone::ILoadersContext::ILock> lock(loadersContext_.Lock()); | 590 std::unique_ptr<ILoadersContext::ILock> lock(loadersContext_.Lock()); |
593 boost::shared_ptr<IObserver> observer(GetSharedObserver()); | 591 boost::shared_ptr<IObserver> observer(GetSharedObserver()); |
594 lock->Schedule(observer, medadataSchedulingPriority_, command.release()); | 592 lock->Schedule(observer, medadataSchedulingPriority_, command.release()); |
595 } | 593 } |
596 } | 594 } |
597 } | 595 } |
598 | 596 |
599 | 597 |
600 OrthancStone::IVolumeSlicer::IExtractedSlice* | 598 IVolumeSlicer::IExtractedSlice* |
601 OrthancSeriesVolumeProgressiveLoader::ExtractSlice(const OrthancStone::CoordinateSystem3D& cuttingPlane) | 599 OrthancSeriesVolumeProgressiveLoader::ExtractSlice(const CoordinateSystem3D& cuttingPlane) |
602 { | 600 { |
603 if (volume_->HasGeometry()) | 601 if (volume_->HasGeometry()) |
604 { | 602 { |
605 return new ExtractedSlice(*this, cuttingPlane); | 603 return new ExtractedSlice(*this, cuttingPlane); |
606 } | 604 } |