Mercurial > hg > orthanc
comparison OrthancServer/RadiotherapyRestApi.cpp @ 532:b22312081388 dicom-rt
extract roi geometry
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Fri, 30 Aug 2013 16:09:19 +0200 |
parents | bd2087bb6450 |
children | da8e064d0d49 |
comparison
equal
deleted
inserted
replaced
529:bd2087bb6450 | 532:b22312081388 |
---|---|
38 OrthancRestApi& contextApi = \ | 38 OrthancRestApi& contextApi = \ |
39 dynamic_cast<OrthancRestApi&>(call.GetContext()); \ | 39 dynamic_cast<OrthancRestApi&>(call.GetContext()); \ |
40 ServerContext& context = contextApi.GetContext() | 40 ServerContext& context = contextApi.GetContext() |
41 | 41 |
42 | 42 |
43 // DICOM tags for RT-STRUCT | |
44 | |
43 #define REFERENCED_STUDY_SEQUENCE "0008,1110" | 45 #define REFERENCED_STUDY_SEQUENCE "0008,1110" |
44 #define REFERENCED_SOP_INSTANCE_UID "0008,1155" | 46 #define REFERENCED_SOP_INSTANCE_UID "0008,1155" |
45 #define FRAME_OF_REFERENCE_UID "0020,0052" | 47 #define FRAME_OF_REFERENCE_UID "0020,0052" |
46 #define REFERENCED_FRAME_OF_REFERENCE_SEQUENCE "3006,0010" | 48 #define REFERENCED_FRAME_OF_REFERENCE_SEQUENCE "3006,0010" |
47 #define STRUCTURE_SET_ROI_SEQUENCE "3006,0020" | 49 #define STRUCTURE_SET_ROI_SEQUENCE "3006,0020" |
49 #define ROI_NAME "3006,0026" | 51 #define ROI_NAME "3006,0026" |
50 #define ROI_GENERATION_ALGORITHM "3006,0036" | 52 #define ROI_GENERATION_ALGORITHM "3006,0036" |
51 #define ROI_CONTOUR_SEQUENCE "3006,0039" | 53 #define ROI_CONTOUR_SEQUENCE "3006,0039" |
52 #define REFERENCED_ROI_NUMBER "3006,0084" | 54 #define REFERENCED_ROI_NUMBER "3006,0084" |
53 #define ROI_DISPLAY_COLOR "3006,002a" | 55 #define ROI_DISPLAY_COLOR "3006,002a" |
56 #define CONTOUR_SEQUENCE "3006,0040" | |
57 #define CONTOUR_IMAGE_SEQUENCE "3006,0016" | |
58 #define CONTOUR_GEOMETRIC_TYPE "3006,0042" | |
59 #define NUMBER_OF_CONTOUR_POINTS "3006,0046" | |
60 #define CONTOUR_DATA "3006,0050" | |
61 | |
54 | 62 |
55 namespace Orthanc | 63 namespace Orthanc |
56 { | 64 { |
57 static bool CheckSeriesModality(Json::Value& study, | 65 static bool CheckSeriesModality(Json::Value& study, |
58 Json::Value& series, | 66 Json::Value& series, |
206 Json::Value result; | 214 Json::Value result; |
207 | 215 |
208 bool found = false; | 216 bool found = false; |
209 for (Json::Value::ArrayIndex i = 0; i < content[STRUCTURE_SET_ROI_SEQUENCE]["Value"].size(); i++) | 217 for (Json::Value::ArrayIndex i = 0; i < content[STRUCTURE_SET_ROI_SEQUENCE]["Value"].size(); i++) |
210 { | 218 { |
211 if (content[STRUCTURE_SET_ROI_SEQUENCE]["Value"][i].isMember(ROI_NUMBER) && | 219 const Json::Value& roi = content[STRUCTURE_SET_ROI_SEQUENCE]["Value"][i]; |
212 content[STRUCTURE_SET_ROI_SEQUENCE]["Value"][i].isMember(ROI_NAME) && | 220 |
213 content[STRUCTURE_SET_ROI_SEQUENCE]["Value"][i][ROI_NUMBER]["Value"].asString() == call.GetUriComponent("roi", "")) | 221 if (roi.isMember(ROI_NUMBER) && |
222 roi.isMember(ROI_NAME) && | |
223 roi[ROI_NUMBER]["Value"].asString() == call.GetUriComponent("roi", "")) | |
214 { | 224 { |
215 result["Number"] = call.GetUriComponent("roi", ""); | 225 result["Number"] = call.GetUriComponent("roi", ""); |
216 result["Name"] = content[STRUCTURE_SET_ROI_SEQUENCE]["Value"][i][ROI_NAME]["Value"].asString(); | 226 result["Name"] = roi[ROI_NAME]["Value"].asString(); |
217 result["GenerationAlgorithm"] = content[STRUCTURE_SET_ROI_SEQUENCE]["Value"][i][ROI_GENERATION_ALGORITHM]["Value"].asString(); | 227 result["GenerationAlgorithm"] = roi[ROI_GENERATION_ALGORITHM]["Value"].asString(); |
218 found = true; | 228 found = true; |
219 } | 229 } |
220 } | 230 } |
221 | 231 |
222 if (!found) | 232 if (!found) |
224 return; | 234 return; |
225 } | 235 } |
226 | 236 |
227 found = false; | 237 found = false; |
228 | 238 |
239 boost::mutex::scoped_lock lock(context.GetDicomFileMutex()); | |
240 ParsedDicomFile& dicom = context.GetDicomFile(series["Instances"][0].asString()); | |
241 | |
229 for (Json::Value::ArrayIndex i = 0; i < content[ROI_CONTOUR_SEQUENCE]["Value"].size(); i++) | 242 for (Json::Value::ArrayIndex i = 0; i < content[ROI_CONTOUR_SEQUENCE]["Value"].size(); i++) |
230 { | 243 { |
231 if (content[ROI_CONTOUR_SEQUENCE]["Value"][i].isMember(REFERENCED_ROI_NUMBER) && | 244 const Json::Value& contour = content[ROI_CONTOUR_SEQUENCE]["Value"][i]; |
232 content[ROI_CONTOUR_SEQUENCE]["Value"][i].isMember(ROI_DISPLAY_COLOR) && | 245 |
233 content[ROI_CONTOUR_SEQUENCE]["Value"][i][REFERENCED_ROI_NUMBER]["Value"].asString() == call.GetUriComponent("roi", "")) | 246 if (contour.isMember(REFERENCED_ROI_NUMBER) && |
247 contour.isMember(ROI_DISPLAY_COLOR) && | |
248 contour.isMember(CONTOUR_SEQUENCE) && | |
249 contour[REFERENCED_ROI_NUMBER]["Value"].asString() == call.GetUriComponent("roi", "")) | |
234 { | 250 { |
235 result["DisplayColor"] = content[ROI_CONTOUR_SEQUENCE]["Value"][i][ROI_DISPLAY_COLOR]["Value"].asString(); | 251 std::vector<std::string> color; |
252 Toolbox::Split(color, contour[ROI_DISPLAY_COLOR]["Value"].asString(), '\\'); | |
253 | |
254 result["Points"] = Json::objectValue; | |
255 result["ClosedPlanar"] = Json::objectValue; | |
256 result["DisplayColor"] = Json::arrayValue; | |
257 for (size_t k = 0; k < color.size(); k++) | |
258 { | |
259 result["DisplayColor"].append(boost::lexical_cast<int>(color[k])); | |
260 } | |
261 | |
262 for (Json::Value::ArrayIndex j = 0; j < contour[CONTOUR_SEQUENCE]["Value"].size(); j++) | |
263 { | |
264 const Json::Value& contourSequence = contour[CONTOUR_SEQUENCE]["Value"][j]; | |
265 | |
266 if (contourSequence.isMember(CONTOUR_IMAGE_SEQUENCE) && | |
267 contourSequence.isMember(CONTOUR_GEOMETRIC_TYPE) && | |
268 contourSequence.isMember(NUMBER_OF_CONTOUR_POINTS) && | |
269 contourSequence.isMember(CONTOUR_DATA) && | |
270 contourSequence[CONTOUR_IMAGE_SEQUENCE]["Value"].size() == 1 && | |
271 contourSequence[CONTOUR_IMAGE_SEQUENCE]["Value"][0].isMember(REFERENCED_SOP_INSTANCE_UID)) | |
272 { | |
273 const std::string type = contourSequence[CONTOUR_GEOMETRIC_TYPE]["Value"].asString(); | |
274 if (type != "POINT" && type != "CLOSED_PLANAR") | |
275 { | |
276 continue; | |
277 } | |
278 | |
279 const std::string uid = (contourSequence[CONTOUR_IMAGE_SEQUENCE]["Value"][0] | |
280 [REFERENCED_SOP_INSTANCE_UID]["Value"].asString()); | |
281 | |
282 std::list<std::string> instance; | |
283 context.GetIndex().LookupTagValue(instance, DICOM_TAG_SOP_INSTANCE_UID, uid); | |
284 if (instance.size() != 1) | |
285 { | |
286 continue; | |
287 } | |
288 | |
289 unsigned int countPoints = boost::lexical_cast<unsigned int> | |
290 (contourSequence[NUMBER_OF_CONTOUR_POINTS]["Value"].asString()); | |
291 if (countPoints <= 0) | |
292 { | |
293 continue; | |
294 } | |
295 | |
296 ParsedDicomFile::SequencePath path; | |
297 path.push_back(std::make_pair(DicomTag(0x3006, 0x0039 /* ROIContourSequence */), i)); | |
298 path.push_back(std::make_pair(DicomTag(0x3006, 0x0040 /* ContourSequence */), j)); | |
299 | |
300 std::string contourData; | |
301 dicom.GetTagValue(contourData, path, DicomTag(0x3006, 0x0050 /* ContourData */)); | |
302 | |
303 std::vector<std::string> points; | |
304 Toolbox::Split(points, contourData, '\\'); | |
305 | |
306 Json::Value* target; | |
307 Json::Value item = Json::arrayValue; | |
308 | |
309 if (type == "POINT" && | |
310 countPoints == 1 && | |
311 points.size() == 3) | |
312 { | |
313 target = &result["Points"]; | |
314 item.append(boost::lexical_cast<float>(points[0])); | |
315 item.append(boost::lexical_cast<float>(points[1])); | |
316 item.append(boost::lexical_cast<float>(points[2])); | |
317 } | |
318 else if (type == "CLOSED_PLANAR" && | |
319 points.size() == 3 * countPoints) | |
320 { | |
321 target = &result["ClosedPlanar"]; | |
322 for (size_t k = 0; k < countPoints; k++) | |
323 { | |
324 Json::Value p = Json::arrayValue; | |
325 p.append(boost::lexical_cast<float>(points[3 * k])); | |
326 p.append(boost::lexical_cast<float>(points[3 * k + 1])); | |
327 p.append(boost::lexical_cast<float>(points[3 * k + 2])); | |
328 item.append(p); | |
329 } | |
330 } | |
331 else | |
332 { | |
333 continue; | |
334 } | |
335 | |
336 if (!target->isMember(instance.front())) | |
337 { | |
338 (*target) [instance.front()] = Json::arrayValue; | |
339 } | |
340 | |
341 (*target) [instance.front()].append(item); | |
342 } | |
343 } | |
344 | |
236 found = true; | 345 found = true; |
237 } | 346 } |
238 } | 347 } |
239 | 348 |
240 if (found) | 349 if (found) |