comparison OrthancStone/Sources/Toolbox/DicomStructureSet2.cpp @ 1834:126522623e20

replaced OrthancStone::DicomPath by new class Orthanc::DicomPath from orthanc framework
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 10 Jun 2021 12:07:04 +0200
parents 946eb7200b82
children f6eaf617d8e8
comparison
equal deleted inserted replaced
1833:3c0996f028a1 1834:126522623e20
29 #include <Logging.h> 29 #include <Logging.h>
30 #include <OrthancException.h> 30 #include <OrthancException.h>
31 #include <Toolbox.h> 31 #include <Toolbox.h>
32 #include <DicomFormat/DicomTag.h> 32 #include <DicomFormat/DicomTag.h>
33 33
34 #include <FullOrthancDataset.h> 34 #include "DicomStructure2.h"
35 #include <DicomDatasetReader.h> 35 #include "GenericToolbox.h"
36 #include "OrthancDatasets/DicomDatasetReader.h"
36 37
37 namespace OrthancStone 38 namespace OrthancStone
38 { 39 {
39 static const OrthancPlugins::DicomTag DICOM_TAG_CONTOUR_GEOMETRIC_TYPE(0x3006, 0x0042); 40 static const Orthanc::DicomTag DICOM_TAG_CONTOUR_GEOMETRIC_TYPE(0x3006, 0x0042);
40 static const OrthancPlugins::DicomTag DICOM_TAG_CONTOUR_IMAGE_SEQUENCE(0x3006, 0x0016); 41 static const Orthanc::DicomTag DICOM_TAG_CONTOUR_IMAGE_SEQUENCE(0x3006, 0x0016);
41 static const OrthancPlugins::DicomTag DICOM_TAG_CONTOUR_SEQUENCE(0x3006, 0x0040); 42 static const Orthanc::DicomTag DICOM_TAG_CONTOUR_SEQUENCE(0x3006, 0x0040);
42 static const OrthancPlugins::DicomTag DICOM_TAG_CONTOUR_DATA(0x3006, 0x0050); 43 static const Orthanc::DicomTag DICOM_TAG_CONTOUR_DATA(0x3006, 0x0050);
43 static const OrthancPlugins::DicomTag DICOM_TAG_NUMBER_OF_CONTOUR_POINTS(0x3006, 0x0046); 44 static const Orthanc::DicomTag DICOM_TAG_NUMBER_OF_CONTOUR_POINTS(0x3006, 0x0046);
44 static const OrthancPlugins::DicomTag DICOM_TAG_REFERENCED_SOP_INSTANCE_UID(0x0008, 0x1155); 45 static const Orthanc::DicomTag DICOM_TAG_REFERENCED_SOP_INSTANCE_UID(0x0008, 0x1155);
45 static const OrthancPlugins::DicomTag DICOM_TAG_ROI_CONTOUR_SEQUENCE(0x3006, 0x0039); 46 static const Orthanc::DicomTag DICOM_TAG_ROI_CONTOUR_SEQUENCE(0x3006, 0x0039);
46 static const OrthancPlugins::DicomTag DICOM_TAG_ROI_DISPLAY_COLOR(0x3006, 0x002a); 47 static const Orthanc::DicomTag DICOM_TAG_ROI_DISPLAY_COLOR(0x3006, 0x002a);
47 static const OrthancPlugins::DicomTag DICOM_TAG_ROI_NAME(0x3006, 0x0026); 48 static const Orthanc::DicomTag DICOM_TAG_ROI_NAME(0x3006, 0x0026);
48 static const OrthancPlugins::DicomTag DICOM_TAG_RT_ROI_INTERPRETED_TYPE(0x3006, 0x00a4); 49 static const Orthanc::DicomTag DICOM_TAG_RT_ROI_INTERPRETED_TYPE(0x3006, 0x00a4);
49 static const OrthancPlugins::DicomTag DICOM_TAG_RT_ROI_OBSERVATIONS_SEQUENCE(0x3006, 0x0080); 50 static const Orthanc::DicomTag DICOM_TAG_RT_ROI_OBSERVATIONS_SEQUENCE(0x3006, 0x0080);
50 static const OrthancPlugins::DicomTag DICOM_TAG_STRUCTURE_SET_ROI_SEQUENCE(0x3006, 0x0020); 51 static const Orthanc::DicomTag DICOM_TAG_STRUCTURE_SET_ROI_SEQUENCE(0x3006, 0x0020);
51 52
52 static inline uint8_t ConvertAndClipToByte(double v) 53 static inline uint8_t ConvertAndClipToByte(double v)
53 { 54 {
54 if (v < 0) 55 if (v < 0)
55 { 56 {
64 return static_cast<uint8_t>(v); 65 return static_cast<uint8_t>(v);
65 } 66 }
66 } 67 }
67 68
68 static bool ReadDicomToVector(Vector& target, 69 static bool ReadDicomToVector(Vector& target,
69 const OrthancPlugins::IDicomDataset& dataset, 70 const IDicomDataset& dataset,
70 const OrthancPlugins::DicomPath& tag) 71 const Orthanc::DicomPath& tag)
71 { 72 {
72 std::string value; 73 std::string value;
73 return (dataset.GetStringValue(value, tag) && 74 return (dataset.GetStringValue(value, tag) &&
74 GenericToolbox::FastParseVector(target, value)); 75 GenericToolbox::FastParseVector(target, value));
75 } 76 }
76 77
77 78
78 void DicomPathToString(std::string& s, const OrthancPlugins::DicomPath& dicomPath) 79 void DicomPathToString(std::string& s, const Orthanc::DicomPath& dicomPath)
79 { 80 {
80 std::stringstream tmp; 81 std::stringstream tmp;
81 for (size_t i = 0; i < dicomPath.GetPrefixLength(); ++i) 82 for (size_t i = 0; i < dicomPath.GetPrefixLength(); ++i)
82 { 83 {
83 OrthancPlugins::DicomTag tag = dicomPath.GetPrefixTag(i); 84 Orthanc::DicomTag tag = dicomPath.GetPrefixTag(i);
84 85
85 // We use this other object to be able to use GetMainTagsName 86 // We use this other object to be able to use GetMainTagsName
86 // and Format 87 // and Format
87 Orthanc::DicomTag tag2(tag.GetGroup(), tag.GetElement()); 88 Orthanc::DicomTag tag2(tag.GetGroup(), tag.GetElement());
88 size_t index = dicomPath.GetPrefixIndex(i); 89 size_t index = dicomPath.GetPrefixIndex(i);
89 tmp << tag2.GetMainTagsName() << " (" << tag2.Format() << ") [" << index << "] / "; 90 tmp << tag2.GetMainTagsName() << " (" << tag2.Format() << ") [" << index << "] / ";
90 } 91 }
91 const OrthancPlugins::DicomTag& tag = dicomPath.GetFinalTag(); 92 const Orthanc::DicomTag& tag = dicomPath.GetFinalTag();
92 Orthanc::DicomTag tag2(tag.GetGroup(), tag.GetElement()); 93 Orthanc::DicomTag tag2(tag.GetGroup(), tag.GetElement());
93 tmp << tag2.GetMainTagsName() << " (" << tag2.Format() << ")"; 94 tmp << tag2.GetMainTagsName() << " (" << tag2.Format() << ")";
94 s = tmp.str(); 95 s = tmp.str();
95 } 96 }
96 97
97 std::ostream& operator<<(std::ostream& s, const OrthancPlugins::DicomPath& dicomPath) 98 std::ostream& operator<<(std::ostream& s, const Orthanc::DicomPath& dicomPath)
98 { 99 {
99 std::string tmp; 100 std::string tmp;
100 DicomPathToString(tmp, dicomPath); 101 DicomPathToString(tmp, dicomPath);
101 s << tmp; 102 s << tmp;
102 return s; 103 return s;
112 DicomStructureSet2::~DicomStructureSet2() 113 DicomStructureSet2::~DicomStructureSet2()
113 { 114 {
114 115
115 } 116 }
116 117
117 void DicomStructureSet2::SetContents(const OrthancPlugins::FullOrthancDataset& tags) 118 void DicomStructureSet2::SetContents(const FullOrthancDataset& tags)
118 { 119 {
119 FillStructuresFromDataset(tags); 120 FillStructuresFromDataset(tags);
120 ComputeDependentProperties(); 121 ComputeDependentProperties();
121 } 122 }
122 123
126 { 127 {
127 structures_[i].ComputeDependentProperties(); 128 structures_[i].ComputeDependentProperties();
128 } 129 }
129 } 130 }
130 131
131 void DicomStructureSet2::FillStructuresFromDataset(const OrthancPlugins::FullOrthancDataset& tags) 132 void DicomStructureSet2::FillStructuresFromDataset(const FullOrthancDataset& tags)
132 { 133 {
133 OrthancPlugins::DicomDatasetReader reader(tags); 134 DicomDatasetReader reader(tags);
134 135
135 // a few sanity checks 136 // a few sanity checks
136 size_t count = 0, tmp = 0; 137 size_t count = 0, tmp = 0;
137 138
138 // DICOM_TAG_RT_ROI_OBSERVATIONS_SEQUENCE (0x3006, 0x0080); 139 // DICOM_TAG_RT_ROI_OBSERVATIONS_SEQUENCE (0x3006, 0x0080);
139 // DICOM_TAG_ROI_CONTOUR_SEQUENCE (0x3006, 0x0039); 140 // DICOM_TAG_ROI_CONTOUR_SEQUENCE (0x3006, 0x0039);
140 // DICOM_TAG_STRUCTURE_SET_ROI_SEQUENCE (0x3006, 0x0020); 141 // DICOM_TAG_STRUCTURE_SET_ROI_SEQUENCE (0x3006, 0x0020);
141 if (!tags.GetSequenceSize(count, DICOM_TAG_RT_ROI_OBSERVATIONS_SEQUENCE) || 142 if (!tags.GetSequenceSize(count, Orthanc::DicomPath(DICOM_TAG_RT_ROI_OBSERVATIONS_SEQUENCE)) ||
142 !tags.GetSequenceSize(tmp, DICOM_TAG_ROI_CONTOUR_SEQUENCE) || 143 !tags.GetSequenceSize(tmp, Orthanc::DicomPath(DICOM_TAG_ROI_CONTOUR_SEQUENCE)) ||
143 tmp != count || 144 tmp != count ||
144 !tags.GetSequenceSize(tmp, DICOM_TAG_STRUCTURE_SET_ROI_SEQUENCE) || 145 !tags.GetSequenceSize(tmp, Orthanc::DicomPath(DICOM_TAG_STRUCTURE_SET_ROI_SEQUENCE)) ||
145 tmp != count) 146 tmp != count)
146 { 147 {
147 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); 148 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
148 } 149 }
149 150
150 // let's now parse the structures stored in the dicom file 151 // let's now parse the structures stored in the dicom file
155 structures_.resize(count); 156 structures_.resize(count);
156 for (size_t i = 0; i < count; i++) 157 for (size_t i = 0; i < count; i++)
157 { 158 {
158 // (0x3006, 0x0080)[i]/(0x3006, 0x00a4) 159 // (0x3006, 0x0080)[i]/(0x3006, 0x00a4)
159 structures_[i].interpretation_ = reader.GetStringValue 160 structures_[i].interpretation_ = reader.GetStringValue
160 (OrthancPlugins::DicomPath(DICOM_TAG_RT_ROI_OBSERVATIONS_SEQUENCE, i, 161 (Orthanc::DicomPath(DICOM_TAG_RT_ROI_OBSERVATIONS_SEQUENCE, i,
161 DICOM_TAG_RT_ROI_INTERPRETED_TYPE), 162 DICOM_TAG_RT_ROI_INTERPRETED_TYPE),
162 "No interpretation"); 163 "No interpretation");
163 164
164 // (0x3006, 0x0020)[i]/(0x3006, 0x0026) 165 // (0x3006, 0x0020)[i]/(0x3006, 0x0026)
165 structures_[i].name_ = reader.GetStringValue 166 structures_[i].name_ = reader.GetStringValue
166 (OrthancPlugins::DicomPath(DICOM_TAG_STRUCTURE_SET_ROI_SEQUENCE, i, 167 (Orthanc::DicomPath(DICOM_TAG_STRUCTURE_SET_ROI_SEQUENCE, i,
167 DICOM_TAG_ROI_NAME), 168 DICOM_TAG_ROI_NAME),
168 "No name"); 169 "No name");
169 170
170 Vector color; 171 Vector color;
171 // (0x3006, 0x0039)[i]/(0x3006, 0x002a) 172 // (0x3006, 0x0039)[i]/(0x3006, 0x002a)
172 if (ReadDicomToVector(color, tags, OrthancPlugins::DicomPath( 173 if (ReadDicomToVector(color, tags, Orthanc::DicomPath(
173 DICOM_TAG_ROI_CONTOUR_SEQUENCE, i, DICOM_TAG_ROI_DISPLAY_COLOR)) 174 DICOM_TAG_ROI_CONTOUR_SEQUENCE, i, DICOM_TAG_ROI_DISPLAY_COLOR))
174 && color.size() == 3) 175 && color.size() == 3)
175 { 176 {
176 structures_[i].red_ = ConvertAndClipToByte(color[0]); 177 structures_[i].red_ = ConvertAndClipToByte(color[0]);
177 structures_[i].green_ = ConvertAndClipToByte(color[1]); 178 structures_[i].green_ = ConvertAndClipToByte(color[1]);
178 structures_[i].blue_ = ConvertAndClipToByte(color[2]); 179 structures_[i].blue_ = ConvertAndClipToByte(color[2]);
179 } 180 }
185 } 186 }
186 187
187 size_t countSlices; 188 size_t countSlices;
188 // DICOM_TAG_ROI_CONTOUR_SEQUENCE (0x3006, 0x0039); 189 // DICOM_TAG_ROI_CONTOUR_SEQUENCE (0x3006, 0x0039);
189 // DICOM_TAG_CONTOUR_SEQUENCE (0x3006, 0x0040); 190 // DICOM_TAG_CONTOUR_SEQUENCE (0x3006, 0x0040);
190 if (!tags.GetSequenceSize(countSlices, OrthancPlugins::DicomPath( 191 if (!tags.GetSequenceSize(countSlices, Orthanc::DicomPath(
191 DICOM_TAG_ROI_CONTOUR_SEQUENCE, i, DICOM_TAG_CONTOUR_SEQUENCE))) 192 DICOM_TAG_ROI_CONTOUR_SEQUENCE, i, DICOM_TAG_CONTOUR_SEQUENCE)))
192 { 193 {
193 LOG(WARNING) << "DicomStructureSet2::SetContents | structure \"" << structures_[i].name_ << "\" has no slices!"; 194 LOG(WARNING) << "DicomStructureSet2::SetContents | structure \"" << structures_[i].name_ << "\" has no slices!";
194 countSlices = 0; 195 countSlices = 0;
195 } 196 }
196 197
197 LOG(INFO) << "New RT structure: \"" << structures_[i].name_ 198 LOG(INFO) << "New RT structure: \"" << structures_[i].name_
198 << "\" with interpretation \"" << structures_[i].interpretation_ 199 << "\" with interpretation \"" << structures_[i].interpretation_
199 << "\" containing " << countSlices << " slices (color: " 200 << "\" containing " << countSlices << " slices (color: "
200 << static_cast<int>(structures_[i].red_) << "," 201 << static_cast<int>(structures_[i].red_) << ","
201 << static_cast<int>(structures_[i].green_) << "," 202 << static_cast<int>(structures_[i].green_) << ","
202 << static_cast<int>(structures_[i].blue_) << ")"; 203 << static_cast<int>(structures_[i].blue_) << ")";
203 204
204 // These temporary variables avoid allocating many vectors in the loop below 205 // These temporary variables avoid allocating many vectors in the loop below
205 206
206 // (0x3006, 0x0039)[i]/(0x3006, 0x0040)[0]/(0x3006, 0x0046) 207 // (0x3006, 0x0039)[i]/(0x3006, 0x0040)[0]/(0x3006, 0x0046)
207 OrthancPlugins::DicomPath countPointsPath( 208 Orthanc::DicomPath countPointsPath(
208 DICOM_TAG_ROI_CONTOUR_SEQUENCE, i, 209 DICOM_TAG_ROI_CONTOUR_SEQUENCE, i,
209 DICOM_TAG_CONTOUR_SEQUENCE, 0, 210 DICOM_TAG_CONTOUR_SEQUENCE, 0,
210 DICOM_TAG_NUMBER_OF_CONTOUR_POINTS); 211 DICOM_TAG_NUMBER_OF_CONTOUR_POINTS);
211 212
212 OrthancPlugins::DicomPath geometricTypePath( 213 Orthanc::DicomPath geometricTypePath(
213 DICOM_TAG_ROI_CONTOUR_SEQUENCE, i, 214 DICOM_TAG_ROI_CONTOUR_SEQUENCE, i,
214 DICOM_TAG_CONTOUR_SEQUENCE, 0, 215 DICOM_TAG_CONTOUR_SEQUENCE, 0,
215 DICOM_TAG_CONTOUR_GEOMETRIC_TYPE); 216 DICOM_TAG_CONTOUR_GEOMETRIC_TYPE);
216 217
217 OrthancPlugins::DicomPath imageSequencePath( 218 Orthanc::DicomPath imageSequencePath(
218 DICOM_TAG_ROI_CONTOUR_SEQUENCE, i, 219 DICOM_TAG_ROI_CONTOUR_SEQUENCE, i,
219 DICOM_TAG_CONTOUR_SEQUENCE, 0, 220 DICOM_TAG_CONTOUR_SEQUENCE, 0,
220 DICOM_TAG_CONTOUR_IMAGE_SEQUENCE); 221 DICOM_TAG_CONTOUR_IMAGE_SEQUENCE);
221 222
222 // (3006,0039)[i] / (0x3006, 0x0040)[0] / (0x3006, 0x0016)[0] / (0x0008, 0x1155) 223 // (3006,0039)[i] / (0x3006, 0x0040)[0] / (0x3006, 0x0016)[0] / (0x0008, 0x1155)
223 OrthancPlugins::DicomPath referencedInstancePath( 224 Orthanc::DicomPath referencedInstancePath(
224 DICOM_TAG_ROI_CONTOUR_SEQUENCE, i, 225 DICOM_TAG_ROI_CONTOUR_SEQUENCE, i,
225 DICOM_TAG_CONTOUR_SEQUENCE, 0, 226 DICOM_TAG_CONTOUR_SEQUENCE, 0,
226 DICOM_TAG_CONTOUR_IMAGE_SEQUENCE, 0, 227 DICOM_TAG_CONTOUR_IMAGE_SEQUENCE, 0,
227 DICOM_TAG_REFERENCED_SOP_INSTANCE_UID); 228 DICOM_TAG_REFERENCED_SOP_INSTANCE_UID);
228 229
229 OrthancPlugins::DicomPath contourDataPath( 230 Orthanc::DicomPath contourDataPath(
230 DICOM_TAG_ROI_CONTOUR_SEQUENCE, i, 231 DICOM_TAG_ROI_CONTOUR_SEQUENCE, i,
231 DICOM_TAG_CONTOUR_SEQUENCE, 0, 232 DICOM_TAG_CONTOUR_SEQUENCE, 0,
232 DICOM_TAG_CONTOUR_DATA); 233 DICOM_TAG_CONTOUR_DATA);
233 234
234 for (size_t j = 0; j < countSlices; j++) 235 for (size_t j = 0; j < countSlices; j++)
270 contourDataPath.SetPrefixIndex(1, j); 271 contourDataPath.SetPrefixIndex(1, j);
271 std::string slicesData = reader.GetMandatoryStringValue(contourDataPath); 272 std::string slicesData = reader.GetMandatoryStringValue(contourDataPath);
272 273
273 Vector points; 274 Vector points;
274 if (!GenericToolbox::FastParseVector(points, slicesData) || 275 if (!GenericToolbox::FastParseVector(points, slicesData) ||
275 points.size() != 3 * countPoints) 276 points.size() != 3 * countPoints)
276 { 277 {
277 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); 278 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
278 } 279 }
279 280
280 // seen in real world 281 // seen in real world