Creating MammographyCADSR file

All other questions regarding DCMTK

Moderator: Moderator Team

Message
Author
Jörg Riesmeier
ICSMED DICOM Services
ICSMED DICOM Services
Posts: 2217
Joined: Fri, 2004-10-29, 21:38
Location: Oldenburg, Germany

#16 Post by Jörg Riesmeier »

I have to insert all image tags in the CAD SR file (including Image View, Patient Orientation, Pixel Spacings...) in order to make it fully compatible with coresponding image;
No, but you also have to add the referenced SOP instances (e.g. images) to the Current Requested Procedure Evidence Sequence or to the Pertinent Other Evidence Sequence (see "mkreport.cc" for examples).
From the XML file corresponding to the original R2 produced CAD SR, the images seem to have been assigned an internal conventional ID (the first one is "5", then "16/27/38") which doesn't appear in the dsrdump.
You are correct, the numbers (IDs) used in the XML file are internal identifiers. DICOM uses another way of identifying and referencing content items: The root node is called "1", the first child is called "1.1", the second child "1.2" and so on. See DICOM standard for details ... Btw, did you ever try the dsrdump option +Pn (--number-nested-items)?

zappy1
Posts: 28
Joined: Fri, 2008-06-27, 11:27

#17 Post by zappy1 »

Jörg Riesmeier wrote:
I have to insert all image tags in the CAD SR file (including Image View, Patient Orientation, Pixel Spacings...) in order to make it fully compatible with coresponding image;
No, but you also have to add the referenced SOP instances (e.g. images) to the Current Requested Procedure Evidence Sequence or to the Pertinent Other Evidence Sequence (see "mkreport.cc" for examples).
I already did that for the part concerning the assigning of an UID to the IMAGE entry in the SR:

Code: Select all

doc->getTree().addContentItem(DSRTypes::RT_contains, DSRTypes::VT_Image, DSRTypes::AM_belowCurrent);   
doc->getCurrentRequestedProcedureEvidence().addItem(studyID, seriesInstanceUID, UID_DigitalMammographyXRayImageStorageForProcessing, actualSOPInstanceUID);
doc->getTree().getCurrentContentItem().setImageReference(DSRImageReferenceValue(UID_DigitalMammographyXRayImageStorageForProcessing, actualSOPInstanceUID));
where the last line is inspired from

Code: Select all

doc->getTree().getCurrentContentItem().setImageReference(DSRImageReferenceValue("0", "0"));
.

But I still have to add the reference to these values in the SCOORD structure and in the file mkreport.cc there is no hint how to do that (the only thing vaguely pointing to something like an internal reference are the lines of the type doc->getTree().addByReferenceRelationship(DSRTypes::RT_inferredFrom, node1);, but they seem of little relevance here).
From the XML file corresponding to the original R2 produced CAD SR, the images seem to have been assigned an internal conventional ID (the first one is "5", then "16/27/38") which doesn't appear in the dsrdump.
You are correct, the numbers (IDs) used in the XML file are internal identifiers. DICOM uses another way of identifying and referencing content items: The root node is called "1", the first child is called "1.1", the second child "1.2" and so on. See DICOM standard for details ... Btw, did you ever try the dsrdump option +Pn (--number-nested-items)?
Yes, I knew about the standard DICOM way of item referencing. The option +Pn applied for the dsrdump of my file outputs:

Code: Select all

Mammography CAD SR Document

