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)