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 {