Patient            : SBI2007^Scenario 6 (F, 19010101, #SBIPT008)
Completion Flag    : PARTIAL
Verification Flag  : UNVERIFIED
Content Date/Time  : 20080715 142628

1  <CONTAINER:(,,"Mammography CAD Report")=SEPARATE>
1.1  <has concept mod CODE:(,,"Language of Content Item and Descendants")=(eng,ISO639_2,"English")>
1.1.1  <has concept mod CODE:(,,"Country of Language")=(US,ISO3166_1,"UNITED STATES")>
1.2  <contains CONTAINER:(,,"Image library")=SEPARATE>
1.2.1  <contains IMAGE:=(DPm image,)>
1.2.1.1  <has acq context CODE:(,,"Image Laterality")=(T-04030,SNM3,"Left breast")>
1.3  <contains CODE:(,,"CAD Processing and Findings Summary")=(111242,DCM,"All algorithms succeeded; with findings")>
1.3.1  <inferred from CONTAINER:(,,"Individual Impression/Recommendation")=SEPARATE>
1.3.1.1  <has concept mod CODE:(,,"Rendering Intent")=(111150,DCM,"Presentation Required: Rendering device is expected to present")>
1.3.1.2  <contains CODE:(,,"Single Image Finding")=(F-01796,SRT[1.1],"Mammography breast density")>
1.3.1.2.1  <has concept mod CODE:(,,"Rendering Intent")=(111150,DCM,"Presentation Required: Rendering device is expected to present")>
1.3.1.2.2  <has properties TEXT:(,,"Algorithm Name")="My_CAD">
1.3.1.2.3  <has properties TEXT:(,,"Algorithm Version")="1.0.0">
1.3.1.2.4  <has properties TEXT:(,,"Algorithm Parameters")="none">
1.3.1.2.5  <has properties SCOORD:(,,"SCoord Code")=(POINT,2200/3000)>
structure agreeing with the sample ones [still, the internal reference doesn't show up in the dumps of the latter].

Jörg Riesmeier
ICSMED DICOM Services
ICSMED DICOM Services
Posts: 2217
Joined: Fri, 2004-10-29, 21:38
Location: Oldenburg, Germany

#18 Post by Jörg Riesmeier »

But I still have to add the reference to these values in the SCOORD structure
Reading the standard (especially part 16) again helps: Usually, the reference from the SCOORD content item to the IMAGE content item is specified by an R-SELECTED FROM relationship (i.e. a by-reference relationship).

Something like:

Code: Select all

 doc->getTree().addByReferenceRelationship(DSRTypes::RT_selectedFrom, nodeID /* ID of the target node */);
The internal node ID is returned by addContentItem(), i.e. you have to store this value of the target node (e.g. the IMAGE you want to reference).

zappy1
Posts: 28
Joined: Fri, 2008-06-27, 11:27

#19 Post by zappy1 »

Jörg Riesmeier wrote:Usually, the reference from the SCOORD content item to the IMAGE content item is specified by an R-SELECTED FROM relationship (i.e. a by-reference relationship).

Something like:

Code: Select all

 doc->getTree().addByReferenceRelationship(DSRTypes::RT_selectedFrom, nodeID /* ID of the target node */);
The internal node ID is returned by addContentItem(), i.e. you have to store this value of the target node (e.g. the IMAGE you want to reference).
This is probably the reason for which I had already wrote the code lines:

Code: Select all

size_t node_im = doc->getTree().addContentItem(DSRTypes::RT_contains, DSRTypes::VT_Image, DSRTypes::AM_belowCurrent); 
for the image, and

Code: Select all

 
doc->getTree().addByReferenceRelationship(DSRTypes::RT_selectedFrom, node_im);
for the SCOORD item. But the inserted reference doesn't show up. What am I doing wrong?!

Jörg Riesmeier
ICSMED DICOM Services
ICSMED DICOM Services
Posts: 2217
Joined: Fri, 2004-10-29, 21:38
Location: Oldenburg, Germany

#20 Post by Jörg Riesmeier »

Did you check what addByReferenceRelationship() returns?

zappy1
Posts: 28
Joined: Fri, 2008-06-27, 11:27

#21 Post by zappy1 »

Jörg Riesmeier wrote:Did you check what addByReferenceRelationship() returns?
Error code 0.

Jörg Riesmeier
ICSMED DICOM Services
ICSMED DICOM Services
Posts: 2217
Joined: Fri, 2004-10-29, 21:38
Location: Oldenburg, Germany

#22 Post by Jörg Riesmeier »

As you can read in the documentation:

Code: Select all

Returns:
ID of new pseudo-node if successful, 0 otherwise
That means, something went wrong. So, it's clear that the by-reference relationship is not shown in the dump :-)

Btw, are you using the current snapshot or the DCMTK release 3.5.4?

zappy1
Posts: 28
Joined: Fri, 2008-06-27, 11:27

#23 Post by zappy1 »

Jörg Riesmeier wrote:As you can read in the documentation:

Code: Select all

Returns:
ID of new pseudo-node if successful, 0 otherwise
That means, something went wrong. So, it's clear that the by-reference relationship is not shown in the dump :-)
Hadn't I read the documentation, I wouldn't have known "0" was the error code in this case. So I already had little doubt that something went wrong. Lemme quote myself for the essential point: "What am I doing wrong?!" :-)
Here's the surrounding code:

Code: Select all

doc->getTree().addContentItem(DSRTypes::RT_hasProperties, DSRTypes::VT_SCoord); 
doc->getTree().getCurrentContentItem().setConceptName(DSRCodedEntryValue("1234", "DCM", "SCoord Code")); 
DSRSpatialCoordinatesValue spatialCoord(DSRTypes::GT_Point); 
spatialCoord.getGraphicDataList().addItem(2200,3000);
doc->getTree().getCurrentContentItem().setSpatialCoordinates(spatialCoord);    
doc->getTree().addByReferenceRelationship(DSRTypes::RT_selectedFrom, node_im);
Btw, are you using the current snapshot or the DCMTK release 3.5.4?
3.5.4, compiled on Mandriva 2008.0/x64.

Regards,
Z.B.

Jörg Riesmeier
ICSMED DICOM Services
ICSMED DICOM Services
Posts: 2217
Joined: Fri, 2004-10-29, 21:38
Location: Oldenburg, Germany

#24 Post by Jörg Riesmeier »

I checked the by-reference relationship (SCCORD R-SELECTED FROM IMAGE) with the current snapshot, and it works :-) There were a couple of modifications to the "dcmsr" module, however, I cannot say by heart (or from the CHANGES file) if this is relevant to your problem. The best thing would probably be to test your program with the current snapshot ...

