comparison Samples/Sdl/Loader.cpp @ 667:e9339f2b5de7

refactoring of VolumeImage
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 15 May 2019 17:30:58 +0200
parents 970949ff868a
children 3805ffa2833d
comparison
equal deleted inserted replaced
665:419e5662d7a5 667:e9339f2b5de7
1357 { 1357 {
1358 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); 1358 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
1359 } 1359 }
1360 } 1360 }
1361 1361
1362 // TODO - Is this necessary?
1362 bool FrameContainsPlane(unsigned int frame, 1363 bool FrameContainsPlane(unsigned int frame,
1363 const OrthancStone::CoordinateSystem3D& plane) const 1364 const OrthancStone::CoordinateSystem3D& plane) const
1364 { 1365 {
1365 if (frame >= imageInformation_.GetNumberOfFrames()) 1366 if (frame >= imageInformation_.GetNumberOfFrames())
1366 { 1367 {
1447 { 1448 {
1448 return expectedPixelFormat_; 1449 return expectedPixelFormat_;
1449 } 1450 }
1450 }; 1451 };
1451 1452
1453
1454 class VolumeImage : public boost::noncopyable
1455 {
1456 private:
1457 std::auto_ptr<OrthancStone::SlicesSorter> slices_;
1458 std::auto_ptr<OrthancStone::ImageBuffer3D> image_;
1459
1460 const DicomInstanceParameters& GetSliceParameters(size_t index) const
1461 {
1462 return dynamic_cast<const DicomInstanceParameters&>(slices_->GetSlicePayload(index));
1463 }
1464
1465 void CheckSlice(size_t index,
1466 const OrthancStone::CoordinateSystem3D& reference,
1467 const DicomInstanceParameters& a) const
1468 {
1469 const OrthancStone::CoordinateSystem3D& slice = slices_->GetSliceGeometry(index);
1470 const DicomInstanceParameters& b = GetSliceParameters(index);
1471
1472 if (!OrthancStone::GeometryToolbox::IsParallel(reference.GetNormal(), slice.GetNormal()))
1473 {
1474 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadGeometry,
1475 "A slice in the volume image is not parallel to the others");
1476 }
1477
1478 if (a.GetExpectedPixelFormat() != b.GetExpectedPixelFormat())
1479 {
1480 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat,
1481 "The pixel format changes across the slices of the volume image");
1482 }
1483
1484 if (a.GetImageInformation().GetWidth() != b.GetImageInformation().GetWidth() ||
1485 a.GetImageInformation().GetHeight() != b.GetImageInformation().GetHeight())
1486 {
1487 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageSize,
1488 "The width/height of slices are not constant in the volume image");
1489 }
1490
1491 if (!OrthancStone::LinearAlgebra::IsNear(a.GetPixelSpacingX(), b.GetPixelSpacingX()) ||
1492 !OrthancStone::LinearAlgebra::IsNear(a.GetPixelSpacingY(), b.GetPixelSpacingY()))
1493 {
1494 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadGeometry,
1495 "The pixel spacing of the slices change across the volume image");
1496 }
1497 }
1498
1499
1500 void CheckVolume()
1501 {
1502 if (slices_->GetSlicesCount() != 0)
1503 {
1504 const OrthancStone::CoordinateSystem3D& reference = slices_->GetSliceGeometry(0);
1505 const DicomInstanceParameters& dicom = GetSliceParameters(0);
1506
1507 for (size_t i = 1; i < slices_->GetSlicesCount(); i++)
1508 {
1509 CheckSlice(i, reference, dicom);
1510 }
1511 }
1512 }
1513
1514
1515 public:
1516 VolumeImage()
1517 {
1518 }
1519
1520 // WARNING: The payload of "slices" must be of class "DicomInstanceParameters"
1521 void SetGeometry(OrthancStone::SlicesSorter* slices) // Takes ownership
1522 {
1523 image_.reset();
1524 slices_.reset(slices);
1525
1526 if (!slices_->Sort())
1527 {
1528 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange,
1529 "Cannot sort the 3D slices of a DICOM series");
1530 }
1531
1532 CheckVolume();
1533
1534 const double spacingZ = slices_->ComputeSpacingBetweenSlices();
1535 LOG(INFO) << "Computed spacing between slices: " << spacingZ << "mm";
1536
1537 const DicomInstanceParameters& parameters = GetSliceParameters(0);
1538
1539 image_.reset(new OrthancStone::ImageBuffer3D(parameters.GetExpectedPixelFormat(),
1540 parameters.GetImageInformation().GetWidth(),
1541 parameters.GetImageInformation().GetHeight(),
1542 slices_->GetSlicesCount(), false /* don't compute range */));
1543
1544 image_->SetAxialGeometry(slices_->GetSliceGeometry(0));
1545 image_->SetVoxelDimensions(parameters.GetPixelSpacingX(), parameters.GetPixelSpacingY(), spacingZ);
1546 image_->Clear();
1547 }
1548
1549 bool IsGeometryReady() const
1550 {
1551 return (image_.get() != NULL &&
1552 slices_.get() != NULL);
1553 }
1554
1555 const OrthancStone::SlicesSorter& GetSlices() const
1556 {
1557 if (!IsGeometryReady())
1558 {
1559 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
1560 }
1561 else
1562 {
1563 return *slices_;
1564 }
1565 }
1566
1567 const OrthancStone::ImageBuffer3D& GetImage() const
1568 {
1569 if (!IsGeometryReady())
1570 {
1571 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
1572 }
1573 else
1574 {
1575 return *image_;
1576 }
1577 }
1578 };
1579
1580
1452 1581
1453 class AxialVolumeOrthancLoader : public OrthancStone::IObserver 1582 class AxialVolumeOrthancLoader : public OrthancStone::IObserver
1454 { 1583 {
1455 private: 1584 private:
1456 class MessageHandler : public Orthanc::IDynamicObject 1585 class MessageHandler : public Orthanc::IDynamicObject
1486 throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); 1615 throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
1487 } 1616 }
1488 1617
1489 Json::Value::Members instances = value.getMemberNames(); 1618 Json::Value::Members instances = value.getMemberNames();
1490 1619
1620 std::auto_ptr<OrthancStone::SlicesSorter> slices(new OrthancStone::SlicesSorter);
1621
1491 for (size_t i = 0; i < instances.size(); i++) 1622 for (size_t i = 0; i < instances.size(); i++)
1492 { 1623 {
1493 Orthanc::DicomMap dicom; 1624 Orthanc::DicomMap dicom;
1494 dicom.FromDicomAsJson(value[instances[i]]); 1625 dicom.FromDicomAsJson(value[instances[i]]);
1495 1626
1496 std::auto_ptr<DicomInstanceParameters> instance(new DicomInstanceParameters(dicom)); 1627 std::auto_ptr<DicomInstanceParameters> instance(new DicomInstanceParameters(dicom));
1497 1628
1498 OrthancStone::CoordinateSystem3D geometry = instance->GetGeometry(); 1629 OrthancStone::CoordinateSystem3D geometry = instance->GetGeometry();
1499 that_.slices_.AddSlice(geometry, instance.release()); 1630 slices->AddSlice(geometry, instance.release());
1500 } 1631 }
1501 1632
1502 if (!that_.slices_.Sort()) 1633 that_.image_.SetGeometry(slices.release());
1503 {
1504 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange,
1505 "Cannot sort the 3D slices of a DICOM series");
1506 }
1507
1508 printf("series sorted %d => %d\n", instances.size(), that_.slices_.GetSlicesCount());
1509 } 1634 }
1510 }; 1635 };
1511 1636
1512 1637
1513 class LoadInstanceGeometryHandler : public MessageHandler 1638 class LoadInstanceGeometryHandler : public MessageHandler
1537 DicomInstanceParameters instance(dicom); 1662 DicomInstanceParameters instance(dicom);
1538 } 1663 }
1539 }; 1664 };
1540 1665
1541 1666
1542 bool active_; 1667 bool active_;
1543 std::auto_ptr<OrthancStone::ImageBuffer3D> image_; 1668 VolumeImage image_;
1544 OrthancStone::SlicesSorter slices_;
1545 1669
1546 public: 1670 public:
1547 AxialVolumeOrthancLoader(OrthancStone::IObservable& oracle) : 1671 AxialVolumeOrthancLoader(OrthancStone::IObservable& oracle) :
1548 IObserver(oracle.GetBroker()), 1672 IObserver(oracle.GetBroker()),
1549 active_(false) 1673 active_(false)