Mercurial > hg > orthanc-stone
comparison Framework/Deprecated/Loaders/OrthancSeriesVolumeProgressiveLoader.cpp @ 1327:4f8db2d202c8 broker
OrthancSeriesProgressiveLoader now has two modes that
can be selected at object creation :
- progressive (will first load jpeg50, then jpeg90 then PAM)
- non-progressive (will directly load PAM (uncompressed))
Please note that the slice loading order remains dynamic
and depending upon the slice that the client code wishes
to extract from the volume.
author | Benjamin Golinvaux <bgo@osimis.io> |
---|---|
date | Wed, 25 Mar 2020 14:34:27 +0100 |
parents | 7702ad9b7011 |
children |
comparison
equal
deleted
inserted
replaced
1326:55166e57a77c | 1327:4f8db2d202c8 |
---|---|
19 **/ | 19 **/ |
20 | 20 |
21 | 21 |
22 #include "OrthancSeriesVolumeProgressiveLoader.h" | 22 #include "OrthancSeriesVolumeProgressiveLoader.h" |
23 | 23 |
24 #include "../../StoneException.h" | |
24 #include "../../Loaders/ILoadersContext.h" | 25 #include "../../Loaders/ILoadersContext.h" |
25 #include "../../Loaders/BasicFetchingItemsSorter.h" | 26 #include "../../Loaders/BasicFetchingItemsSorter.h" |
26 #include "../../Loaders/BasicFetchingStrategy.h" | 27 #include "../../Loaders/BasicFetchingStrategy.h" |
27 #include "../../Toolbox/GeometryToolbox.h" | 28 #include "../../Toolbox/GeometryToolbox.h" |
28 #include "../../Volumes/DicomVolumeImageMPRSlicer.h" | 29 #include "../../Volumes/DicomVolumeImageMPRSlicer.h" |
62 that_.strategy_->SetCurrent(GetSliceIndex()); | 63 that_.strategy_->SetCurrent(GetSliceIndex()); |
63 } | 64 } |
64 } | 65 } |
65 } | 66 } |
66 }; | 67 }; |
67 | |
68 | 68 |
69 | 69 void OrthancSeriesVolumeProgressiveLoader::SeriesGeometry::CheckSlice( |
70 void OrthancSeriesVolumeProgressiveLoader::SeriesGeometry::CheckSlice(size_t index, | 70 size_t index, const OrthancStone::DicomInstanceParameters& reference) const |
71 const OrthancStone::DicomInstanceParameters& reference) const | |
72 { | 71 { |
73 const OrthancStone::DicomInstanceParameters& slice = *slices_[index]; | 72 const OrthancStone::DicomInstanceParameters& slice = *slices_[index]; |
74 | 73 |
75 if (!OrthancStone::GeometryToolbox::IsParallel( | 74 if (!OrthancStone::GeometryToolbox::IsParallel( |
76 reference.GetGeometry().GetNormal(), | 75 reference.GetGeometry().GetNormal(), |
258 | 257 |
259 void OrthancSeriesVolumeProgressiveLoader::ScheduleNextSliceDownload() | 258 void OrthancSeriesVolumeProgressiveLoader::ScheduleNextSliceDownload() |
260 { | 259 { |
261 assert(strategy_.get() != NULL); | 260 assert(strategy_.get() != NULL); |
262 | 261 |
263 unsigned int sliceIndex, quality; | 262 unsigned int sliceIndex = 0, quality = 0; |
264 | 263 |
265 if (strategy_->GetNext(sliceIndex, quality)) | 264 if (strategy_->GetNext(sliceIndex, quality)) |
266 { | 265 { |
267 | 266 if (!progressiveQuality_) |
268 #if USE_SINGLE_QUALITY | 267 { |
269 assert(quality == SINGLE_QUALITY); | 268 ORTHANC_ASSERT(quality == QUALITY_00, "INTERNAL ERROR. quality != QUALITY_00 in " |
270 #else | 269 << "OrthancSeriesVolumeProgressiveLoader::ScheduleNextSliceDownload"); |
271 assert(quality <= BEST_QUALITY); | 270 } |
272 #endif | |
273 | 271 |
274 const OrthancStone::DicomInstanceParameters& slice = seriesGeometry_.GetSliceParameters(sliceIndex); | 272 const OrthancStone::DicomInstanceParameters& slice = seriesGeometry_.GetSliceParameters(sliceIndex); |
275 | 273 |
276 const std::string& instance = slice.GetOrthancInstanceIdentifier(); | 274 const std::string& instance = slice.GetOrthancInstanceIdentifier(); |
277 if (instance.empty()) | 275 if (instance.empty()) |
279 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | 277 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); |
280 } | 278 } |
281 | 279 |
282 std::unique_ptr<OrthancStone::OracleCommandBase> command; | 280 std::unique_ptr<OrthancStone::OracleCommandBase> command; |
283 | 281 |
284 #if USE_SINGLE_QUALITY | 282 if (!progressiveQuality_ || quality == QUALITY_02) |
285 #else | |
286 if (quality == BEST_QUALITY) | |
287 #endif | |
288 { | 283 { |
289 std::unique_ptr<OrthancStone::GetOrthancImageCommand> tmp(new OrthancStone::GetOrthancImageCommand); | 284 std::unique_ptr<OrthancStone::GetOrthancImageCommand> tmp(new OrthancStone::GetOrthancImageCommand); |
290 // TODO: review the following comment. | 285 // TODO: review the following comment. |
291 // - Commented out by bgo on 2019-07-19 | reason: Alain has seen cases | 286 // - Commented out by bgo on 2019-07-19 | reason: Alain has seen cases |
292 // where gzipping the uint16 image took 11 sec to produce 5mb. | 287 // where gzipping the uint16 image took 11 sec to produce 5mb. |
302 // << "OrthancSeriesVolumeProgressiveLoader.ScheduleNextSliceDownload()" | 297 // << "OrthancSeriesVolumeProgressiveLoader.ScheduleNextSliceDownload()" |
303 // << " sliceIndex = " << sliceIndex << " slice quality = " << quality | 298 // << " sliceIndex = " << sliceIndex << " slice quality = " << quality |
304 // << " URI = " << tmp->GetUri(); | 299 // << " URI = " << tmp->GetUri(); |
305 command.reset(tmp.release()); | 300 command.reset(tmp.release()); |
306 } | 301 } |
307 #if USE_SINGLE_QUALITY | 302 else // progressive mode is true AND quality is not final (different from QUALITY_02 |
308 #else | 303 { |
309 else | 304 std::unique_ptr<OrthancStone::GetOrthancWebViewerJpegCommand> tmp( |
310 { | 305 new OrthancStone::GetOrthancWebViewerJpegCommand); |
311 std::unique_ptr<OrthancStone::GetOrthancWebViewerJpegCommand> tmp(new OrthancStone::GetOrthancWebViewerJpegCommand); | 306 |
312 // TODO: review the following comment. Commented out by bgo on 2019-07-19 | 307 // TODO: review the following comment. Commented out by bgo on 2019-07-19 |
313 // (gzip for jpeg seems overkill) | 308 // (gzip for jpeg seems overkill) |
314 //tmp->SetHttpHeader("Accept-Encoding", "gzip"); | 309 //tmp->SetHttpHeader("Accept-Encoding", "gzip"); |
315 tmp->SetInstance(instance); | 310 tmp->SetInstance(instance); |
316 tmp->SetQuality((quality == 0 ? 50 : 90)); | 311 tmp->SetQuality((quality == 0 ? 50 : 90)); // QUALITY_00 is Jpeg50 while QUALITY_01 is Jpeg90 |
317 tmp->SetExpectedPixelFormat(slice.GetExpectedPixelFormat()); | 312 tmp->SetExpectedPixelFormat(slice.GetExpectedPixelFormat()); |
318 LOG(TRACE) | 313 LOG(TRACE) |
319 << "OrthancSeriesVolumeProgressiveLoader.ScheduleNextSliceDownload()" | 314 << "OrthancSeriesVolumeProgressiveLoader.ScheduleNextSliceDownload()" |
320 << " sliceIndex = " << sliceIndex << " slice quality = " << quality; | 315 << " sliceIndex = " << sliceIndex << " slice quality = " << quality; |
321 command.reset(tmp.release()); | 316 command.reset(tmp.release()); |
322 } | 317 } |
323 #endif | |
324 | 318 |
325 command->AcquirePayload(new Orthanc::SingleValueObject<unsigned int>(sliceIndex)); | 319 command->AcquirePayload(new Orthanc::SingleValueObject<unsigned int>(sliceIndex)); |
326 | 320 |
327 { | 321 { |
328 std::unique_ptr<OrthancStone::ILoadersContext::ILock> lock(loadersContext_.Lock()); | 322 std::unique_ptr<OrthancStone::ILoadersContext::ILock> lock(loadersContext_.Lock()); |
384 | 378 |
385 volume_->Initialize(seriesGeometry_.GetImageGeometry(), parameters.GetExpectedPixelFormat()); | 379 volume_->Initialize(seriesGeometry_.GetImageGeometry(), parameters.GetExpectedPixelFormat()); |
386 volume_->SetDicomParameters(parameters); | 380 volume_->SetDicomParameters(parameters); |
387 volume_->GetPixelData().Clear(); | 381 volume_->GetPixelData().Clear(); |
388 | 382 |
389 #if USE_SINGLE_QUALITY | 383 // If we are in progressive mode, the Fetching strategy will first request QUALITY_00, then QUALITY_01, then |
384 // QUALITY_02... Otherwise, it's only QUALITY_00 | |
385 unsigned int maxQuality = QUALITY_00; | |
386 if (progressiveQuality_) | |
387 maxQuality = QUALITY_02; | |
388 | |
390 strategy_.reset(new OrthancStone::BasicFetchingStrategy( | 389 strategy_.reset(new OrthancStone::BasicFetchingStrategy( |
391 sorter_->CreateSorter(static_cast<unsigned int>(slicesCount)), | 390 sorter_->CreateSorter(static_cast<unsigned int>(slicesCount)), |
392 SINGLE_QUALITY)); | 391 maxQuality)); |
393 #else | |
394 strategy_.reset(new OrthancStone::BasicFetchingStrategy( | |
395 sorter_->CreateSorter(static_cast<unsigned int>(slicesCount)), | |
396 BEST_QUALITY)); | |
397 #endif | |
398 | 392 |
399 assert(simultaneousDownloads_ != 0); | 393 assert(simultaneousDownloads_ != 0); |
400 for (unsigned int i = 0; i < simultaneousDownloads_; i++) | 394 for (unsigned int i = 0; i < simultaneousDownloads_; i++) |
401 { | 395 { |
402 ScheduleNextSliceDownload(); | 396 ScheduleNextSliceDownload(); |
411 | 405 |
412 void OrthancSeriesVolumeProgressiveLoader::SetSliceContent(unsigned int sliceIndex, | 406 void OrthancSeriesVolumeProgressiveLoader::SetSliceContent(unsigned int sliceIndex, |
413 const Orthanc::ImageAccessor& image, | 407 const Orthanc::ImageAccessor& image, |
414 unsigned int quality) | 408 unsigned int quality) |
415 { | 409 { |
416 assert(sliceIndex < slicesQuality_.size() && | 410 ORTHANC_ASSERT(sliceIndex < slicesQuality_.size() && |
417 slicesQuality_.size() == volume_->GetPixelData().GetDepth()); | 411 slicesQuality_.size() == volume_->GetPixelData().GetDepth()); |
418 | 412 |
413 if (!progressiveQuality_) | |
414 { | |
415 ORTHANC_ASSERT(quality == QUALITY_00); | |
416 ORTHANC_ASSERT(slicesQuality_[sliceIndex] == QUALITY_00); | |
417 } | |
418 | |
419 if (quality >= slicesQuality_[sliceIndex]) | 419 if (quality >= slicesQuality_[sliceIndex]) |
420 { | 420 { |
421 { | 421 { |
422 OrthancStone::ImageBuffer3D::SliceWriter writer(volume_->GetPixelData(), OrthancStone::VolumeProjection_Axial, sliceIndex); | 422 OrthancStone::ImageBuffer3D::SliceWriter writer(volume_->GetPixelData(), |
423 OrthancStone::VolumeProjection_Axial, | |
424 sliceIndex); | |
425 | |
423 Orthanc::ImageProcessing::Copy(writer.GetAccessor(), image); | 426 Orthanc::ImageProcessing::Copy(writer.GetAccessor(), image); |
424 } | 427 } |
425 | 428 |
426 volume_->IncrementRevision(); | 429 volume_->IncrementRevision(); |
427 seriesGeometry_.IncrementSliceRevision(sliceIndex); | 430 seriesGeometry_.IncrementSliceRevision(sliceIndex); |
432 LOG(TRACE) << "SetSliceContent sliceIndex = " << sliceIndex << " -- will " | 435 LOG(TRACE) << "SetSliceContent sliceIndex = " << sliceIndex << " -- will " |
433 << " now call ScheduleNextSliceDownload()"; | 436 << " now call ScheduleNextSliceDownload()"; |
434 ScheduleNextSliceDownload(); | 437 ScheduleNextSliceDownload(); |
435 } | 438 } |
436 | 439 |
437 void OrthancSeriesVolumeProgressiveLoader::LoadBestQualitySliceContent(const OrthancStone::GetOrthancImageCommand::SuccessMessage& message) | 440 void OrthancSeriesVolumeProgressiveLoader::LoadBestQualitySliceContent( |
438 { | 441 const OrthancStone::GetOrthancImageCommand::SuccessMessage& message) |
439 #if USE_SINGLE_QUALITY | 442 { |
440 SetSliceContent(GetSliceIndexPayload(message.GetOrigin()), message.GetImage(), SINGLE_QUALITY); | 443 unsigned int quality = QUALITY_00; |
441 #else | 444 if (progressiveQuality_) |
442 SetSliceContent(GetSliceIndexPayload(message.GetOrigin()), message.GetImage(), BEST_QUALITY); | 445 quality = QUALITY_02; |
443 #endif | 446 |
444 } | 447 SetSliceContent(GetSliceIndexPayload(message.GetOrigin()), |
445 | 448 message.GetImage(), |
446 #if USE_SINGLE_QUALITY | 449 quality); |
447 #else | 450 } |
448 void OrthancSeriesVolumeProgressiveLoader::LoadJpegSliceContent(const OrthancStone::GetOrthancWebViewerJpegCommand::SuccessMessage& message) | 451 |
449 { | 452 void OrthancSeriesVolumeProgressiveLoader::LoadJpegSliceContent( |
453 const OrthancStone::GetOrthancWebViewerJpegCommand::SuccessMessage& message) | |
454 { | |
455 ORTHANC_ASSERT(progressiveQuality_, "INTERNAL ERROR: OrthancSeriesVolumeProgressiveLoader::LoadJpegSliceContent" | |
456 << " called while progressiveQuality_ is false!"); | |
457 | |
450 LOG(TRACE) << "OrthancSeriesVolumeProgressiveLoader::LoadJpegSliceContent"; | 458 LOG(TRACE) << "OrthancSeriesVolumeProgressiveLoader::LoadJpegSliceContent"; |
451 unsigned int quality; | 459 unsigned int quality; |
452 | 460 |
453 switch (dynamic_cast<const OrthancStone::GetOrthancWebViewerJpegCommand&>(message.GetOrigin()).GetQuality()) | 461 switch (dynamic_cast<const OrthancStone::GetOrthancWebViewerJpegCommand&>(message.GetOrigin()).GetQuality()) |
454 { | 462 { |
455 case 50: | 463 case 50: |
456 quality = LOW_QUALITY; | 464 quality = QUALITY_00; |
457 break; | 465 break; |
458 | 466 |
459 case 90: | 467 case 90: |
460 quality = MIDDLE_QUALITY; | 468 quality = QUALITY_01; |
461 break; | 469 break; |
462 | 470 |
463 default: | 471 default: |
464 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | 472 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); |
465 } | 473 } |
466 | 474 |
467 SetSliceContent(GetSliceIndexPayload(message.GetOrigin()), message.GetImage(), quality); | 475 SetSliceContent(GetSliceIndexPayload(message.GetOrigin()), message.GetImage(), quality); |
468 } | 476 } |
469 #endif | |
470 | 477 |
471 OrthancSeriesVolumeProgressiveLoader::OrthancSeriesVolumeProgressiveLoader( | 478 OrthancSeriesVolumeProgressiveLoader::OrthancSeriesVolumeProgressiveLoader( |
472 OrthancStone::ILoadersContext& loadersContext, | 479 OrthancStone::ILoadersContext& loadersContext, |
473 const boost::shared_ptr<OrthancStone::DicomVolumeImage>& volume) | 480 boost::shared_ptr<OrthancStone::DicomVolumeImage> volume, |
481 bool progressiveQuality) | |
474 : loadersContext_(loadersContext) | 482 : loadersContext_(loadersContext) |
475 , active_(false) | 483 , active_(false) |
484 , progressiveQuality_(progressiveQuality) | |
476 , simultaneousDownloads_(4) | 485 , simultaneousDownloads_(4) |
477 , volume_(volume) | 486 , volume_(volume) |
478 , sorter_(new OrthancStone::BasicFetchingItemsSorter::Factory) | 487 , sorter_(new OrthancStone::BasicFetchingItemsSorter::Factory) |
479 , volumeImageReadyInHighQuality_(false) | 488 , volumeImageReadyInHighQuality_(false) |
480 { | 489 { |
481 } | 490 } |
482 | 491 |
483 boost::shared_ptr<OrthancSeriesVolumeProgressiveLoader> | 492 boost::shared_ptr<OrthancSeriesVolumeProgressiveLoader> |
484 OrthancSeriesVolumeProgressiveLoader::Create( | 493 OrthancSeriesVolumeProgressiveLoader::Create( |
485 OrthancStone::ILoadersContext& loadersContext, | 494 OrthancStone::ILoadersContext& loadersContext, |
486 const boost::shared_ptr<OrthancStone::DicomVolumeImage>& volume) | 495 boost::shared_ptr<OrthancStone::DicomVolumeImage> volume, |
496 bool progressiveQuality) | |
487 { | 497 { |
488 std::auto_ptr<OrthancStone::ILoadersContext::ILock> lock(loadersContext.Lock()); | 498 std::auto_ptr<OrthancStone::ILoadersContext::ILock> lock(loadersContext.Lock()); |
489 | 499 |
490 boost::shared_ptr<OrthancSeriesVolumeProgressiveLoader> obj( | 500 boost::shared_ptr<OrthancSeriesVolumeProgressiveLoader> obj( |
491 new OrthancSeriesVolumeProgressiveLoader(loadersContext,volume)); | 501 new OrthancSeriesVolumeProgressiveLoader( |
502 loadersContext, volume, progressiveQuality)); | |
492 | 503 |
493 obj->Register<OrthancStone::OrthancRestApiCommand::SuccessMessage>( | 504 obj->Register<OrthancStone::OrthancRestApiCommand::SuccessMessage>( |
494 lock->GetOracleObservable(), | 505 lock->GetOracleObservable(), |
495 &OrthancSeriesVolumeProgressiveLoader::LoadGeometry); | 506 &OrthancSeriesVolumeProgressiveLoader::LoadGeometry); |
496 | 507 |
497 obj->Register<OrthancStone::GetOrthancImageCommand::SuccessMessage>( | 508 obj->Register<OrthancStone::GetOrthancImageCommand::SuccessMessage>( |
498 lock->GetOracleObservable(), | 509 lock->GetOracleObservable(), |
499 &OrthancSeriesVolumeProgressiveLoader::LoadBestQualitySliceContent); | 510 &OrthancSeriesVolumeProgressiveLoader::LoadBestQualitySliceContent); |
500 | 511 |
501 #if USE_SINGLE_QUALITY | |
502 #else | |
503 obj->Register<OrthancStone::GetOrthancWebViewerJpegCommand::SuccessMessage>( | 512 obj->Register<OrthancStone::GetOrthancWebViewerJpegCommand::SuccessMessage>( |
504 lock->GetOracleObservable(), | 513 lock->GetOracleObservable(), |
505 &OrthancSeriesVolumeProgressiveLoader::LoadJpegSliceContent); | 514 &OrthancSeriesVolumeProgressiveLoader::LoadJpegSliceContent); |
506 #endif | 515 |
507 return obj; | 516 return obj; |
508 } | 517 } |
509 | 518 |
510 | 519 |
511 OrthancSeriesVolumeProgressiveLoader::~OrthancSeriesVolumeProgressiveLoader() | 520 OrthancSeriesVolumeProgressiveLoader::~OrthancSeriesVolumeProgressiveLoader() |
531 } | 540 } |
532 | 541 |
533 | 542 |
534 void OrthancSeriesVolumeProgressiveLoader::LoadSeries(const std::string& seriesId) | 543 void OrthancSeriesVolumeProgressiveLoader::LoadSeries(const std::string& seriesId) |
535 { | 544 { |
536 // LOG(TRACE) << "OrthancSeriesVolumeProgressiveLoader::LoadSeries seriesId=" << seriesId; | |
537 if (active_) | 545 if (active_) |
538 { | 546 { |
539 // LOG(TRACE) << "OrthancSeriesVolumeProgressiveLoader::LoadSeries NOT ACTIVE! --> ERROR"; | |
540 LOG(ERROR) << "OrthancSeriesVolumeProgressiveLoader::LoadSeries(const std::string& seriesId): (active_)"; | 547 LOG(ERROR) << "OrthancSeriesVolumeProgressiveLoader::LoadSeries(const std::string& seriesId): (active_)"; |
541 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | 548 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); |
542 } | 549 } |
543 else | 550 else |
544 { | 551 { |