zappy1
Posts: 28
Joined: Fri, 2008-06-27, 11:27

#25 Post by zappy1 »

Jörg Riesmeier wrote:I checked the by-reference relationship (SCCORD R-SELECTED FROM IMAGE) with the current snapshot, and it works :-) There were a couple of modifications to the "dcmsr" module, however, I cannot say by heart (or from the CHANGES file) if this is relevant to your problem. The best thing would probably be to test your program with the current snapshot ...
Before updating the package, it would be interesting to point out that adding another image entry (in a wrong point of the tree!) triggers the correct attribution of the image reference "5" for the first image (the interesting one), and the correct reference tag in the SCOORD structure with return code "17" (I discovered that incidentally, when inserting the image between two doc->getTree().goUp(); in the code!). Indeed, the xml file exhibits the tag "<image id="5" >" and the required

Code: Select all

    <reference ref="5" >
      <relationship>SELECTED FROM</relationship>
    </reference>
in the SCOORD structure. Unfortunately, the obtained tree structure is wrong (that is: a "code" tree item is inserted after the two "image" entries instead of being on the same level with their "container" parent; normally it should be found after this node and not as its child entry), and consequently, the GUI does not plot the inserted CAD point. Inserting correctly the second image (with correct tree structure), makes disappear the first image id...
So it looks more like a tree-related issue. For the record, the current part of the code concerned looks like this:

Code: Select all

doc->getTree().addContentItem(DSRTypes::RT_contains, DSRTypes::VT_Container); // image library container
doc->getTree().getCurrentContentItem().setConceptName(DSRCodedEntryValue("111028", "DCM", "Image library"));

im_id[0] = doc->getTree().addContentItem(DSRTypes::RT_contains, DSRTypes::VT_Image, DSRTypes::AM_belowCurrent); // the first image
 
