Skip to content

Instantly share code, notes, and snippets.

@fedorov
Created August 12, 2017 19:58
Show Gist options
  • Select an option

  • Save fedorov/41e42c1e701d74b2391792241809fe62 to your computer and use it in GitHub Desktop.

Select an option

Save fedorov/41e42c1e701d74b2391792241809fe62 to your computer and use it in GitHub Desktop.
Sample program reading an SR document based on TID 1500 and printing details on the measurements
/*
* Sample program reading an SR document based on TID 1500 and printing details on the measurements
*
* Author: J. Riesmeier, Oldenburg, Germany
*
*/
#include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */
#include "dcmtk/dcmsr/dsrdoc.h"
#include "dcmtk/dcmsr/dsrcodtn.h"
#include "dcmtk/dcmsr/dsrimgtn.h"
#include "dcmtk/dcmsr/dsrnumtn.h"
#include "dcmtk/dcmsr/dsrtextn.h"
#include "dcmtk/dcmsr/dsruidtn.h"
#include "dcmtk/dcmsr/codes/dcm.h"
#include "dcmtk/dcmsr/codes/ncit.h"
#include "dcmtk/dcmsr/codes/srt.h"
#include "dcmtk/dcmsr/codes/umls.h"
#include <dcmtk/dcmsr/dsruidtn.h>
#include "dcmtk/dcmdata/dcfilefo.h"
class TID1500_Reader
: DSRDocumentTree
{
public:
TID1500_Reader(const DSRDocumentTree &tree)
: DSRDocumentTree(tree)
{
/* check for expected template identification */
if (!compareTemplateIdentification("1500", "DCMR"))
CERR << "warning: template identification \"TID 1500 (DCMR)\" not found" << OFendl;
}
OFCondition getMeasurements()
{
OFCondition status = SR_EC_InvalidDocumentTree;
/* iterate over the document tree and print the measurements */
if (gotoNamedChildNode(CODE_DCM_ImagingMeasurements))
{
if (gotoNamedChildNode(CODE_DCM_MeasurementGroup))
{
do {
COUT << "Measurement Group:" << OFendl;
/* remember cursor to current content item (as a starting point) */
const DSRDocumentTreeNodeCursor groupCursor(getCursor());
/* print some general information */
printContentItem(CODE_NCIt_ActivitySession, groupCursor);
printContentItem(CODE_UMLS_TimePoint, groupCursor);
printContentItem(CODE_SRT_MeasurementMethod, groupCursor);
printContentItem(CODE_DCM_ReferencedSegment, groupCursor);
printContentItem(CODE_DCM_SourceSeriesForSegmentation, groupCursor);
printContentItem(CODE_DCM_TrackingIdentifier, groupCursor);
printContentItem(CODE_DCM_TrackingUniqueIdentifier, groupCursor);
printContentItem(CODE_DCM_Finding, groupCursor);
printContentItem(CODE_SRT_FindingSite, groupCursor);
/* print details on measurement value(s) */
DSRDocumentTreeNodeCursor cursor(groupCursor);
if (cursor.gotoChild())
{
size_t counter = 0;
COUT << "- Measurements:" << OFendl;
/* iterate over all direct child nodes */
do {
const DSRDocumentTreeNode *node = cursor.getNode();
/* and check for numeric measurement value content items */
if ((node != NULL) && (node->getValueType() == VT_Num))
{
COUT << " #" << (++counter) << " ";
printMeasurement(*OFstatic_cast(const DSRNumTreeNode *, node), cursor);
}
} while (cursor.gotoNext());
}
} while (gotoNextNamedNode(CODE_DCM_MeasurementGroup));
status = EC_Normal;
}
}
return status;
}
void printContentItem(const DSRCodedEntryValue &conceptName,
DSRDocumentTreeNodeCursor cursor)
{
/* try to go to the given content item */
if (gotoNamedChildNode(conceptName, cursor))
{
const DSRDocumentTreeNode *node = cursor.getNode();
if (node != NULL)
{
COUT << "- " << conceptName.getCodeMeaning() << ": ";
/* use appropriate value for output */
switch (node->getValueType())
{
case VT_Text:
COUT << OFstatic_cast(const DSRTextTreeNode *, node)->getValue();
break;
case VT_UIDRef:
COUT << OFstatic_cast(const DSRUIDRefTreeNode *, node)->getValue();
break;
case VT_Code:
COUT << OFstatic_cast(const DSRCodeTreeNode *, node)->getValue().getCodeMeaning();
break;
case VT_Image:
COUT << OFstatic_cast(const DSRImageTreeNode *, node)->getValue().getSOPInstanceUID();
break;
default:
COUT << "n/a";
}
COUT << OFendl;
}
}
}
void printMeasurement(const DSRNumTreeNode &numNode,
DSRDocumentTreeNodeCursor cursor)
{
COUT << numNode.getConceptName().getCodeMeaning() << ": " << numNode.getValue().getNumericValue() << " " << numNode.getValue().getMeasurementUnit().getCodeMeaning() << OFendl;
/* check for any modifiers */
if (cursor.gotoChild())
{
/* iterate over all direct child nodes */
do {
const DSRDocumentTreeNode *node = cursor.getNode();
if (node != NULL)
{
/* and check for "has concept mod CODE" content items */
if ((node->getRelationshipType() == RT_hasConceptMod) && (node->getValueType() == VT_Code))
{
/* of course, we could also filter on concept name (if needed) */
COUT << " - " << node->getConceptName().getCodeMeaning() << ": " << OFstatic_cast(const DSRCodeTreeNode *, node)->getCodeMeaning() << OFendl;
}
/* as well as "inferred from NUM" content items */
else if ((node->getRelationshipType() == RT_inferredFrom) && (node->getValueType() == VT_Num))
{
COUT << " - " << node->getConceptName().getCodeMeaning() << ": " << OFstatic_cast(const DSRNumTreeNode *, node)->getNumericValue()
<< " " << OFstatic_cast(const DSRNumTreeNode *, node)->getValue().getMeasurementUnit().getCodeMeaning() << OFendl;
}
}
} while (cursor.gotoNext());
}
}
using DSRDocumentTree::gotoNamedChildNode;
protected:
size_t gotoNamedChildNode(const DSRCodedEntryValue &conceptName,
DSRDocumentTreeNodeCursor &cursor)
{
size_t nodeID = 0;
/* goto the first child node */
if (conceptName.isValid() && cursor.gotoChild())
{
const DSRDocumentTreeNode *node;
/* iterate over all nodes on this level */
do {
node = cursor.getNode();
/* and check for the desired concept name */
if ((node != NULL) && (node->getConceptName() == conceptName))
nodeID = node->getNodeID();
} while ((nodeID == 0) && cursor.gotoNext());
}
return nodeID;
}
};
int main(int argc, char *argv[])
{
int result = 0;
/* check number of command line parameters */
if (argc >= 2)
{
const char *filename = argv[1];
DcmFileFormat fileformat;
/* first, load the DICOM file */
COUT << "Filename: " << filename << OFendl;
OFCondition status = fileformat.loadFile(filename);
if (status.good())
{
DSRDocument document;
DcmDataset &dataset = *fileformat.getDataset();
/* then, read the SR document from the DICOM dataset */
status = document.read(dataset);
if (status.good())
{
TID1500_Reader reader(document.getTree());
/* and, finally, get the measurements from the SR document */
status = reader.getMeasurements();
if (status.bad())
{
CERR << "error: cannot get Measurements from DICOM SR document: " << status.text() << OFendl;
result = 4;
}
} else {
CERR << "error: cannot read DICOM SR document: " << status.text() << OFendl;
result = 3;
}
} else {
CERR << "error: cannot load DICOM file: " << status.text() << OFendl;
result = 2;
}
} else {
CERR << "error: no input filename specified" << OFendl;
result = 1;
}
return result;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment