Mercurial > hg > orthanc-stone
comparison Samples/Sdl/Loader.cpp @ 764:f36a6f7e7bdf
cont
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 23 May 2019 12:54:10 +0200 |
parents | 53167294d870 |
children | f6438fdc447e |
comparison
equal
deleted
inserted
replaced
763:53167294d870 | 764:f36a6f7e7bdf |
---|---|
738 | 738 |
739 | 739 |
740 class OrthancMultiframeVolumeLoader : public IObserver | 740 class OrthancMultiframeVolumeLoader : public IObserver |
741 { | 741 { |
742 private: | 742 private: |
743 class Handler : public Orthanc::IDynamicObject | 743 class State : public Orthanc::IDynamicObject |
744 { | 744 { |
745 private: | 745 private: |
746 OrthancMultiframeVolumeLoader& that_; | 746 OrthancMultiframeVolumeLoader& that_; |
747 std::string instanceId_; | |
748 | 747 |
749 protected: | 748 protected: |
750 void Schedule(OrthancRestApiCommand* command) const | 749 void Schedule(OrthancRestApiCommand* command) const |
751 { | 750 { |
752 that_.oracle_.Schedule(that_, command); | 751 that_.oracle_.Schedule(that_, command); |
753 } | 752 } |
754 | 753 |
755 const std::string& GetInstanceId() const | |
756 { | |
757 return instanceId_; | |
758 } | |
759 | |
760 OrthancMultiframeVolumeLoader& GetTarget() const | 754 OrthancMultiframeVolumeLoader& GetTarget() const |
761 { | 755 { |
762 return that_; | 756 return that_; |
763 } | 757 } |
764 | 758 |
765 public: | 759 public: |
766 Handler(OrthancMultiframeVolumeLoader& that, | 760 State(OrthancMultiframeVolumeLoader& that) : |
767 const std::string& instanceId) : | 761 that_(that) |
768 that_(that), | |
769 instanceId_(instanceId) | |
770 { | |
771 } | |
772 | |
773 Handler(const Handler& previous) : | |
774 that_(previous.that_), | |
775 instanceId_(previous.instanceId_) | |
776 { | 762 { |
777 } | 763 } |
778 | 764 |
779 virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) const = 0; | 765 virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) const = 0; |
780 }; | 766 }; |
781 | 767 |
782 void Handle(const OrthancRestApiCommand::SuccessMessage& message) | 768 void Handle(const OrthancRestApiCommand::SuccessMessage& message) |
783 { | 769 { |
784 dynamic_cast<const Handler&>(message.GetOrigin().GetPayload()).Handle(message); | 770 dynamic_cast<const State&>(message.GetOrigin().GetPayload()).Handle(message); |
785 } | 771 } |
786 | 772 |
787 | 773 |
788 class LoadRTDoseGeometry : public Handler | 774 class LoadRTDoseGeometry : public State |
789 { | 775 { |
790 private: | 776 private: |
791 std::auto_ptr<Orthanc::DicomMap> dicom_; | 777 std::auto_ptr<Orthanc::DicomMap> dicom_; |
792 | 778 |
793 public: | 779 public: |
794 LoadRTDoseGeometry(const Handler& previous, | 780 LoadRTDoseGeometry(OrthancMultiframeVolumeLoader& that, |
795 Orthanc::DicomMap* dicom) : | 781 Orthanc::DicomMap* dicom) : |
796 Handler(previous), | 782 State(that), |
797 dicom_(dicom) | 783 dicom_(dicom) |
798 { | 784 { |
799 if (dicom == NULL) | 785 if (dicom == NULL) |
800 { | 786 { |
801 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); | 787 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); |
809 dicom_->SetValue(Orthanc::DICOM_TAG_GRID_FRAME_OFFSET_VECTOR, s, false); | 795 dicom_->SetValue(Orthanc::DICOM_TAG_GRID_FRAME_OFFSET_VECTOR, s, false); |
810 | 796 |
811 GetTarget().SetGeometry(*dicom_); | 797 GetTarget().SetGeometry(*dicom_); |
812 } | 798 } |
813 }; | 799 }; |
800 | |
801 | |
802 static std::string GetSopClassUid(const Orthanc::DicomMap& dicom) | |
803 { | |
804 std::string s; | |
805 if (!dicom.CopyToString(s, Orthanc::DICOM_TAG_SOP_CLASS_UID, false)) | |
806 { | |
807 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, | |
808 "DICOM file without SOP class UID"); | |
809 } | |
810 else | |
811 { | |
812 return s; | |
813 } | |
814 } | |
814 | 815 |
815 | 816 |
816 class LoadGeometry : public Handler | 817 class LoadGeometry : public State |
817 { | 818 { |
818 public: | 819 public: |
819 LoadGeometry(OrthancMultiframeVolumeLoader& that, | 820 LoadGeometry(OrthancMultiframeVolumeLoader& that) : |
820 const std::string& instanceId) : | 821 State(that) |
821 Handler(that, instanceId) | |
822 { | 822 { |
823 } | 823 } |
824 | 824 |
825 virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) const | 825 virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) const |
826 { | 826 { |
833 } | 833 } |
834 | 834 |
835 std::auto_ptr<Orthanc::DicomMap> dicom(new Orthanc::DicomMap); | 835 std::auto_ptr<Orthanc::DicomMap> dicom(new Orthanc::DicomMap); |
836 dicom->FromDicomAsJson(body); | 836 dicom->FromDicomAsJson(body); |
837 | 837 |
838 std::string s; | 838 if (StringToSopClassUid(GetSopClassUid(*dicom)) == SopClassUid_RTDose) |
839 if (!dicom->CopyToString(s, Orthanc::DICOM_TAG_SOP_CLASS_UID, false)) | |
840 { | |
841 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, | |
842 "DICOM file without SOP class UID"); | |
843 } | |
844 | |
845 if (StringToSopClassUid(s) == SopClassUid_RTDose) | |
846 { | 839 { |
847 // Download the "Grid Frame Offset Vector" DICOM tag, that is | 840 // Download the "Grid Frame Offset Vector" DICOM tag, that is |
848 // mandatory for RT-DOSE, but is too long to be returned by default | 841 // mandatory for RT-DOSE, but is too long to be returned by default |
849 | 842 |
850 std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand); | 843 std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand); |
851 command->SetUri("/instances/" + GetInstanceId() + "/content/" + | 844 command->SetUri("/instances/" + GetTarget().GetInstanceId() + "/content/" + |
852 Orthanc::DICOM_TAG_GRID_FRAME_OFFSET_VECTOR.Format()); | 845 Orthanc::DICOM_TAG_GRID_FRAME_OFFSET_VECTOR.Format()); |
853 command->SetPayload(new LoadRTDoseGeometry(*this, dicom.release())); | 846 command->SetPayload(new LoadRTDoseGeometry(GetTarget(), dicom.release())); |
854 | 847 |
855 Schedule(command.release()); | 848 Schedule(command.release()); |
856 } | 849 } |
857 else | 850 else |
858 { | 851 { |
859 GetTarget().SetGeometry(*dicom); | 852 GetTarget().SetGeometry(*dicom); |
860 } | 853 } |
854 } | |
855 }; | |
856 | |
857 | |
858 | |
859 class LoadTransferSyntax : public State | |
860 { | |
861 public: | |
862 LoadTransferSyntax(OrthancMultiframeVolumeLoader& that) : | |
863 State(that) | |
864 { | |
865 } | |
866 | |
867 virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) const | |
868 { | |
869 GetTarget().SetTransferSyntax(message.GetAnswer()); | |
861 } | 870 } |
862 }; | 871 }; |
863 | 872 |
864 | 873 |
865 | 874 |
866 IOracle& oracle_; | 875 IOracle& oracle_; |
867 bool active_; | 876 bool active_; |
868 | 877 std::string instanceId_; |
869 std::auto_ptr<ImageBuffer3D> image_; | 878 std::string transferSyntaxUid_; |
879 | |
870 std::auto_ptr<DicomInstanceParameters> dicom_; | 880 std::auto_ptr<DicomInstanceParameters> dicom_; |
871 std::auto_ptr<VolumeImageGeometry> geometry_; | 881 std::auto_ptr<VolumeImageGeometry> geometry_; |
872 | 882 std::auto_ptr<ImageBuffer3D> image_; |
883 | |
884 | |
885 const std::string& GetInstanceId() const | |
886 { | |
887 if (active_) | |
888 { | |
889 return instanceId_; | |
890 } | |
891 else | |
892 { | |
893 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
894 } | |
895 } | |
896 | |
897 | |
898 void ScheduleFrameDownloads() | |
899 { | |
900 if (transferSyntaxUid_.empty() || | |
901 !HasGeometry()) | |
902 { | |
903 return; | |
904 } | |
905 | |
906 if (transferSyntaxUid_ != "1.2.840.10008.1.2" && | |
907 transferSyntaxUid_ != "1.2.840.10008.1.2.1" && | |
908 transferSyntaxUid_ != "1.2.840.10008.1.2.2") | |
909 { | |
910 throw Orthanc::OrthancException( | |
911 Orthanc::ErrorCode_NotImplemented, | |
912 "No support for multiframe instances with transfer syntax: " + transferSyntaxUid_); | |
913 } | |
914 } | |
915 | |
916 | |
917 void SetTransferSyntax(const std::string& transferSyntax) | |
918 { | |
919 transferSyntaxUid_ = Orthanc::Toolbox::StripSpaces(transferSyntax); | |
920 ScheduleFrameDownloads(); | |
921 } | |
922 | |
873 | 923 |
874 void SetGeometry(const Orthanc::DicomMap& dicom) | 924 void SetGeometry(const Orthanc::DicomMap& dicom) |
875 { | 925 { |
876 dicom_.reset(new DicomInstanceParameters(dicom)); | 926 dicom_.reset(new DicomInstanceParameters(dicom)); |
877 | 927 |
878 Orthanc::PixelFormat format; | 928 Orthanc::PixelFormat format; |
879 if (!dicom_->GetImageInformation().ExtractPixelFormat(format, true)) | 929 if (!dicom_->GetImageInformation().ExtractPixelFormat(format, true)) |
880 { | 930 { |
881 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); | 931 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); |
932 } | |
933 | |
934 double spacingZ; | |
935 switch (dicom_->GetSopClassUid()) | |
936 { | |
937 case SopClassUid_RTDose: | |
938 spacingZ = dicom_->GetThickness(); | |
939 break; | |
940 | |
941 default: | |
942 throw Orthanc::OrthancException( | |
943 Orthanc::ErrorCode_NotImplemented, | |
944 "No support for multiframe instances with SOP class UID: " + GetSopClassUid(dicom)); | |
882 } | 945 } |
883 | 946 |
884 const unsigned int width = dicom_->GetImageInformation().GetWidth(); | 947 const unsigned int width = dicom_->GetImageInformation().GetWidth(); |
885 const unsigned int height = dicom_->GetImageInformation().GetHeight(); | 948 const unsigned int height = dicom_->GetImageInformation().GetHeight(); |
886 const unsigned int depth = dicom_->GetImageInformation().GetNumberOfFrames(); | 949 const unsigned int depth = dicom_->GetImageInformation().GetNumberOfFrames(); |
888 geometry_.reset(new VolumeImageGeometry); | 951 geometry_.reset(new VolumeImageGeometry); |
889 geometry_->SetSize(width, height, depth); | 952 geometry_->SetSize(width, height, depth); |
890 geometry_->SetAxialGeometry(dicom_->GetGeometry()); | 953 geometry_->SetAxialGeometry(dicom_->GetGeometry()); |
891 geometry_->SetVoxelDimensions(dicom_->GetPixelSpacingX(), | 954 geometry_->SetVoxelDimensions(dicom_->GetPixelSpacingX(), |
892 dicom_->GetPixelSpacingY(), | 955 dicom_->GetPixelSpacingY(), |
893 dicom_->GetThickness()); | 956 spacingZ); |
894 | 957 |
895 image_.reset(new ImageBuffer3D(format, width, height, depth, | 958 image_.reset(new ImageBuffer3D(format, width, height, depth, |
896 false /* don't compute range */)); | 959 false /* don't compute range */)); |
897 | 960 |
898 { | 961 ScheduleFrameDownloads(); |
899 Orthanc::DicomArray a(dicom); | |
900 a.Print(stdout); | |
901 } | |
902 } | 962 } |
903 | 963 |
904 | 964 |
905 public: | 965 public: |
906 OrthancMultiframeVolumeLoader(IOracle& oracle, | 966 OrthancMultiframeVolumeLoader(IOracle& oracle, |
912 oracleObservable.RegisterObserverCallback( | 972 oracleObservable.RegisterObserverCallback( |
913 new Callable<OrthancMultiframeVolumeLoader, OrthancRestApiCommand::SuccessMessage> | 973 new Callable<OrthancMultiframeVolumeLoader, OrthancRestApiCommand::SuccessMessage> |
914 (*this, &OrthancMultiframeVolumeLoader::Handle)); | 974 (*this, &OrthancMultiframeVolumeLoader::Handle)); |
915 } | 975 } |
916 | 976 |
977 | |
978 bool HasGeometry() const | |
979 { | |
980 return (dicom_.get() != NULL && | |
981 geometry_.get() != NULL && | |
982 image_.get() != NULL); | |
983 } | |
984 | |
985 | |
917 void LoadInstance(const std::string& instanceId) | 986 void LoadInstance(const std::string& instanceId) |
918 { | 987 { |
919 if (active_) | 988 if (active_) |
920 { | 989 { |
921 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | 990 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); |
922 } | 991 } |
923 else | 992 else |
924 { | 993 { |
925 active_ = true; | 994 active_ = true; |
926 | 995 instanceId_ = instanceId; |
927 std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand); | 996 |
928 command->SetUri("/instances/" + instanceId + "/tags"); | 997 { |
929 command->SetPayload(new LoadGeometry(*this, instanceId)); | 998 std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand); |
930 | 999 command->SetUri("/instances/" + instanceId + "/tags"); |
931 oracle_.Schedule(*this, command.release()); | 1000 command->SetPayload(new LoadGeometry(*this)); |
1001 oracle_.Schedule(*this, command.release()); | |
1002 } | |
1003 | |
1004 { | |
1005 std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand); | |
1006 command->SetUri("/instances/" + instanceId + "/metadata/TransferSyntax"); | |
1007 command->SetPayload(new LoadTransferSyntax(*this)); | |
1008 oracle_.Schedule(*this, command.release()); | |
1009 } | |
932 } | 1010 } |
933 } | 1011 } |
934 }; | 1012 }; |
935 | 1013 |
936 | 1014 |
1321 | 1399 |
1322 // 2017-11-17-Anonymized | 1400 // 2017-11-17-Anonymized |
1323 //loader1->LoadSeries("cb3ea4d1-d08f3856-ad7b6314-74d88d77-60b05618"); // CT | 1401 //loader1->LoadSeries("cb3ea4d1-d08f3856-ad7b6314-74d88d77-60b05618"); // CT |
1324 loader3->LoadInstance("41029085-71718346-811efac4-420e2c15-d39f99b6"); // RT-DOSE | 1402 loader3->LoadInstance("41029085-71718346-811efac4-420e2c15-d39f99b6"); // RT-DOSE |
1325 | 1403 |
1404 // 2015-01-28-Multiframe | |
1405 //loader3->LoadInstance("88f71e2a-5fad1c61-96ed14d6-5b3d3cf7-a5825279"); // Multiframe CT | |
1406 | |
1326 // Delphine | 1407 // Delphine |
1327 //loader1->LoadSeries("5990e39c-51e5f201-fe87a54c-31a55943-e59ef80e"); // CT | 1408 //loader1->LoadSeries("5990e39c-51e5f201-fe87a54c-31a55943-e59ef80e"); // CT |
1328 //loader1->LoadSeries("67f1b334-02c16752-45026e40-a5b60b6b-030ecab5"); // Lung 1/10mm | 1409 //loader1->LoadSeries("67f1b334-02c16752-45026e40-a5b60b6b-030ecab5"); // Lung 1/10mm |
1329 | 1410 |
1330 | 1411 |