doc->getTree().getCurrentContentItem().setImageReference(DSRImageReferenceValue(UID_DigitalMammographyXRayImageStorageForProcessing, actualSOPInstanceUID[0]));
doc->getCurrentRequestedProcedureEvidence().addItem(studyID, seriesInstanceUID[0], UID_DigitalMammographyXRayImageStorageForProcessing, actualSOPInstanceUID[0]);
 [...]
im_id[1] = doc->getTree().addContentItem(DSRTypes::RT_contains, DSRTypes::VT_Image, DSRTypes::AM_afterCurrent); // the second image
doc->getTree().getCurrentContentItem().setImageReference(DSRImageReferenceValue(UID_DigitalMammographyXRayImageStorageForProcessing, seriesInstanceUID[1]));
doc->getCurrentRequestedProcedureEvidence().addItem(studyID, seriesInstanceUID[1], UID_DigitalMammographyXRayImageStorageForProcessing, seriesInstanceUID[1]);

doc->getTree().goUp();
// doc->getTree().goUp(); // commented for obtaining the wrong tree structure
//// inserting CAD findings general report
doc->getTree().addContentItem(DSRTypes::RT_contains, DSRTypes::VT_Code, DSRTypes::AM_belowCurrent);
doc->getTree().getCurrentContentItem().setConceptName(DSRCodedEntryValue("111017", "DCM", "CAD Processing and Findings Summary")); 
[...]
If you don't have any other idea, I will check with the new snapshot.

Regards,
Z.B.

Jörg Riesmeier
ICSMED DICOM Services
ICSMED DICOM Services
Posts: 2217
Joined: Fri, 2004-10-29, 21:38
Location: Oldenburg, Germany

#26 Post by Jörg Riesmeier »

General comment: the "dcmsr" module only checks the IOD constraints from part 3 (e.g. table A.35.5-2) and not (yet) the template constraints from part 16 -- also see my earlier posting on this topic.

zappy1
Posts: 28
Joined: Fri, 2008-06-27, 11:27

#27 Post by zappy1 »

Jörg Riesmeier wrote:General comment: the "dcmsr" module only checks the IOD constraints from part 3 (e.g. table A.35.5-2) and not (yet) the template constraints from part 16 [...].
It finally worked (but I still don't think the issue was related to the version of DCMTK I used). There is only one minor difference with respect to the previous version of my code, that is correct including of all four images in the SR "Image Library" container; out of that, I simplified some doc->getTree().goUp(); and AM_belowCurrent/AM_afterCurrent sequences. At the ontological level I'm somehow puzzled, but at the practical level I'm happy with the result. :-) From now on, I should supposedly have less reasons to bother you with questions on this issue.
:-)

Thank you again for your help.

Regards,
Z.B.

(P.S. I can post the minimal code if there are persons interested in it)

Jörg Riesmeier
ICSMED DICOM Services
ICSMED DICOM Services
Posts: 2217
Joined: Fri, 2004-10-29, 21:38
Location: Oldenburg, Germany

#28 Post by Jörg Riesmeier »

I can post the minimal code if there are persons interested in it
I guess this would be interesting to many people ... and I personally would also like to know what the reason for your original problem was :D

zappy1
Posts: 28
Joined: Fri, 2008-06-27, 11:27

#29 Post by zappy1 »

Jörg Riesmeier wrote:
I can post the minimal code if there are persons interested in it
I guess this would be interesting to many people ... and I personally would also like to know what the reason for your original problem was :D
I would like that, too. :-) For some other time, yet...

Anyway, this is the (almost) minimal code.

Code: Select all

#include <dcmtk/config/osconfig.h>
#include <dcmtk/ofstd/ofstd.h>
#include <dcmtk/dcmdata/dcuid.h>
#include <dcmtk/dcmdata/dcfilefo.h>
#include <dcmtk/dcmsr/dsrdoc.h>
#include <dcmtk/dcmsr/dsrtypes.h>
#include <dcmtk/dcmsr/dsrsoprf.h>
#include <dcmtk/dcmsr/dsrmamcc.h>
#include <dcmtk/dcmsr/dsrscovl.h>
#include <stdlib.h>
#include <strstream>
#include <stdio.h>
#include <string>
#include <iostream>
#include <math.h>

