Mercurial > hg > orthanc-stone
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()), |