No announcement yet.

Convert DICOM SR to HL7 ORU

  • Filter
  • Time
  • Show
Clear All
new posts

  • Convert DICOM SR to HL7 ORU

    So, today I started out on what seemed something very simple and straightforward, but now I'm stuck. As the title says I'm trying to convert DICOM SR objects to HL7 ORU's. I have no problem creating the ORU's and mapping the simple stuff like patient id, acc number etc. But I'm stuck trying to get the actual report information out of the SR and into OBX segments. The problem is that the tag 0040, A730 (Content Sequence) contains multiple items and the number of items may vary. I don't know how to iterate over the items in this tag. In hl7 you can do something like `for each (seg in msg..SEG)` I guess I'm looking for an equivalent in DICOM. I have attached the channel I have so far and a sample SR object.

    My Mirth Connect version is

    Attached Files

  • #2
    Hi hintham,

    I developed this function (attached) for data extraction from DICOM SR files. Unfortunately not all DICOMSR have same structure, and you have to adapt the code at yours. I'm not a Javascript nor DICOM SR expert but I think that it could be helpful. Please get the code inside txt file and paste it as a new entry in code templates section.

    In your case you only need to add this code in the transformer and play with this function for mapping values (at your own):

    //Common data for patient & study, add as many as you wish
    var patient = msg['tag00100020'].toString()
    var accesion = msg['tag0020000D'].toString()

    //Loop not useful, usually only one tag0040A730 found at first level
    for each (item in msg['tag0040A730']['item'])

    Please, let me know if it has been useful.

    Hope this helps,

    Ricard Bernat
    Attached Files


    • #3
      Thanks Ricard,

      This looks promising, I'll give it a try.



      • #4
        Hi Ricard,

        Thanks again for your input, I managed to get it to work with the help of your script.



        • #5
          Hi Ron,
          Would you mind sharing the channel that you created?


          • #6
            Sure, here it is. Please bear in mind that the script is not a generic one, but written for my specific needs. My SR's are always structured exactly the same, which is not normally the case.

            BTW: The hashTable is a lookup table that I use to map accession numbers to study instance uid's. It is specific to a migration I had to do using this script.

            var studyInstanceUid = msg['tag0020000D'].toString();
  'Start processing ' + studyInstanceUid);
            var hashTable = globalChannelMap.get('hashTable');
            var accessionNumber = hashTable[studyInstanceUid];
  'Found accession number ' + accessionNumber + ' for study instance Uid ' + studyInstanceUid);
            // MSH
            tmp['MSH']['MSH.10']['MSH.10.1'] = DateUtil.getCurrentDate('yyyyMMddhhmmssSSS').toString(); // Control ID
            // PV1
            tmp['PV1']['PV1.8']['PV1.8.2'] = msg['tag00080090'].toString(); // Referring Physician
            // PID
            tmp['PID']['PID.3']['PID.3.1'] = msg['tag00100020'].toString(); // Patient ID
            tmp['PID']['PID.5']['PID.5.1'] = msg['tag00100010'].toString(); // Patient Name
            tmp['PID']['PID.7']['PID.7.1'] = msg['tag00100030'].toString(); // Date of Birth
            tmp['PID']['PID.8']['PID.8.1'] = msg['tag00100040'].toString(); // Sex
            // ORC
            tmp['ORC']['ORC.2']['ORC.2.1'] = accessionNumber;  // Accession Number
            tmp['ORC']['ORC.3']['ORC.3.1'] = accessionNumber;  // Accession Number
            // OBR
            tmp['OBR']['OBR.2']['OBR.2.1'] = accessionNumber;  // Accession Number
            tmp['OBR']['OBR.3']['OBR.3.1'] = accessionNumber;  // Accession Number
            tmp['OBR']['OBR.4']['OBR.4.2'] = msg['tag00081030'].toString() ;  // Requested Procedure Description
            tmp['OBR']['OBR.7']['OBR.7.1'] = msg['tag0040A073']['item']['tag0040A030'].toString();  // Approval Date & Time
            tmp['OBR']['OBR.22']['OBR.22.1'] = msg['tag00080020'].toString() + msg['tag00080030'].toString();  // Study Date & Time
            tmp['OBR']['OBR.32']['OBR.32.1'] = msg['tag0040A073']['item']['tag0040A088'].toString(); // Interpretation approver id
            tmp['OBR']['OBR.32']['OBR.32.2'] = msg['tag0040A073']['item']['tag0040A075'].toString(); // Interpretation approver name
            // OBX
            var statusFlag = 'P'; // Assume report is preliminary, unless -->
            if (msg['tag0040A493'].toString() === 'VERIFIED') // Change status to final, unless -->
            if (msg['tag0040A491'].toString() != 'COMPLETE') // Change status to partial result
            var observerName = ''; // Placeholder
            var i = 0;
            for each (item in msg['tag0040A730']['item']) {
            	if (item['tag0040A043']['item']['tag00080104'].toString() == 'EXAM'){ // Reason for study
            		tmp['OBR']['OBR.31']['OBR.31.1'] = item['tag0040A160'].toString(); 
            		continue; // Skip to next item
            	if (item['tag0040A040'].toString() == 'PNAME'){
            		tmp['OBR']['OBR.32']['OBR.32.2'] = item['tag0040A123'].toString(); // This will go in OBX.
            	createSegment('OBX', tmp, i);
            	tmp['OBX'][i]['OBX.1']['OBX.1.1'] = i + 1;
            	// Get the value type
            	if (item['tag0040A040'].toString() === 'TEXT'){
            		tmp['OBX'][i]['OBX.2']['OBX.2.1'] = 'FT';
            	else {
            		logger.warn('Unsupported value type ' + valueType);
            	tmp['OBX'][i]['OBX.3']['OBX.3.2'] = 'GDT'; // Observation Identifier (Interpretation text
            	tmp['OBX'][i]['OBX.3']['OBX.3.4'] = item['tag0040A043']['item']['tag00080100'].toString(); // Alternate code value		
            	tmp['OBX'][i]['OBX.3']['OBX.3.5'] = item['tag0040A043']['item']['tag00080104'].toString(); // Alternate code meaning		
            	tmp['OBX'][i]['OBX.3']['OBX.3.6'] = item['tag0040A043']['item']['tag00080102'].toString(); // Alternate coding scheme		
            	tmp['OBX'][i]['OBX.5']['OBX.5.1'] = item['tag0040A160'].toString(); // Result
            //.replace(/\x0D\x0A/g,'\\.br\\'); // Result
            	tmp['OBX'][i]['OBX.11']['OBX.11.1'] = statusFlag; // Result status
            	tmp['OBX'][i]['OBX.14']['OBX.14.1'] = msg['tag00080023'].toString() + msg['tag00080033'].toString(); // Observation date/time
            	tmp['OBX'][i]['OBX.15']['OBX.15.2'] = msg['tag0040A073']['item']['tag0040A027'].toString(); // Producer ID
            	tmp['OBX'][i]['OBX.16']['OBX.16.1'] = msg['tag0040A073']['item']['tag0040A088'].toString(); // Observer ID
            	tmp['OBX'][i]['OBX.16']['OBX.16.2'] = msg['tag0040A073']['item']['tag0040A075'].toString(); // Observer Name
            // ZDS
            createSegmentAfter('ZDS', tmp['OBX'][i - 1]);
            tmp['ZDS']['ZDS.1']['ZDS.1.1'] = studyInstanceUid;  // Study Instance UID
            createSegmentAfter('ZM1', tmp['ZDS']);
            tmp['ZM1']['ZM1.3']['ZM1.3.1'] = msg['tag00080060'].toString();  // Modality