comparison Samples/Sdl/Loader.cpp @ 678:6f10f9a6676a

turning DicomVolumeImage into a bean class
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 16 May 2019 11:20:43 +0200
parents 3805ffa2833d
children 0eb26f514ac5
comparison
equal deleted inserted replaced
669:3805ffa2833d 678:6f10f9a6676a
1484 { 1484 {
1485 private: 1485 private:
1486 std::auto_ptr<OrthancStone::ImageBuffer3D> image_; 1486 std::auto_ptr<OrthancStone::ImageBuffer3D> image_;
1487 std::vector<DicomInstanceParameters*> slices_; 1487 std::vector<DicomInstanceParameters*> slices_;
1488 1488
1489 static const DicomInstanceParameters& 1489 void CheckSlice(size_t index,
1490 GetSliceParameters(const OrthancStone::SlicesSorter& slices, 1490 const DicomInstanceParameters& reference) const
1491 size_t index) 1491 {
1492 { 1492 const DicomInstanceParameters& slice = *slices_[index];
1493 return dynamic_cast<const DicomInstanceParameters&>(slices.GetSlicePayload(index));
1494 }
1495
1496 static void CheckSlice(const OrthancStone::SlicesSorter& slices,
1497 size_t index,
1498 const OrthancStone::CoordinateSystem3D& reference,
1499 const DicomInstanceParameters& a)
1500 {
1501 const OrthancStone::CoordinateSystem3D& slice = slices.GetSliceGeometry(index);
1502 const DicomInstanceParameters& b = GetSliceParameters(slices, index);
1503 1493
1504 if (!OrthancStone::GeometryToolbox::IsParallel(reference.GetNormal(), slice.GetNormal())) 1494 if (!OrthancStone::GeometryToolbox::IsParallel(
1495 reference.GetGeometry().GetNormal(),
1496 slice.GetGeometry().GetNormal()))
1505 { 1497 {
1506 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadGeometry, 1498 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadGeometry,
1507 "A slice in the volume image is not parallel to the others"); 1499 "A slice in the volume image is not parallel to the others");
1508 } 1500 }
1509 1501
1510 if (a.GetExpectedPixelFormat() != b.GetExpectedPixelFormat()) 1502 if (reference.GetExpectedPixelFormat() != slice.GetExpectedPixelFormat())
1511 { 1503 {
1512 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat, 1504 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat,
1513 "The pixel format changes across the slices of the volume image"); 1505 "The pixel format changes across the slices of the volume image");
1514 } 1506 }
1515 1507
1516 if (a.GetImageInformation().GetWidth() != b.GetImageInformation().GetWidth() || 1508 if (reference.GetImageInformation().GetWidth() != slice.GetImageInformation().GetWidth() ||
1517 a.GetImageInformation().GetHeight() != b.GetImageInformation().GetHeight()) 1509 reference.GetImageInformation().GetHeight() != slice.GetImageInformation().GetHeight())
1518 { 1510 {
1519 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageSize, 1511 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageSize,
1520 "The width/height of slices are not constant in the volume image"); 1512 "The width/height of slices are not constant in the volume image");
1521 } 1513 }
1522 1514
1523 if (!OrthancStone::LinearAlgebra::IsNear(a.GetPixelSpacingX(), b.GetPixelSpacingX()) || 1515 if (!OrthancStone::LinearAlgebra::IsNear(reference.GetPixelSpacingX(), slice.GetPixelSpacingX()) ||
1524 !OrthancStone::LinearAlgebra::IsNear(a.GetPixelSpacingY(), b.GetPixelSpacingY())) 1516 !OrthancStone::LinearAlgebra::IsNear(reference.GetPixelSpacingY(), slice.GetPixelSpacingY()))
1525 { 1517 {
1526 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadGeometry, 1518 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadGeometry,
1527 "The pixel spacing of the slices change across the volume image"); 1519 "The pixel spacing of the slices change across the volume image");
1528 } 1520 }
1529 } 1521 }
1530 1522
1531 1523
1532 static void CheckVolume(const OrthancStone::SlicesSorter& slices) 1524 void CheckVolume() const
1533 { 1525 {
1534 for (size_t i = 0; i < slices.GetSlicesCount(); i++) 1526 for (size_t i = 0; i < slices_.size(); i++)
1535 { 1527 {
1536 if (GetSliceParameters(slices, i).GetImageInformation().GetNumberOfFrames() != 1) 1528 assert(slices_[i] != NULL);
1529 if (slices_[i]->GetImageInformation().GetNumberOfFrames() != 1)
1537 { 1530 {
1538 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadGeometry, 1531 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadGeometry,
1539 "This class does not support multi-frame images"); 1532 "This class does not support multi-frame images");
1540 } 1533 }
1541 } 1534 }
1542 1535
1543 if (slices.GetSlicesCount() != 0) 1536 if (slices_.size() != 0)
1544 { 1537 {
1545 const OrthancStone::CoordinateSystem3D& reference = slices.GetSliceGeometry(0); 1538 const DicomInstanceParameters& reference = *slices_[0];
1546 const DicomInstanceParameters& dicom = GetSliceParameters(slices, 0); 1539
1547 1540 for (size_t i = 1; i < slices_.size(); i++)
1548 for (size_t i = 1; i < slices.GetSlicesCount(); i++) 1541 {
1549 { 1542 CheckSlice(i, reference);
1550 CheckSlice(slices, i, reference, dicom);
1551 } 1543 }
1552 } 1544 }
1553 } 1545 }
1554 1546
1555 1547
1584 { 1576 {
1585 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange, 1577 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange,
1586 "Cannot sort the 3D slices of a DICOM series"); 1578 "Cannot sort the 3D slices of a DICOM series");
1587 } 1579 }
1588 1580
1589 slices_.reserve(slices.GetSlicesCount()); 1581 if (slices.GetSlicesCount() == 0)
1590 1582 {
1591 for (size_t i = 0; i < slices.GetSlicesCount(); i++) 1583 // Empty volume
1592 { 1584 image_.reset(new OrthancStone::ImageBuffer3D(Orthanc::PixelFormat_Grayscale8, 0, 0, 0,
1593 slices_.push_back(new DicomInstanceParameters(GetSliceParameters(slices, i))); 1585 false /* don't compute range */));
1594 } 1586 }
1595 1587 else
1596 CheckVolume(slices); 1588 {
1597 1589 slices_.reserve(slices.GetSlicesCount());
1598 const double spacingZ = slices.ComputeSpacingBetweenSlices(); 1590
1599 LOG(INFO) << "Computed spacing between slices: " << spacingZ << "mm"; 1591 for (size_t i = 0; i < slices.GetSlicesCount(); i++)
1592 {
1593 const DicomInstanceParameters& slice =
1594 dynamic_cast<const DicomInstanceParameters&>(slices.GetSlicePayload(i));
1595 slices_.push_back(new DicomInstanceParameters(slice));
1596 }
1597
1598 CheckVolume();
1599
1600 const double spacingZ = slices.ComputeSpacingBetweenSlices();
1601 LOG(INFO) << "Computed spacing between slices: " << spacingZ << "mm";
1600 1602
1601 const DicomInstanceParameters& parameters = GetSliceParameters(slices, 0); 1603 const DicomInstanceParameters& parameters = *slices_[0];
1602 1604
1603 image_.reset(new OrthancStone::ImageBuffer3D(parameters.GetExpectedPixelFormat(), 1605 image_.reset(new OrthancStone::ImageBuffer3D(parameters.GetExpectedPixelFormat(),
1604 parameters.GetImageInformation().GetWidth(), 1606 parameters.GetImageInformation().GetWidth(),
1605 parameters.GetImageInformation().GetHeight(), 1607 parameters.GetImageInformation().GetHeight(),
1606 slices.GetSlicesCount(), false /* don't compute range */)); 1608 slices.GetSlicesCount(), false /* don't compute range */));
1607 1609
1608 image_->SetAxialGeometry(slices.GetSliceGeometry(0)); 1610 image_->SetAxialGeometry(slices.GetSliceGeometry(0));
1609 image_->SetVoxelDimensions(parameters.GetPixelSpacingX(), parameters.GetPixelSpacingY(), spacingZ); 1611 image_->SetVoxelDimensions(parameters.GetPixelSpacingX(), parameters.GetPixelSpacingY(), spacingZ);
1612 }
1613
1610 image_->Clear(); 1614 image_->Clear();
1611 } 1615 }
1612 1616
1613 bool IsGeometryReady() const 1617 bool IsGeometryReady() const
1614 { 1618 {
1623 } 1627 }
1624 else 1628 else
1625 { 1629 {
1626 return *image_; 1630 return *image_;
1627 } 1631 }
1628 } 1632 }
1633
1634 size_t GetSlicesCount() const
1635 {
1636 if (!IsGeometryReady())
1637 {
1638 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
1639 }
1640 else
1641 {
1642 assert(slices_.size() == image_->GetDepth());
1643 return slices_.size();
1644 }
1645 }
1646
1647 const DicomInstanceParameters& GetSlice(size_t index) const
1648 {
1649 if (!IsGeometryReady())
1650 {
1651 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
1652 }
1653 else if (index >= slices_.size())
1654 {
1655 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
1656 }
1657 else
1658 {
1659 assert(slices_.size() == image_->GetDepth());
1660 return *slices_[index];
1661 }
1662 }
1629 }; 1663 };
1630 1664
1631 1665
1632 1666
1633 class AxialVolumeOrthancLoader : public OrthancStone::IObserver 1667 class AxialVolumeOrthancLoader : public OrthancStone::IObserver