using std::iostream;
using std::ifstream;
using namespace std;


int main(int argc,char **argv) {
  char fnm[130];
  int hhh, i,j ,k,dix;
  size_t im_id[20];

  int cad_status;


  bool ex_ImageLaterality[20];

  DcmFileFormat fileformat;

  DcmFileFormat fform[20]; /// these are the dicom image files to be opened

  OFString patientsName, patientID, patientsBirthDate, patientsSex;
  OFString studyID, studyDate, studyTime;
  OFString seriesNumber[20], instanceNumber[20], seriesInstanceUID[20];
  OFString imageSOPClassUID[20], actualSOPInstanceUID[20];
  OFString imageLaterality[20];

  cad_status=1; /// this will mean CAD found smthg

  for (dix=0;dix<4;dix++) { /// there are four images

  sprintf(fnm,"%d",dix+1); /// filenames of the images are 1, 2, 3, 4...

  OFCondition status = fform[dix].loadFile(fnm);
  if (status.good())
  {
  //  OFString patientsName;
    if (fform[dix].getDataset()->findAndGetOFString(DCM_PatientsName, patientsName).good()) 
    {
       fform[dix].getDataset()->findAndGetOFString(DCM_StudyID,studyID);
      // fform[dix].getDataset()->findAndGetOFString(DCM_SeriesID,seriesID);
       fform[dix].getDataset()->findAndGetOFString(DCM_PatientID,patientID);
       fform[dix].getDataset()->findAndGetOFString(DcmTag(0x0010, 0x0030),patientsBirthDate, 0, false);
       fform[dix].getDataset()->findAndGetOFString(DCM_PatientsSex,patientsSex);
       fform[dix].getDataset()->findAndGetOFString(DCM_StudyDate,studyDate); /// not used!
       fform[dix].getDataset()->findAndGetOFString(DCM_StudyTime,studyTime); /// not used!
       fform[dix].getDataset()->findAndGetOFString(DCM_SeriesNumber,seriesNumber[dix]);
       fform[dix].getDataset()->findAndGetOFString(DCM_InstanceNumber,instanceNumber[dix]);
       fform[dix].getDataset()->findAndGetOFString(DCM_SeriesInstanceUID,seriesInstanceUID[dix]);
       fform[dix].getDataset()->findAndGetOFString(DCM_SOPClassUID,imageSOPClassUID[dix]);
       if (imageSOPClassUID[dix]=="1.2.840.10008.5.1.4.1.1.1.2.1") { /// the image is for processing
         fform[dix].getDataset()->findAndGetOFString(DCM_SOPInstanceUID, actualSOPInstanceUID[dix]);
       }
       else { /// the image is for presentation
         fform[dix].getDataset()->findAndGetOFString(DcmTag(0x0008, 0x1155),actualSOPInstanceUID[dix], 0, true);
       }

       //// image values
       if (fform[dix].getDataset()->findAndGetOFString(DcmTag(0x0020, 0x0062),imageLaterality[dix], 0, true)==EC_Normal) { 
         ex_ImageLaterality[dix]=true;
         cout << "img inst UID " << actualSOPInstanceUID[dix] << endl;
       }
       else ex_ImageLaterality[dix]=false;
    }
    else cerr << "Error: cannot access Patient's Name!" << endl;
  }
  else cerr << "Error: cannot read DICOM file (" << status.text() << ")" << endl;
  }

  
///////////////

  DSRDocument *doc = new DSRDocument();
  if (doc != NULL) {
    OFString studyUID_01;
    OFBool writeFile = OFTrue;
    doc->createNewDocument(DSRTypes::DT_MammographyCadSR);
    doc->getStudyInstanceUID(studyUID_01);
    doc->setStudyID(studyID);
    doc->setStudyDescription("Test Mammography CAD Reporting Template");
    doc->setSeriesDescription("My Dicom SR test");
    doc->setSeriesNumber(seriesNumber[0]);
    doc->setSpecificCharacterSetType(DSRTypes::CS_Latin1);
    doc->setPatientID(patientID);
    doc->setPatientsName(patientsName);
    doc->setPatientsBirthDate(patientsBirthDate);
    doc->setPatientsSex(patientsSex);

//////////
//// the next lines set on container's root node (with value, scheme, meaning)
    doc->getTree().addContentItem(DSRTypes::RT_isRoot, DSRTypes::VT_Container); /// this is node 1 (document root)
    doc->getTree().getCurrentContentItem().setTemplateIdentification("4000","DCMR");
    doc->getTree().getCurrentContentItem().setConceptName(DSRCodedEntryValue("111036", "DCM", "Mammography CAD Report"));


//// setting document language (EN_US)
    {
    doc->getTree().addContentItem(DSRTypes::RT_hasConceptMod, DSRTypes::VT_Code, DSRTypes::AM_belowCurrent);
    doc->getTree().getCurrentContentItem().setConceptName(DSRCodedEntryValue("121049", "DCM", "Language of Content Item and Descendants"));
    doc->getTree().getCurrentContentItem().setCodeValue(DSRCodedEntryValue("eng","ISO639_2","English"));
 
    doc->getTree().addContentItem(DSRTypes::RT_hasConceptMod, DSRTypes::VT_Code, DSRTypes::AM_belowCurrent); 
    doc->getTree().getCurrentContentItem().setConceptName(DSRCodedEntryValue("121046", "DCM", "Country of Language")); 
    doc->getTree().getCurrentContentItem().setCodeValue(DSRCodedEntryValue("US","ISO3166_1","UNITED STATES")); 

    doc->getTree().goUp();
    }
//// end setting document language (EN_US)


//// now inserting the images
{
    doc->getTree().addContentItem(DSRTypes::RT_contains, DSRTypes::VT_Container); /// this is node 1.2
    doc->getTree().getCurrentContentItem().setConceptName(DSRCodedEntryValue("111028", "DCM", "Image library"));

    for(dix=0;dix<4;dix++) { /// still 4 images to add...
    im_id[dix] = doc->getTree().addContentItem(DSRTypes::RT_contains, DSRTypes::VT_Image, DSRTypes::AM_belowCurrent); /// these are nodes 1.2.*
    cout << "im_id is " << im_id[dix] << endl;
    doc->getTree().getCurrentContentItem().setImageReference(DSRImageReferenceValue(UID_DigitalMammographyXRayImageStorageForProcessing, actualSOPInstanceUID[dix]));
    doc->getCurrentRequestedProcedureEvidence().addItem(studyID, seriesInstanceUID[dix], UID_DigitalMammographyXRayImageStorageForProcessing, actualSOPInstanceUID[dix]);

    if (ex_ImageLaterality[dix]) { /// this part concerns image laterality (R/L/Unknown)
       //cout << "Writing laterality\n";
       doc->getTree().addContentItem(DSRTypes::RT_hasAcqContext, DSRTypes::VT_Code, DSRTypes::AM_belowCurrent);
       doc->getTree().getCurrentContentItem().setConceptName(DSRCodedEntryValue("111027", "DCM", "Image Laterality"));
       if (imageLaterality[dix]=='R') doc->getTree().getCurrentContentItem().setCodeValue(DSRCodedEntryValue("T-04020","SNM3","Right breast")); 
       else if (imageLaterality[dix]=='L') doc->getTree().getCurrentContentItem().setCodeValue(DSRCodedEntryValue("T-04030","SNM3","Left breast"));
       else doc->getTree().getCurrentContentItem().setCodeValue(DSRCodedEntryValue("T-Rex","SNM3","Unknown breast"));
       doc->getTree().goUp();
    }
    doc->getTree().goUp();
    }
}
//// end inserting the images


//// inserting CAD findings general report
    doc->getTree().addContentItem(DSRTypes::RT_contains, DSRTypes::VT_Code, DSRTypes::AM_afterCurrent);
    doc->getTree().getCurrentContentItem().setConceptName(DSRCodedEntryValue("111017", "DCM", "CAD Processing and Findings Summary")); /// this is node 1.3
    switch (cad_status) { /// well, if there's really something in that image...
      case 0:
         doc->getTree().getCurrentContentItem().setCodeValue(DSRCodedEntryValue("111241","DCM","All algorithms succeeded; without findings"));
         break;
      case 1:
         doc->getTree().getCurrentContentItem().setCodeValue(DSRCodedEntryValue("111242","DCM","All algorithms succeeded; with findings"));
         break;
      default:
         doc->getTree().getCurrentContentItem().setCodeValue(DSRCodedEntryValue("111245","DCM","No algorithms succeeded; without findings"));
         break;
    }
    
//// inserting some findings
    doc->getTree().addContentItem(DSRTypes::RT_inferredFrom, DSRTypes::VT_Container, DSRTypes::AM_belowCurrent); /// this is node 1.3.1
    doc->getTree().getCurrentContentItem().setConceptName(DSRCodedEntryValue("111034", "DCM", "Individual Impression/Recommendation"));

    doc->getTree().addContentItem(DSRTypes::RT_hasConceptMod, DSRTypes::VT_Code, DSRTypes::AM_belowCurrent); /// this is node 1.3.1.1
    doc->getTree().getCurrentContentItem().setConceptName(DSRCodedEntryValue("111056", "DCM", "Rendering Intent"));
    doc->getTree().getCurrentContentItem().setCodeValue(DSRCodedEntryValue("111150","DCM","Presentation Required: Rendering device is expected to present"));

    doc->getTree().addContentItem(DSRTypes::RT_contains, DSRTypes::VT_Code, DSRTypes::AM_afterCurrent); /// this is node 1.3.1.2
    doc->getTree().getCurrentContentItem().setConceptName(DSRCodedEntryValue("111059", "DCM", "Single Image Finding"));
    doc->getTree().getCurrentContentItem().setCodeValue(DSRCodedEntryValue("F-01796","SRT", "1.1","Mammography breast density"));

    doc->getTree().addContentItem(DSRTypes::RT_hasConceptMod, DSRTypes::VT_Code, DSRTypes::AM_belowCurrent); /// this is node 1.3.1.2.1
    doc->getTree().getCurrentContentItem().setConceptName(DSRCodedEntryValue("111056", "DCM", "Rendering Intent"));
    doc->getTree().getCurrentContentItem().setCodeValue(DSRCodedEntryValue("111150","DCM","Presentation Required: Rendering device is expected to present"));

    { /// algorithm presentation
    doc->getTree().addContentItem(DSRTypes::RT_hasProperties, DSRTypes::VT_Text, DSRTypes::AM_afterCurrent);
    doc->getTree().getCurrentContentItem().setConceptName(DSRCodedEntryValue("111001", "DCM", "Algorithm Name"));
    doc->getTree().getCurrentContentItem().setStringValue("My_CAD");

    doc->getTree().addContentItem(DSRTypes::RT_hasProperties, DSRTypes::VT_Text, DSRTypes::AM_afterCurrent);
    doc->getTree().getCurrentContentItem().setConceptName(DSRCodedEntryValue("111003", "DCM", "Algorithm Version"));
    doc->getTree().getCurrentContentItem().setStringValue("1.0.0");

    doc->getTree().addContentItem(DSRTypes::RT_hasProperties, DSRTypes::VT_Text, DSRTypes::AM_afterCurrent);
    doc->getTree().getCurrentContentItem().setConceptName(DSRCodedEntryValue("111002", "DCM", "Algorithm Parameters"));
    doc->getTree().getCurrentContentItem().setStringValue("none");
    }

    { /// finally, adding the point...

    doc->getTree().addContentItem(DSRTypes::RT_hasProperties, DSRTypes::VT_SCoord); /// this is node 1.3.1.2.5
    cout << "added code " << doc->getTree().addByReferenceRelationship(DSRTypes::RT_selectedFrom, im_id[3]) << endl;
    doc->getTree().getCurrentContentItem().setConceptName(DSRCodedEntryValue("111010", "DCM", "Center")); 
    DSRSpatialCoordinatesValue spatialCoord(DSRTypes::GT_Point); 
    spatialCoord.getGraphicDataList().addItem(2200,3000);
    doc->getTree().getCurrentContentItem().setSpatialCoordinates(spatialCoord);
    }

    DcmFileFormat *newfileformat = new DcmFileFormat(); 
    OFCondition status = doc->write(*newfileformat->getDataset()); 

    status = newfileformat->saveFile("SRF", EXS_LittleEndianExplicit); 
    if (status.bad()) 
      cerr << "Can't save SR file";
    
  }
  else cout << "Something went REALLY wrong, you were not supposed to read this\n";

  k = 0;
  return k;
}
It compiles with the line

