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