⚠️ Este é um site de tradução não oficial, sem relação com o DCMTK / OFFIS. Para informações oficiais, consulte a página original (https://support.dcmtk.org/docs/mod_dcmsr.html).

dcmsr: uma biblioteca de relatórios estruturados e aplicativos utilitários

Este módulo contém classes para ler, escrever, criar, modificar, acessar, imprimir e renderizar documentos DICOM de relatório estruturado (SR). A lista de classes SOP com suporte é fornecida em DSRTypes::E_DocumentType.

As principais classes de interface são:

Aqui estão mais algumas classes úteis para implementar templates SR:

Atualmente, os seguintes templates SR estão implementados (consulte as notas para mais detalhes):

Ferramentas

Este módulo contém as seguintes ferramentas de linha de comando:

Exemplos

O exemplo a seguir mostra como carregar um relatório estruturado DICOM e renderizar seu conteúdo em formato HTML:

DcmFileFormat fileformat;
OFCondition status = fileformat.loadFile("test.dcm");
if (status.good())
{
 DSRDocument document;
  status = document.read(*fileformat.getDataset());
 if (status.good())
  {
    status = document.renderHTML(cout);
 if (status.bad())
      cerr << "Error: cannot render SR document (" << status.text() << ")" << endl;
  } else
    cerr << "Error: cannot read SR document (" << status.text() << ")" << endl;
} else
  cerr << "Error: cannot load DICOM file (" << status.text() << ")" << endl;

O exemplo a seguir mostra como criar um relatório estruturado DICOM e salvá-lo em um arquivo (mais detalhes podem ser encontrados no arquivo-fonte mkreport):

DSRDocument document;
document.setPatientName("Doe^John");
/* ... */
DSRDocumentTree &tree = document.getTree();
tree.addContentItem(DSRTypes::RT_isRoot, DSRTypes::VT_Container);
tree.getCurrentContentItem().setConceptName(DSRCodedEntryValue(/* some code */));
tree.addChildContentItem(DSRTypes::RT_hasObsContext, DSRTypes::VT_Code, CODE_DCM_ObserverType);
tree.getCurrentContentItem().setCodeValue(CODE_DCM_Person);
/* ... */
DcmFileFormat fileformat;
OFCondition status = document.write(*fileformat.getDataset())
if (status.good())
{
  status = fileformat.saveFile("test.dcm", EXS_LittleEndianExplicit);
 if (status.bad())
    cerr << "Error: cannot save DICOM file (" << status.text() << ")" << endl;
} else
  cerr << "Error: cannot write SR document (" << status.text() << ")" << endl;

Como alternativa, muitas propriedades da árvore do documento podem ser acessadas e modificadas diretamente, como mostra o exemplo a seguir:

DSRDocument document(DSRTypes::DT_KeyObjectSelectionDocument);
/* ... */
DSRDocumentTree &tree = document.getTree();
tree.addContentItem(DSRTypes::RT_isRoot, DSRTypes::VT_Container);
DSRCodedEntryValue *codePtr = tree.getCurrentContentItem().getConceptNamePtr();
if (codePtr != NULL)
  codePtr->setCode("113000", "DCM", "Of Interest");
/* ... */
tree.addContentItem(DSRTypes::RT_contains, DSRTypes::VT_Image);
DSRImageReferenceValue *imagePtr = tree.getCurrentContentItem().getImageReferencePtr();
if (imagePtr != NULL)
{
  imagePtr->setValue(DSRImageReferenceValue(UID_UltrasoundMultiframeImageStorage, /* image UID */));
  imagePtr->setPresentationState(DSRCompositeReferenceValue(UID_GrayscaleSoftcopyPresentationStateStorage, /* GSPS UID */));
  imagePtr->getFrameList().addItem(2);
  imagePtr->getFrameList().addItem(5);
}
/* ... */

Além disso, existem métodos específicos DSRDocumentTree::addContentItem() e DSRDocumentTree::addChildContentItem() que esperam um ponteiro para uma instância recém-criada de DSRDocumentTreeNode.

Percorrer uma árvore de documento e buscar itens de conteúdo que atendam a determinados critérios pode ser feito de várias maneiras. Aqui estão duas delas:

DSRDocument document;
/* ... */
DSRDocumentTree &tree = document.getTree();
/* #1: search for content items with a certain concept name */
if (tree.gotoNamedNode(CODE_DCM_ProcedureReported))
{
 do {
 const DSRDocumentTreeNode *node = tree.getNode();
 /* and check for expected value type */
 if ((node != NULL) && (node->getValueType() == DSRTypes::VT_Code))
    {
 /* do something useful with the CODE content item */
    }
  } while (tree.gotoNextNamedNode(CODE_DCM_ProcedureReported, OFFalse /*searchIntoSub*/));
}
/* #2: search for content items using a more complex filter */
DSRDocumentTreeNodeAndFilter filter;
filter.addFilter(new DSRDocumentTreeNodeValueTypeFilter(DSRTypes::VT_Code));
filter.addFilter(new DSRDocumentTreeNodeRelationshipTypeFilter(DSRTypes::RT_hasConceptMod));
filter.addFilter(new DSRDocumentTreeNodeHasChildrenFilter());
if (tree.gotoMatchingNode(filter))
{
 /* found first "has concept mod CODE" content item that has children */
}

O último exemplo mostra como lidar com templates SR, por exemplo, ao criar um relatório estruturado DICOM baseado no TID 1500 (Measurement Report):

TID1500_MeasurementReport report(CMR_CID7021::ImagingMeasurementReport);
report.setLanguage(CID5000_Language::English);
report.getObservationContext().addPersonObserver("Doe^Jane", "Some Organization");
/* ... */
CMR_TID1411_in_TID1500 &volumetric = report.getVolumetricROIMeasurements();
volumetric.setActivitySession("1");
volumetric.setTrackingIdentifier("aorta reference region");
/* ... */
CMR_TID1419_in_TID1411_in_TID1500 &measurement = volumetric.getMeasurement();
measurement.createNewMeasurement(CMR_CID7469::Volume, CMR_TID1419_in_TID1411_in_TID1500::MeasurementValue("15", CMR_CID7181::CubicMillimeter));
measurement.setDerivation(CMR_CID7464::StandardDeviation);
/* ... */
DSRDocument document;
document.setPatientName("Last Name^First Name");
/* ... */
if (document.setTreeFromRootTemplate(report).good())
  document.print(cout, DSRTypes::PF_printTemplateIdentification);
else
  cerr << "Error: cannot set template content as document tree" << endl;