Code: Select all

g++ -DHAVE_CONFIG_H -Wno-deprecated -o sr_gen sr_gen.cpp  -ldcmsr -ldcmdata -lofstd -lpthread -lxml2 -lz
(of course, if saved as sr_gen.cpp). The output is the file SRF containing a microcalcification point for the 4-th image. At this moment it's really scratchy, but is still a fair startpoint.

zappy1
Posts: 28
Joined: Fri, 2008-06-27, 11:27

#30 Post by zappy1 »

Hello again,
Jörg Riesmeier wrote: Basically, there are two ways of adding and filling an SCOORD content item:

Code: Select all

 doc->getTree().addContentItem(DSRTypes::RT_hasProperties, DSRTypes::VT_SCoord);
 doc->getTree().getCurrentContentItem().setConceptName(DSRCodedEntryValue("1234", OFFIS_CODING_SCHEME_DESIGNATOR, "SCoord Code"));
 DSRSpatialCoordinatesValue *scoordPtr = doc->getTree().getCurrentContentItem().getSpatialCoordinatesPtr();
 if (scoordPtr != NULL)
 {
     scoordPtr->setGraphicType(DSRTypes::GT_Circle);
     scoordPtr->getGraphicDataList().addItem(0, 0);
     scoordPtr->getGraphicDataList().addItem(255, 255);
 }
