comparison Framework/Toolbox/Slice.cpp @ 117:42c05a3baee3 wasm

loading multi-frame instances as 3D volumes
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 28 Sep 2017 16:55:51 +0200
parents 2eca030792aa
children a4d0b6c82b29
comparison
equal deleted inserted replaced
116:4c5f7cda8624 117:42c05a3baee3
19 **/ 19 **/
20 20
21 21
22 #include "Slice.h" 22 #include "Slice.h"
23 23
24 #include "../Enumerations.h"
25
26 #include <Core/Logging.h>
24 #include <Core/OrthancException.h> 27 #include <Core/OrthancException.h>
28 #include <Core/Toolbox.h>
29
30 #include <boost/lexical_cast.hpp>
25 31
26 namespace OrthancStone 32 namespace OrthancStone
27 { 33 {
34 static bool ParseDouble(double& target,
35 const std::string& source)
36 {
37 try
38 {
39 target = boost::lexical_cast<double>(source);
40 return true;
41 }
42 catch (boost::bad_lexical_cast&)
43 {
44 return false;
45 }
46 }
47
48 bool Slice::ComputeRTDoseGeometry(const OrthancPlugins::DicomDatasetReader& reader,
49 unsigned int frame)
50 {
51 // http://dicom.nema.org/medical/Dicom/2016a/output/chtml/part03/sect_C.8.8.3.2.html
52 static const OrthancPlugins::DicomTag DICOM_TAG_GRID_FRAME_OFFSET_VECTOR(0x3004, 0x000c);
53 static const OrthancPlugins::DicomTag DICOM_TAG_FRAME_INCREMENT_POINTER(0x0028, 0x0009);
54
55 std::string increment = reader.GetStringValue(DICOM_TAG_FRAME_INCREMENT_POINTER, "");
56 std::string offsetTag;
57
58 bool ok = reader.GetDataset().GetStringValue(offsetTag, DICOM_TAG_GRID_FRAME_OFFSET_VECTOR);
59 if (!ok)
60 {
61 LOG(ERROR) << "Cannot read the \"GridFrameOffsetVector\" tag, check you are using Orthanc >= 1.3.1";
62 return false;
63 }
64
65 Orthanc::Toolbox::ToUpperCase(increment);
66 if (increment != "3004,000C" ||
67 offsetTag.empty())
68 {
69 return false;
70 }
71
72 std::vector<std::string> offsets;
73 Orthanc::Toolbox::TokenizeString(offsets, offsetTag, '\\');
74
75 if (frameCount_ == 0 ||
76 offsets.size() != frameCount_ ||
77 frame >= frameCount_)
78 {
79 LOG(ERROR) << "No information about the 3D location of some slice(s) in a RT DOSE";
80 return false;
81 }
82
83 double offset0, z;
84
85 if (!ParseDouble(offset0, offsets[0]) ||
86 !ParseDouble(z, offsets[frame]))
87 {
88 LOG(ERROR) << "Invalid syntax";
89 return false;
90 }
91
92 if (!GeometryToolbox::IsCloseToZero(offset0))
93 {
94 LOG(ERROR) << "Invalid syntax";
95 return false;
96 }
97
98 geometry_ = CoordinateSystem3D(geometry_.GetOrigin() + z * geometry_.GetNormal(),
99 geometry_.GetAxisX(),
100 geometry_.GetAxisY());
101
102 return true;
103 }
104
105
28 bool Slice::ParseOrthancFrame(const OrthancPlugins::IDicomDataset& dataset, 106 bool Slice::ParseOrthancFrame(const OrthancPlugins::IDicomDataset& dataset,
29 const std::string& instanceId, 107 const std::string& instanceId,
30 unsigned int frame) 108 unsigned int frame)
31 { 109 {
110 orthancInstanceId_ = instanceId;
111 frame_ = frame;
112 type_ = Type_OrthancDecodableFrame;
113
32 OrthancPlugins::DicomDatasetReader reader(dataset); 114 OrthancPlugins::DicomDatasetReader reader(dataset);
33 115
34 unsigned int frameCount; 116 sopClassUid_ = reader.GetStringValue(OrthancPlugins::DICOM_TAG_SOP_CLASS_UID, "");
35 if (!reader.GetUnsignedIntegerValue(frameCount, OrthancPlugins::DICOM_TAG_NUMBER_OF_FRAMES)) 117 if (sopClassUid_.empty())
36 { 118 {
37 frameCount = 1; // Assume instance with one frame 119 LOG(ERROR) << "Instance without a SOP class UID";
38 } 120 return false;
39 121 }
40 if (frame >= frameCount) 122
41 { 123 if (!reader.GetUnsignedIntegerValue(frameCount_, OrthancPlugins::DICOM_TAG_NUMBER_OF_FRAMES))
42 return false; 124 {
43 } 125 frameCount_ = 1; // Assume instance with one frame
44 126 }
45 if (!reader.GetDoubleValue(thickness_, OrthancPlugins::DICOM_TAG_SLICE_THICKNESS)) 127
46 { 128 if (frame >= frameCount_)
47 thickness_ = 100.0 * std::numeric_limits<double>::epsilon(); 129 {
48 } 130 return false;
131 }
132
133 if (!reader.GetUnsignedIntegerValue(width_, OrthancPlugins::DICOM_TAG_COLUMNS) ||
134 !reader.GetUnsignedIntegerValue(height_, OrthancPlugins::DICOM_TAG_ROWS))
135 {
136 return false;
137 }
138
139 thickness_ = 100.0 * std::numeric_limits<double>::epsilon();
140
141 std::string tmp;
142 if (dataset.GetStringValue(tmp, OrthancPlugins::DICOM_TAG_SLICE_THICKNESS))
143 {
144 if (!tmp.empty() &&
145 !ParseDouble(thickness_, tmp))
146 {
147 return false; // Syntax error
148 }
149 }
150
151 converter_.ReadParameters(dataset);
49 152
50 GeometryToolbox::GetPixelSpacing(pixelSpacingX_, pixelSpacingY_, dataset); 153 GeometryToolbox::GetPixelSpacing(pixelSpacingX_, pixelSpacingY_, dataset);
51 154
52 std::string position, orientation; 155 std::string position, orientation;
53 if (dataset.GetStringValue(position, OrthancPlugins::DICOM_TAG_IMAGE_POSITION_PATIENT) && 156 if (dataset.GetStringValue(position, OrthancPlugins::DICOM_TAG_IMAGE_POSITION_PATIENT) &&
54 dataset.GetStringValue(orientation, OrthancPlugins::DICOM_TAG_IMAGE_ORIENTATION_PATIENT)) 157 dataset.GetStringValue(orientation, OrthancPlugins::DICOM_TAG_IMAGE_ORIENTATION_PATIENT))
55 { 158 {
56 geometry_ = CoordinateSystem3D(position, orientation); 159 geometry_ = CoordinateSystem3D(position, orientation);
57 } 160
58 161 bool ok = true;
59 if (reader.GetUnsignedIntegerValue(width_, OrthancPlugins::DICOM_TAG_COLUMNS) && 162 SopClassUid tmp;
60 reader.GetUnsignedIntegerValue(height_, OrthancPlugins::DICOM_TAG_ROWS)) 163
61 { 164 if (StringToSopClassUid(tmp, sopClassUid_))
62 orthancInstanceId_ = instanceId; 165 {
63 frame_ = frame; 166 switch (tmp)
64 converter_.ReadParameters(dataset); 167 {
65 168 case SopClassUid_RTDose:
66 type_ = Type_OrthancInstance; 169 type_ = Type_OrthancRawFrame;
67 return true; 170 ok = ComputeRTDoseGeometry(reader, frame);
171 break;
172
173 default:
174 break;
175 }
176 }
177
178 if (!ok)
179 {
180 LOG(ERROR) << "Cannot deduce the 3D location of frame " << frame
181 << " in instance " << instanceId << ", whose SOP class UID is: " << sopClassUid_;
182 return false;
183 }
184 }
185
186 return true;
187 }
188
189
190 const std::string Slice::GetOrthancInstanceId() const
191 {
192 if (type_ == Type_OrthancDecodableFrame ||
193 type_ == Type_OrthancRawFrame)
194 {
195 return orthancInstanceId_;
68 } 196 }
69 else 197 else
70 { 198 {
71 return false; 199 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
72 } 200 }
73 }
74
75
76 const std::string Slice::GetOrthancInstanceId() const
77 {
78 if (type_ != Type_OrthancInstance)
79 {
80 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
81 }
82
83 return orthancInstanceId_;
84 } 201 }
85 202
86 203
87 unsigned int Slice::GetFrame() const 204 unsigned int Slice::GetFrame() const
88 { 205 {