Mercurial > hg > orthanc
diff 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 |
line wrap: on
line diff
--- a/OrthancServer/RadiotherapyRestApi.cpp Thu Aug 29 17:59:09 2013 +0200 +++ b/OrthancServer/RadiotherapyRestApi.cpp Fri Aug 30 16:09:19 2013 +0200 @@ -40,6 +40,8 @@ ServerContext& context = contextApi.GetContext() +// DICOM tags for RT-STRUCT + #define REFERENCED_STUDY_SEQUENCE "0008,1110" #define REFERENCED_SOP_INSTANCE_UID "0008,1155" #define FRAME_OF_REFERENCE_UID "0020,0052" @@ -51,6 +53,12 @@ #define ROI_CONTOUR_SEQUENCE "3006,0039" #define REFERENCED_ROI_NUMBER "3006,0084" #define ROI_DISPLAY_COLOR "3006,002a" +#define CONTOUR_SEQUENCE "3006,0040" +#define CONTOUR_IMAGE_SEQUENCE "3006,0016" +#define CONTOUR_GEOMETRIC_TYPE "3006,0042" +#define NUMBER_OF_CONTOUR_POINTS "3006,0046" +#define CONTOUR_DATA "3006,0050" + namespace Orthanc { @@ -208,13 +216,15 @@ bool found = false; for (Json::Value::ArrayIndex i = 0; i < content[STRUCTURE_SET_ROI_SEQUENCE]["Value"].size(); i++) { - if (content[STRUCTURE_SET_ROI_SEQUENCE]["Value"][i].isMember(ROI_NUMBER) && - content[STRUCTURE_SET_ROI_SEQUENCE]["Value"][i].isMember(ROI_NAME) && - content[STRUCTURE_SET_ROI_SEQUENCE]["Value"][i][ROI_NUMBER]["Value"].asString() == call.GetUriComponent("roi", "")) + const Json::Value& roi = content[STRUCTURE_SET_ROI_SEQUENCE]["Value"][i]; + + if (roi.isMember(ROI_NUMBER) && + roi.isMember(ROI_NAME) && + roi[ROI_NUMBER]["Value"].asString() == call.GetUriComponent("roi", "")) { result["Number"] = call.GetUriComponent("roi", ""); - result["Name"] = content[STRUCTURE_SET_ROI_SEQUENCE]["Value"][i][ROI_NAME]["Value"].asString(); - result["GenerationAlgorithm"] = content[STRUCTURE_SET_ROI_SEQUENCE]["Value"][i][ROI_GENERATION_ALGORITHM]["Value"].asString(); + result["Name"] = roi[ROI_NAME]["Value"].asString(); + result["GenerationAlgorithm"] = roi[ROI_GENERATION_ALGORITHM]["Value"].asString(); found = true; } } @@ -226,13 +236,112 @@ found = false; + boost::mutex::scoped_lock lock(context.GetDicomFileMutex()); + ParsedDicomFile& dicom = context.GetDicomFile(series["Instances"][0].asString()); + for (Json::Value::ArrayIndex i = 0; i < content[ROI_CONTOUR_SEQUENCE]["Value"].size(); i++) { - if (content[ROI_CONTOUR_SEQUENCE]["Value"][i].isMember(REFERENCED_ROI_NUMBER) && - content[ROI_CONTOUR_SEQUENCE]["Value"][i].isMember(ROI_DISPLAY_COLOR) && - content[ROI_CONTOUR_SEQUENCE]["Value"][i][REFERENCED_ROI_NUMBER]["Value"].asString() == call.GetUriComponent("roi", "")) + const Json::Value& contour = content[ROI_CONTOUR_SEQUENCE]["Value"][i]; + + if (contour.isMember(REFERENCED_ROI_NUMBER) && + contour.isMember(ROI_DISPLAY_COLOR) && + contour.isMember(CONTOUR_SEQUENCE) && + contour[REFERENCED_ROI_NUMBER]["Value"].asString() == call.GetUriComponent("roi", "")) { - result["DisplayColor"] = content[ROI_CONTOUR_SEQUENCE]["Value"][i][ROI_DISPLAY_COLOR]["Value"].asString(); + std::vector<std::string> color; + Toolbox::Split(color, contour[ROI_DISPLAY_COLOR]["Value"].asString(), '\\'); + + result["Points"] = Json::objectValue; + result["ClosedPlanar"] = Json::objectValue; + result["DisplayColor"] = Json::arrayValue; + for (size_t k = 0; k < color.size(); k++) + { + result["DisplayColor"].append(boost::lexical_cast<int>(color[k])); + } + + for (Json::Value::ArrayIndex j = 0; j < contour[CONTOUR_SEQUENCE]["Value"].size(); j++) + { + const Json::Value& contourSequence = contour[CONTOUR_SEQUENCE]["Value"][j]; + + if (contourSequence.isMember(CONTOUR_IMAGE_SEQUENCE) && + contourSequence.isMember(CONTOUR_GEOMETRIC_TYPE) && + contourSequence.isMember(NUMBER_OF_CONTOUR_POINTS) && + contourSequence.isMember(CONTOUR_DATA) && + contourSequence[CONTOUR_IMAGE_SEQUENCE]["Value"].size() == 1 && + contourSequence[CONTOUR_IMAGE_SEQUENCE]["Value"][0].isMember(REFERENCED_SOP_INSTANCE_UID)) + { + const std::string type = contourSequence[CONTOUR_GEOMETRIC_TYPE]["Value"].asString(); + if (type != "POINT" && type != "CLOSED_PLANAR") + { + continue; + } + + const std::string uid = (contourSequence[CONTOUR_IMAGE_SEQUENCE]["Value"][0] + [REFERENCED_SOP_INSTANCE_UID]["Value"].asString()); + + std::list<std::string> instance; + context.GetIndex().LookupTagValue(instance, DICOM_TAG_SOP_INSTANCE_UID, uid); + if (instance.size() != 1) + { + continue; + } + + unsigned int countPoints = boost::lexical_cast<unsigned int> + (contourSequence[NUMBER_OF_CONTOUR_POINTS]["Value"].asString()); + if (countPoints <= 0) + { + continue; + } + + ParsedDicomFile::SequencePath path; + path.push_back(std::make_pair(DicomTag(0x3006, 0x0039 /* ROIContourSequence */), i)); + path.push_back(std::make_pair(DicomTag(0x3006, 0x0040 /* ContourSequence */), j)); + + std::string contourData; + dicom.GetTagValue(contourData, path, DicomTag(0x3006, 0x0050 /* ContourData */)); + + std::vector<std::string> points; + Toolbox::Split(points, contourData, '\\'); + + Json::Value* target; + Json::Value item = Json::arrayValue; + + if (type == "POINT" && + countPoints == 1 && + points.size() == 3) + { + target = &result["Points"]; + item.append(boost::lexical_cast<float>(points[0])); + item.append(boost::lexical_cast<float>(points[1])); + item.append(boost::lexical_cast<float>(points[2])); + } + else if (type == "CLOSED_PLANAR" && + points.size() == 3 * countPoints) + { + target = &result["ClosedPlanar"]; + for (size_t k = 0; k < countPoints; k++) + { + Json::Value p = Json::arrayValue; + p.append(boost::lexical_cast<float>(points[3 * k])); + p.append(boost::lexical_cast<float>(points[3 * k + 1])); + p.append(boost::lexical_cast<float>(points[3 * k + 2])); + item.append(p); + } + } + else + { + continue; + } + + if (!target->isMember(instance.front())) + { + (*target) [instance.front()] = Json::arrayValue; + } + + (*target) [instance.front()].append(item); + } + } + found = true; } }