[...]
Back on track with this one: I suppose the previous code should insert a circle in the CAD SR (I guess the first integer couple gives the center, while the second is a point pertaining to the circle). I used it for creating a SRF (correctly generated), then I visualized the result with JiveX. While the points and polylines have my intended shape, the inserted "circle" is shown by JiveX GUI as a line between the two points inserted with addItem(), result which is obviously not what I want to see.
My first question: is my guess (about the meaning of inserted coordinates) right?!
My second question:is this rendering a GUI related issue or I am still wrong with something in the SR?
For the record, the dsrdump of SRF has these meaningful lines:

Code: Select all

     <contains CODE:(,,"Single Image Finding")=(F-01796,SRT[1.1],"Mammography breast density")>
        <has concept mod CODE:(,,"Rendering Intent")=(111150,DCM,"Presentation Required: Rendering device is expected to present")>
        <has properties TEXT:(,,"Algorithm Name")="My_CAD">
        <has properties TEXT:(,,"Algorithm Version")="1.0.0">
        <has properties TEXT:(,,"Algorithm Parameters")="none">
        <has properties SCOORD:(,,"Outline")=(CIRCLE,1456/2210,...)>
          <selected from 1.2.3>
(obviously, I inserted different coordinates for the center and the point)
The same polyline is displayed by JiveX if inserting a GT_Ellipse instead of the circle (of course, the ellipse is given by the four vertices of the major and minor axis).

Thank you in advance for your answer.

Regards,
Z.B.

Post Reply

Who is online

Users browsing this forum: Bing [Bot], Google [Bot] and 1 guest