comparison Samples/Sdl/Loader.cpp @ 709:7457b4ee1f29

VolumeSeriesOrthancLoader uses a prefetching strategy
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 20 May 2019 12:03:16 +0200
parents 10910827f235
children 3046a603eebf
comparison
equal deleted inserted replaced
708:51976977d2d3 709:7457b4ee1f29
26 #include "../../Framework/StoneInitialization.h" 26 #include "../../Framework/StoneInitialization.h"
27 #include "../../Framework/Toolbox/GeometryToolbox.h" 27 #include "../../Framework/Toolbox/GeometryToolbox.h"
28 #include "../../Framework/Toolbox/SlicesSorter.h" 28 #include "../../Framework/Toolbox/SlicesSorter.h"
29 #include "../../Framework/Volumes/ImageBuffer3D.h" 29 #include "../../Framework/Volumes/ImageBuffer3D.h"
30 #include "../../Framework/Scene2D/Scene2D.h" 30 #include "../../Framework/Scene2D/Scene2D.h"
31 #include "../../Framework/Loaders/BasicFetchingStrategy.h"
32 #include "../../Framework/Loaders/BasicFetchingItemsSorter.h"
31 33
32 // From Orthanc framework 34 // From Orthanc framework
33 #include <Core/Compression/GzipCompressor.h> 35 #include <Core/Compression/GzipCompressor.h>
34 #include <Core/Compression/ZlibCompressor.h> 36 #include <Core/Compression/ZlibCompressor.h>
35 #include <Core/DicomFormat/DicomArray.h> 37 #include <Core/DicomFormat/DicomArray.h>
395 } 397 }
396 398
397 void SetUri(const std::string& uri) 399 void SetUri(const std::string& uri)
398 { 400 {
399 uri_ = uri; 401 uri_ = uri;
402 }
403
404 void SetInstanceUri(const std::string& instance,
405 Orthanc::PixelFormat pixelFormat)
406 {
407 uri_ = "/instances/" + instance;
408
409 switch (pixelFormat)
410 {
411 case Orthanc::PixelFormat_RGB24:
412 uri_ += "/preview";
413 break;
414
415 case Orthanc::PixelFormat_Grayscale16:
416 uri_ += "/image-uint16";
417 break;
418
419 case Orthanc::PixelFormat_SignedGrayscale16:
420 uri_ += "/image-int16";
421 break;
422
423 default:
424 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
425 }
400 } 426 }
401 427
402 void SetHttpHeader(const std::string& key, 428 void SetHttpHeader(const std::string& key,
403 const std::string& value) 429 const std::string& value)
404 { 430 {
1150 private: 1176 private:
1151 std::auto_ptr<OrthancStone::ImageBuffer3D> image_; 1177 std::auto_ptr<OrthancStone::ImageBuffer3D> image_;
1152 std::vector<DicomInstanceParameters*> slices_; 1178 std::vector<DicomInstanceParameters*> slices_;
1153 uint64_t revision_; 1179 uint64_t revision_;
1154 std::vector<uint64_t> slicesRevision_; 1180 std::vector<uint64_t> slicesRevision_;
1181 std::vector<unsigned int> slicesQuality_;
1155 1182
1156 void CheckSlice(size_t index, 1183 void CheckSlice(size_t index,
1157 const DicomInstanceParameters& reference) const 1184 const DicomInstanceParameters& reference) const
1158 { 1185 {
1159 const DicomInstanceParameters& slice = *slices_[index]; 1186 const DicomInstanceParameters& slice = *slices_[index];
1219 for (size_t i = 0; i < slices_.size(); i++) 1246 for (size_t i = 0; i < slices_.size(); i++)
1220 { 1247 {
1221 assert(slices_[i] != NULL); 1248 assert(slices_[i] != NULL);
1222 delete slices_[i]; 1249 delete slices_[i];
1223 } 1250 }
1251
1252 slices_.clear();
1253 slicesRevision_.clear();
1254 slicesQuality_.clear();
1224 } 1255 }
1225 1256
1226 1257
1227 void CheckSliceIndex(size_t index) const 1258 void CheckSliceIndex(size_t index) const
1228 { 1259 {
1268 false /* don't compute range */)); 1299 false /* don't compute range */));
1269 } 1300 }
1270 else 1301 else
1271 { 1302 {
1272 slices_.reserve(slices.GetSlicesCount()); 1303 slices_.reserve(slices.GetSlicesCount());
1273 slicesRevision_.resize(slices.GetSlicesCount()); 1304 slicesRevision_.resize(slices.GetSlicesCount(), 0);
1305 slicesQuality_.resize(slices.GetSlicesCount(), 0);
1274 1306
1275 for (size_t i = 0; i < slices.GetSlicesCount(); i++) 1307 for (size_t i = 0; i < slices.GetSlicesCount(); i++)
1276 { 1308 {
1277 const DicomInstanceParameters& slice = 1309 const DicomInstanceParameters& slice =
1278 dynamic_cast<const DicomInstanceParameters&>(slices.GetSlicePayload(i)); 1310 dynamic_cast<const DicomInstanceParameters&>(slices.GetSlicePayload(i));
1279 slices_.push_back(new DicomInstanceParameters(slice)); 1311 slices_.push_back(new DicomInstanceParameters(slice));
1280 slicesRevision_[i] = 0;
1281 } 1312 }
1282 1313
1283 CheckVolume(); 1314 CheckVolume();
1284 1315
1285 const double spacingZ = slices.ComputeSpacingBetweenSlices(); 1316 const double spacingZ = slices.ComputeSpacingBetweenSlices();
1347 CheckSliceIndex(index); 1378 CheckSliceIndex(index);
1348 return slicesRevision_[index]; 1379 return slicesRevision_[index];
1349 } 1380 }
1350 1381
1351 void SetSliceContent(size_t index, 1382 void SetSliceContent(size_t index,
1352 const Orthanc::ImageAccessor& image) 1383 const Orthanc::ImageAccessor& image,
1384 unsigned int quality)
1353 { 1385 {
1354 CheckSliceIndex(index); 1386 CheckSliceIndex(index);
1355 1387
1356 { 1388 // If a better image quality is already available, don't update the content
1357 OrthancStone::ImageBuffer3D::SliceWriter writer 1389 if (quality >= slicesQuality_[index])
1358 (*image_, OrthancStone::VolumeProjection_Axial, index); 1390 {
1359 Orthanc::ImageProcessing::Copy(writer.GetAccessor(), image); 1391 {
1360 } 1392 OrthancStone::ImageBuffer3D::SliceWriter writer
1361 1393 (*image_, OrthancStone::VolumeProjection_Axial, index);
1362 revision_ ++; 1394 Orthanc::ImageProcessing::Copy(writer.GetAccessor(), image);
1363 slicesRevision_[index] += 1; 1395 }
1396
1397 revision_ ++;
1398 slicesRevision_[index] += 1;
1399 }
1364 } 1400 }
1365 }; 1401 };
1366 1402
1367 1403
1368 1404
1375 virtual void Handle(const Json::Value& body) const 1411 virtual void Handle(const Json::Value& body) const
1376 { 1412 {
1377 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); 1413 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
1378 } 1414 }
1379 1415
1380 virtual void Handle(const Orthanc::ImageAccessor& image) const 1416 virtual void Handle(const Orthanc::ImageAccessor& image,
1417 unsigned int quality) const
1381 { 1418 {
1382 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); 1419 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
1383 } 1420 }
1384 }; 1421 };
1385 1422
1396 dynamic_cast<const MessageHandler&>(message.GetOrigin().GetPayload()).Handle(body); 1433 dynamic_cast<const MessageHandler&>(message.GetOrigin().GetPayload()).Handle(body);
1397 } 1434 }
1398 1435
1399 void Handle(const Refactoring::GetOrthancImageCommand::SuccessMessage& message) 1436 void Handle(const Refactoring::GetOrthancImageCommand::SuccessMessage& message)
1400 { 1437 {
1401 dynamic_cast<const MessageHandler&>(message.GetOrigin().GetPayload()).Handle(message.GetImage()); 1438 dynamic_cast<const MessageHandler&>(message.GetOrigin().GetPayload()).Handle(message.GetImage(), 2 /* best quality */);
1402 } 1439 }
1403 1440
1404 void Handle(const Refactoring::GetOrthancWebViewerJpegCommand::SuccessMessage& message) 1441 void Handle(const Refactoring::GetOrthancWebViewerJpegCommand::SuccessMessage& message)
1405 { 1442 {
1406 dynamic_cast<const MessageHandler&>(message.GetOrigin().GetPayload()).Handle(message.GetImage()); 1443 unsigned int quality;
1444
1445 switch (message.GetOrigin().GetQuality())
1446 {
1447 case 50:
1448 quality = 0;
1449 break;
1450
1451 case 95:
1452 quality = 1;
1453 break;
1454
1455 default:
1456 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
1457 }
1458
1459 dynamic_cast<const MessageHandler&>(message.GetOrigin().GetPayload()).Handle(message.GetImage(), quality);
1407 } 1460 }
1408 1461
1409 1462
1410 class LoadSliceImage : public MessageHandler 1463 class LoadSliceImage : public MessageHandler
1411 {
1412 private:
1413 DicomVolumeImage& target_;
1414 size_t slice_;
1415
1416 public:
1417 LoadSliceImage(DicomVolumeImage& target,
1418 size_t slice) :
1419 target_(target),
1420 slice_(slice)
1421 {
1422 }
1423
1424 virtual void Handle(const Orthanc::ImageAccessor& image) const
1425 {
1426 target_.SetSliceContent(slice_, image);
1427 }
1428 };
1429
1430
1431 class LoadSeriesGeometryHandler : public MessageHandler
1432 { 1464 {
1433 private: 1465 private:
1434 VolumeSeriesOrthancLoader& that_; 1466 VolumeSeriesOrthancLoader& that_;
1467 size_t slice_;
1468
1469 public:
1470 LoadSliceImage(VolumeSeriesOrthancLoader& that,
1471 size_t slice) :
1472 that_(that),
1473 slice_(slice)
1474 {
1475 }
1476
1477 virtual void Handle(const Orthanc::ImageAccessor& image,
1478 unsigned int quality) const
1479 {
1480 assert(quality <= 2);
1481 that_.volume_.SetSliceContent(slice_, image, quality);
1482 that_.ScheduleNextSliceDownload();
1483 }
1484 };
1485
1486
1487 class LoadSeriesGeometryHandler : public MessageHandler
1488 {
1489 private:
1490 VolumeSeriesOrthancLoader& that_;
1435 1491
1436 public: 1492 public:
1437 LoadSeriesGeometryHandler(VolumeSeriesOrthancLoader& that) : 1493 LoadSeriesGeometryHandler(VolumeSeriesOrthancLoader& that) :
1438 that_(that) 1494 that_(that)
1439 { 1495 {
1440 } 1496 }
1441 1497
1442 virtual void Handle(const Json::Value& body) const 1498 virtual void Handle(const Json::Value& body) const
1443 { 1499 {
1444 Json::Value::Members instances = body.getMemberNames(); 1500 {
1445 1501 Json::Value::Members instances = body.getMemberNames();
1446 OrthancStone::SlicesSorter slices; 1502
1503 OrthancStone::SlicesSorter slices;
1447 1504
1448 for (size_t i = 0; i < instances.size(); i++) 1505 for (size_t i = 0; i < instances.size(); i++)
1449 {
1450 Orthanc::DicomMap dicom;
1451 dicom.FromDicomAsJson(body[instances[i]]);
1452
1453 std::auto_ptr<DicomInstanceParameters> instance(new DicomInstanceParameters(dicom));
1454 instance->SetOrthancInstanceIdentifier(instances[i]);
1455
1456 OrthancStone::CoordinateSystem3D geometry = instance->GetGeometry();
1457 slices.AddSlice(geometry, instance.release());
1458 }
1459
1460 that_.volume_.SetGeometry(slices);
1461
1462 {
1463 OrthancStone::LinearAlgebra::Print(that_.volume_.GetImage().GetGeometry().GetCoordinates(0, 0, 0));
1464 OrthancStone::LinearAlgebra::Print(that_.volume_.GetImage().GetGeometry().GetCoordinates(1, 1, 1));
1465 return;
1466 }
1467
1468 for (size_t i = 0; i < that_.volume_.GetSlicesCount(); i++)
1469 {
1470 const DicomInstanceParameters& slice = that_.volume_.GetSliceParameters(i);
1471
1472 const std::string& instance = slice.GetOrthancInstanceIdentifier();
1473 if (instance.empty())
1474 { 1506 {
1475 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); 1507 Orthanc::DicomMap dicom;
1508 dicom.FromDicomAsJson(body[instances[i]]);
1509
1510 std::auto_ptr<DicomInstanceParameters> instance(new DicomInstanceParameters(dicom));
1511 instance->SetOrthancInstanceIdentifier(instances[i]);
1512
1513 OrthancStone::CoordinateSystem3D geometry = instance->GetGeometry();
1514 slices.AddSlice(geometry, instance.release());
1476 } 1515 }
1477 1516
1478 #if 0 1517 that_.volume_.SetGeometry(slices);
1479 std::auto_ptr<Refactoring::GetOrthancWebViewerJpegCommand> command( 1518 }
1480 new Refactoring::GetOrthancWebViewerJpegCommand); 1519
1481 command->SetInstance(instance); 1520 if (that_.volume_.GetSlicesCount() != 0)
1482 command->SetQuality(95); 1521 {
1483 #else 1522 that_.strategy_.reset(new OrthancStone::BasicFetchingStrategy(
1484 std::string uri = "/instances/" + instance; 1523 new OrthancStone::BasicFetchingItemsSorter(that_.volume_.GetSlicesCount()), 2));
1485 1524
1486 switch (slice.GetExpectedPixelFormat()) 1525 for (unsigned int i = 0; i < 4; i++) // Schedule up to 4 simultaneous downloads (TODO - parameter)
1487 { 1526 {
1488 case Orthanc::PixelFormat_RGB24: 1527 that_.ScheduleNextSliceDownload();
1489 uri += "/preview";
1490 break;
1491
1492 case Orthanc::PixelFormat_Grayscale16:
1493 uri += "/image-uint16";
1494 break;
1495
1496 case Orthanc::PixelFormat_SignedGrayscale16:
1497 uri += "/image-int16";
1498 break;
1499
1500 default:
1501 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
1502 } 1528 }
1503
1504 std::auto_ptr<Refactoring::GetOrthancImageCommand> command(
1505 new Refactoring::GetOrthancImageCommand);
1506 command->SetHttpHeader("Accept-Encoding", "gzip");
1507 command->SetHttpHeader("Accept", std::string(Orthanc::EnumerationToString(Orthanc::MimeType_Pam)));
1508 command->SetUri(uri);
1509 #endif
1510
1511 command->SetExpectedPixelFormat(slice.GetExpectedPixelFormat());
1512 command->SetPayload(new LoadSliceImage(that_.volume_, i));
1513
1514 that_.oracle_.Schedule(that_, command.release());
1515 } 1529 }
1516 } 1530 }
1517 }; 1531 };
1518 1532
1519 1533
1536 DicomInstanceParameters instance(dicom); 1550 DicomInstanceParameters instance(dicom);
1537 } 1551 }
1538 }; 1552 };
1539 1553
1540 1554
1555 void ScheduleNextSliceDownload()
1556 {
1557 assert(strategy_.get() != NULL);
1558
1559 unsigned int sliceIndex, quality;
1560
1561 if (strategy_->GetNext(sliceIndex, quality))
1562 {
1563 assert(quality <= 2);
1564
1565 const DicomInstanceParameters& slice = volume_.GetSliceParameters(sliceIndex);
1566
1567 const std::string& instance = slice.GetOrthancInstanceIdentifier();
1568 if (instance.empty())
1569 {
1570 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
1571 }
1572
1573 std::auto_ptr<Refactoring::IOracleCommand> command;
1574
1575 if (quality == 2) // Best quality
1576 {
1577 std::auto_ptr<Refactoring::GetOrthancImageCommand> tmp(
1578 new Refactoring::GetOrthancImageCommand);
1579 tmp->SetHttpHeader("Accept-Encoding", "gzip");
1580 tmp->SetHttpHeader("Accept", std::string(Orthanc::EnumerationToString(Orthanc::MimeType_Pam)));
1581 tmp->SetInstanceUri(instance, slice.GetExpectedPixelFormat());
1582 tmp->SetExpectedPixelFormat(slice.GetExpectedPixelFormat());
1583 tmp->SetPayload(new LoadSliceImage(*this, sliceIndex));
1584 command.reset(tmp.release());
1585 }
1586 else
1587 {
1588 std::auto_ptr<Refactoring::GetOrthancWebViewerJpegCommand> tmp(
1589 new Refactoring::GetOrthancWebViewerJpegCommand);
1590 tmp->SetHttpHeader("Accept-Encoding", "gzip");
1591 tmp->SetInstance(instance);
1592 tmp->SetQuality((quality == 0 ? 50 : 95));
1593 tmp->SetExpectedPixelFormat(slice.GetExpectedPixelFormat());
1594 tmp->SetPayload(new LoadSliceImage(*this, sliceIndex));
1595 command.reset(tmp.release());
1596 }
1597
1598 oracle_.Schedule(*this, command.release());
1599 }
1600 }
1601
1602
1541 IOracle& oracle_; 1603 IOracle& oracle_;
1542 bool active_; 1604 bool active_;
1543 DicomVolumeImage volume_; 1605 DicomVolumeImage volume_;
1606
1607 std::auto_ptr<OrthancStone::IFetchingStrategy> strategy_;
1544 1608
1545 public: 1609 public:
1546 VolumeSeriesOrthancLoader(IOracle& oracle, 1610 VolumeSeriesOrthancLoader(IOracle& oracle,
1547 OrthancStone::IObservable& oracleObservable) : 1611 OrthancStone::IObservable& oracleObservable) :
1548 IObserver(oracleObservable.GetBroker()), 1612 IObserver(oracleObservable.GetBroker()),