Tuesday, July 4, 2023

Indexing DICOM files in a directory into a CSV file using PowerShell and MODALIZER-SDK

This post is continues my series on PowerShell DICOM scripting. It covers a very common task that repeats itself in all kind of forms where I have a directory full of DICOM files that piled up somewhere and needs to be indexed and processed. PowerShell scripting comes handy in these cases where there's a need to do something fast and probably change it on the fly. Of course, you will need our MODALIZER-SDK for this one.

#!PowerShell ... jeje ... this doesn't work on widows ;-) 

# Well, this is something very useful (I think) for anyone managing a PACS.
# Lets say you have a directory full with DICOM files you have no idea what's in them (you do, right?) and you want to scan through them.
# So, here's a little powershell script for this:

# Ok, so first we get the directory to scan as a command line parameter
param ($ScanPath)

# This is a function. It extract one element from a DICOM object and return an empty string if the element doesn't exist or doesn't have a value. We use it later on.
function Get-Value($obj, $tag
{
  $e = $obj.GetElement($tag)
  if ($e -ne $null)
  {
    if ($e.Value -ne $null)
    { 
      return $e.Value
    }
    else
    {
      return ""
    }
  }
  else
  {
    return "";
  }
}

# Modify this array to add more tags. The pair items are used for headers (and readabity).
$tags = @(
    0x00080016, "sop class uid",
    0x00080018, "sop instance uid",
    0x00080020, "study date",
    0x00080030, "study time",
    0x00080050, "accession number",
    0x00100010, "patient name",
    0x00100020, "patient id",
    0x00100030, "patient birth date",
    0x00100040, "patient sex",
    0x0020000d, "study Instance UID",
    0x0020000e, "$series Instance UID")

# This prints a nice CSV header line. 
# Note all the '","' to enclose values in double quotes and separate them with commas. 
function Print-Header
{
    $line = '"Filename","Status'
    for (($i=1); ($i -lt $tags.Count); ($i+=2))
    {
        $line += '","'
        $line += $tags[$i]
    }
    $line += '"'
    $line
}

# This is where the element values are extracted and one line is returned. 
# The filename is in the first column and a status is in the second. Then the values from the tags array follow.
# The status  can be "OK" or "ERROR". You will also see errors in stderr.
function Parse-DicomFile($filename)
{
    $line = '"'
    $line += $filename
    $line += '","OK'
    try {
        $obj = New-Object -ComObject rzdcx.DCXOBJ
        $obj.openFile($filename)
        for (($i=0); ($i -lt $tags.Count); ($i+=2))
        {
            $line += '","'
            $line += Get-Value $obj $tags[$i]
        }
        $line+='"'
    } catch { $line = '"' + $filename+ '","ERROR"' }
    return $line
}

# Here it starts. We first print the header and then scan through the folder and extract the data from every DICOM file. 
# Note ignoring directories
Print-Header
Get-ChildItem -Recurse -Path $ScanPath | Foreach-Object {    
    if ($_.Attributes -ne "Directory") {
        Parse-DicomFile $_.FullName
    }

# Enjoy!!!



Wednesday, June 28, 2023

Introduction to DICOM - Chapter 5 – Solving a DICOM Communication Problem

Today we are going to diagnose a communication problem between two DICOM applications and hopefully find the reason for the problem and solve it. I know, we didn’t even start talking about the DICOM network protocol, but hey, we’re not going to read all this 3,000 pages standard together before getting our hands dirty, right?
In this post we'll discuss:
  1. Application Entities (AE’s) – the nodes in the DICOM network and their name – AE Title
  2. Association – a network peer-to-peer session between two DICOM applications
  3. Association Negotiation – The first part of the association in which the two AE’s agree on what can and can’t be done during the Association
  4. The Verification Service using the C-ECHO command – a DICOM Service Class that is used to verify a connection, sort of application level ‘ping’.
  5. The Storage Service using the C-STORE command – a DICOM Service that allows one AE to send a DICOM object to another AE
The C in C-ECHO and C-STORE commands stands for Composite. If you remember, in chapter 4 when discussing the DICOM Data Model, we said that DICOM applications exchange composite objects (the DICOM images that we already know) that are composites of modules from different IE's where IE's are the information entities of the Normalized DICOM data model.

Here's the story:
Complaint 20123

Burt Simpson from Springfield Memorial Hospital reports that he can’t send the screen capture to the PACS. He kept clicking the green “Send” button but he always gets the same error: “Operation Failed!”. The log file Burt copied from the system is attached.
You may ask yourself, what’s the point in analyzing a log of an application that we are never going to use? Well, the truth is that all DICOM logs look alike. Actually, most DICOM applications are quite similar because DICOM software implementations have common ancient ancestors. If it’s a C library it may be the DICOM test node, CTN. If it’s Java than it might be dcm4che. Even if it's PHP or other newer languages, the libraries were transcribed and ported from the old C implementations so all DICOM logs are similar.

Query/Retrieve part II - C-MOVE


In part I of this post, I was in a meeting with a customer reviewing their workstation code and while sitting there I was thinking to myself, why should my customers have to deal with so many details of the DICOM Q/R Service when all they really want is to retrieve a study just like they would have downloaded a zip file from a web site. And thus, later, back in my office I decided to extended the DICOM Toolkit API to include a C-MOVE method that will take care of everything including the incoming association. In today’s post I’m going to use the new MoveAndStore method to talk about the DICOM Query/Retrieve service. We’ll start at the end and then work our way backwards.

C-MOVE is a DICOM command that means this: The calling AE (we) ask the called AE (the PACS) to send all the DICOM Instances that match the identifier to the target AE. 
Here’s how you ask a PACS to send you the DICOM images with RZDCX (version 2.0.1.9).

        public void MoveAndStore()
        {
            // Create an object with the query matching criteria (Identifier)
            DCXOBJ query = new DCXOBJ();
            DCXELM e = new DCXELM();
            e.Init((int)DICOM_TAGS_ENUM.patientName);
            e.Value = DOE^JOHN";
            query.insertElement(e);
            e.Init((int)DICOM_TAGS_ENUM.patientID);
            e.Value = @"123456789";
query.insertElement(e);
            // Create an accepter to handle the incomming association
DCXACC accepter = new DCXACC();
            accepter.StoreDirectory = @".\MoveAndStore";
Directory.CreateDirectory(accepter.StoreDirectory);
            // Create a requester and run the query
DCXREQ requester = new DCXREQ();
            requester.MoveAndStore(
                MyAETitle, // The AE title that issue the C-MOVE
                IS_AE,     // The PACS AE title
                IS_Host,   // The PACS IP address
                IS_port,   // The PACS listener port
                MyAETitle, // The AE title to send the
                query,     // The matching criteria
                104,       // The port to receive the results
                accepter); // The accepter to handle the results
        }

Behind this rather short function hides a lot of DICOM networking and when it returns we should have all the matching objects stored in the directory “.\MoveAndStore”. Readers with some practical DICOM experience probably expect me to say that it can also fail. In that case MoveAndStore throws an exception with the error code and description. Sometimes you would have to set the detailed logging on and start reading logs like we did in chapter 5 of this tutorial on DICOM networking and in some later post we will look together at a DICOM log of a Q/R transaction.

The following diagram, taken from part 2 of the DICOM standard, is commonly seen in DICOM Conformance Statements as the Data Flow diagram of the Q/R Service. These diagrams and their notation are defined by the standard in part 2 that specify the DICOM Conformance Statement – a standard document that every application vendor should provide and that describes how they implemented the standard in their product. At some point we will get to how to read and write these documents.




The vertical dashed line represents the DICOM Protocol Interface between the two applications (it is usually a single dashed line but in this example it got a bit messed up). The arrows accros the interface represents DICOM associations. The arrow points from the application that initiates the association (the requester) to the application that responds to it (the responder or accepter). The upper part of the diagram shows the control chanel where the C-MOVE request is sent and statuses are reported back by the PACS. The lower part of the diagram shows the data chanel where the DICOM instances are sent to the client.

DICOM Modality Worklist

Modality worklist (MWL) is one of DICOM’s workflow services that really make a difference. It’s the difference between grocery store workflow with notes on little pieces of paper and a true modern accountable workflow.

Technically speaking, DICOM Modality Worklist is a task manager just like a piece of paper with short text and a check box or the tasks application on your iPhone (or Android). But for the imaging center or RAD department the advantages are enormous. The most obvious benefit is that there’s no need to reconcile all kind of misspelled names in the PACS because the patient name is no longer keyed in on the modality workstation but received electronically via the MWL query. The fact that the requested procedure is also received electronically reduces the chance for doing the wrong procedure to the wrong patient. Combined with Modality Performed Procedure step (MPPS), that allows the modality to report the task status, take ownership over the task and checkmark it as done when completed, the up side is obvious. No wonder then, that many HMO’s require Modality Worklist as a mandatory feature for every imaging device they purchase. 

The most basic abstraction of a task is a short description of what should be done and a checkbox. That’s all it takes. The MWL data model is a bit more complicated and has two levels.
The top, parent, level is called “Requested Procedure” (RP) and holds the information about the patient (name, id), the study (accession number, study instance UID) and the procedure. The procedure can be described as text using attribute (0032,1060) – “Requested Procedure Description” or in a more sophisticated manner using the (0032,1064) – “Requested Procedure Code Sequence” where static tables of codes and meanings can be used to configure and maintain procedures in the RIS or HIS.
The child level is called “Scheduled Procedure Step” (SPS) and holds attributes relevant to the modality and the actual procedure to be made. A single requested procedure may hold more than one SPS if the request is for a multi-modality study, for example a chest X-Ray and a CT or whatever combination, or if for example two protocols should be applied (e.g. Chest and Abdomen). As a modality, we will use the data in the RP to identify the patient and eliminate re-typing of the name and ID and the SPS to determine what exactly to do.

Modality Performed Procedure Step

Introduction


After the post on Modality Worklist, I felt that it wouldn’t be a complete without explanation on Modality Performed Procedure Step. MWL without MPPS is like a task list without checkboxes, and after all, striking a checkbox on a completed task is great fun. Talking of which, I once red this article about productivity and task lists and since then I’m using a circular checkbox on my paper to do notes because it’s 4 times faster. Instead of 4 lines you only need one. Think of it.

IHE Comes to Rescue


Though the DICOM standard states that it doesn’t go into the details of the implementation and what should be the implications of MPPS on workflow it is very clear from reading the details of the standard that an MPPS is the checkmark of MWL. The gap is closed by IHE radiology technical framework that does a great job and details exactly what should be the workflow and how the implementation should look like. If you are not familiar with IHE, I strongly recommend navigating to their web site and start digging. Getting familiar with the IHE Technical Frameworks can save a lot of expensive software architect hours and more important, save you from implementing things wrong. The IHE TF is high quality software specification document that you can use almost as is for your healthcare IT software projects.


Anyway, if you don’t have time to dig inside the long documents of IHE and DICOM and HL7, here’s a short data and program flow summary:

  1. The modality makes a MWL Query. Each result is a requested procedure object with one or more Scheduled Procedure Steps (SPS).
  2. The user picks one SPS to perform.  
  3. The modality creates a new Modality Performed Procedure Step (MPPS) that references the Study, the requested procedure, and the SPS.  This is done using the N-CREATE command. 
  4. There’s a state machine for MPPS with three states:
    1. In Progress (A dot at the center of the circular checkbox)
    2. Completed (A dash on the checkbox)
    3. Discontinued (Back to the beginning)
  5. After the images acquisition is done the modality sends an updated status for the MPPS using N-SET command. The N-SET must include a performed series sequence with at least one series in it, even if the procedure was aborted (in which case the series will have no images).
  6. At this point the Scheduler should dash the checkbox to mark the task as completed (or discontinued).
  7. Though usually you would have a 1-to-1 relationship between a scheduled procedure and a performed procedure, the DICOM data model has a n-to-m relationship between SPS and MPPS. The connection is made by the MPPS that references the SPS that it was performed for.

The DIMSE-N Protocol


Unlike all the other command that we’ve discussed so far in this tutorial namely C-ECHO, C-STORE, C-FIND and C-MOVE that are DIMSE-C commands, MPPS uses the normalized, DIMSE-N protocol commands N-CREATE and N-SET to create and update the Modality Performed Procedure Step normalized  information entity. We’ve discussed the normalized data model (aka DICOM Model of the Real World) briefly in chapter 4 when discussing DICOM Objects and stating that image objects are composites of modules from different information entities.
Like, in MWL before, here’s where MPPS fits into the DICOM Data Model:

Storage Commitment

What is DICOM Storage Commitment Service and why is it needed

Storage commitment (SCM) is a DICOM service that lets you verify if files that were previously sent to the PACS using the DICOM Storage Service were indeed stored by the application you sent it to. The SOP Class UID of this Service is “1.2.840.10008.1.20.1”. One can argue if it is necessary or not because when you send a DICOM image using C-STORE command and get a success status (0x0000) then it is supposed to be stored so the existence of Storage Commitment raises doubts about the meaning of that status in the first place. However, I can defiantly think of reasons for having such service, first because better safe than sorry and second because I already had some programming experience in the days when the DICOM standard was specified, Thanks god, we did make a long way since then. For example, some engineers, for the sake of efficiency and performance considerations, may have decided to first puts the files in a temporary storage or a queue, without even looking at their content and reply immediately with success and then later, when some batch or another thread processes the files in the queue and try to fill the database errors occur. I wouldn’t implement it this way, and I’ll give you reasons for that at the end of this post, but I did run into such implementations. The DICOM standard gives us the service but doesn’t go into the details of what is the implementation meaning should be but IHE does. IHE says that if your application creates instances and send it to somewhere, before deleting them from your local disk it should send a Storage Commitment and if all instances are OK, go ahead and make some space on your hard drive. Sounds like a good idea to me, it’s like double booking. Storage is the transaction and Storage Commitment is the reconciliation, Why not.

Storage Commitment Data Flow

All together SCM is pretty straight forward. All we need to do is to send a list of the instances and get back a reply saying which are in the PACS database and which are not, and that’s exactly how it works. Well, almost.  

Chapter 12: Pixel Data

Frame 0001
I guess that one can't escape talking about pixels when dealing with DICOM. After all, imaging is what DICOM is all about and digital images are built from pixels. So today, to celebrate release 2.0.2.6 (and the x64 version) of the DICOM Toolkit, I'm finally going to touch the heart of every DICOM Image, The Pixel Data.

For today's post I've prepared a little C++ test application that really does nothing much other then putting pixels into the pixel data of a DICOM file and save it. Well, not exactly nothing much, because it creates a huge DICOM file, more then 0.7 GB and compress it and never use more then 20 MB of memory. If you want to know how, read on.

DICOMDIR and Media Interchange

[update 24 March 2023: Latest releases of HRZ software can be found on HRZ website - www.hrzkit.com]

DICOMDIR, Have you heard this term? What does it mean? Do I need this in my system? Lots of questions. Let's try to answer some.

Here's a list with quick information about DICOMDIR:

  1. Standard DICOM CD/DVD should have a file named DICOMDIR in its root directory.
  2. The DICOMDIR file has in it records that hold paths to DICOM files on the media.
  3. DICOMDIR is a DICOM Object holding a sequence of DICOMDIR records nodes each having a type like PATIENT, STUDY, SERIES and IMAGE
  4. The DICOMDIR file include key attributes from the data on the media such as Patient Name, Patient ID, Study ID, Study Date.
  5. The file names of DICOM files on a standard DICOM CD/DVD should be capital alphanumeric up to 8 characters with no suffix.
  6. The CD/DVD may include other files that are not DICOM. The DICOMDIR file does not reference them.
  7. The mandatory elements of the DICOMDIR nodes are not 1-2-1 with the mandatory elements in the DICOM Objects. For example Study ID which is Type 2 in DICOM Image objects is Type 1 in DICOMDIR STUDY Record. So when creating your DICOM images if you intend to create DICOMDIR for them, add these elements too.
There are two ways DICOM application can collaborate with one another. They can communicate over TCP/IP network connection or they can exchange files over some physical media.

The first figure in the DIOM standard makes sense eventually
The picture above, which is by the way the first figure in the DICOM standard (page 10 of chapter 1), explains that very well although when I first looked at thirteen years ago it it didn't mean anything to me.
It is worth staying a bit longer on this figure because it has a lot of valuable information in it so lets work it top to bottom.

Converting Bitmap, JPEG and PDF to DICOM

Before we move any further, the examples in this post are included in HRZ's MODALIZER-SDK DICOM C# Examples package. Non programmers, can achieve the same results and much more using MODALIZER+ DICOM Wizard, HRZ's administrative PACS workstation. Let's start.

Imagine you're a dermatologist taking pictures of patients' skin for treatment tracking using a digital camera. The pictures are JPEG's and have no patient info in them. If you could convert them to DICOM and send them to the clinic PACS, that would be a great advancement.

Tuesday, June 27, 2023

Getting Oriented using the Image Plane Module

Just before diving into how to get oriented using the Image Plane Module, so we can put the letters right in our viewer, I want to get equipped with few more latin words so we understand what Radiologists are mumbling. If you're a Doctor, please be patient with us programmers. 

Cuts! Three major cuts we have (or planes): 

Transverse (AKA Axial) divides head from feet
Axial Cut

Sagittall Cut - right between the eyes
Sagittal Cut

and Coronal Cut - the Filet
Coronal Cut



And now that we're done with Anatomy let's do some Geometry. In this post I'm going to start explaining the use of the Image Plane Module. To refresh on Modules read chapter 4 of the DICOM Tutorial. The Image Plane module is part of the CT Image IOD and the MR Image IOD and any other object that have a frame of reference, i.e. that has a spatial coordinates system related to the patient or in other words is a 3D scan of the body.

Introduction to DICOM - Chapter 4 - DICOM Objects


Chapter 4 – DICOM Objects
In chapter 3 we’ve learned about DICOM elements. Every element is one piece of typed data with a pre defined, well specified meaning. There are thousands of DICOM elements (See chapter 6 of the standard) from the very basic attributes of patient name and birth date to the most esoteric uses of 3D surface vortices. In this chapter we’re going to collect elements into image object that is called Secondary Capture Image. 

The guys at DICOM did a lot of very good work and created well defined classes for a very detailed Data Model. This is why I always advise to dig in the DICOM standard before designing your imaging device software because there’s a very good chance that the DICOM technical committees already did the work for you and you can save a lot of expansive design time this way. 

In a way DICOM objects definitions are similar to object oriented programming. I prefer though the analog to interfaces specifications. The motivation to adhere to a standard is to enable interoperability. By detailing information object definitions (IOD’s) DICOM enables us to exchange virtual objects between applications without knowing in advance anything about the application we are going to interface with. 

In this chapter I'm going to complete chapter’s 3 examples by adding elements to the object until it’s a valid Secondary Capture Image according to the DICOM standard. Secondary Capture Image is the simplest DICOM image object. Secondary Captures is not related to any specific device. It has the very basic set of elements that a DICOM application needs in order to display and archive a DICOM image properly.

Friday, June 23, 2023

Introduction to DICOM - Chapter 3 - DICOM Elements

Chapter 3 – DICOM Elements

Let’s start with a useful example. Suppose you are a dermatologist and that you use your Smartphone digital camera to record and track patients’ skin condition. You practice a simple procedure that is basically this:

1. Take a photo

2. Send it to yourself by email

3. Open the email on your laptop and save the picture in a folder having the patient name.

As programmers, we don’t have to talk much about the flows of this practice but for a small, one doctor clinic, this might just work.

In this lesson, we’ll take the JPEG image and DICOMIZE it. When we DICOMIZE an Image we wrap the image in a DICOM envelope and add important data that is required by the DICOM standard in order to enable all DICOM enabled applications to read and display the image correctly. It’s true that non DICOM application can display the JPEG image just as it is now without DICOMIZING but that’s another story.

Introduction to DICOM - Chpater 2 - Why is it this way in DICOM?

Introduction to DICOM
Chpater 2 - Why is it this way in DICOM?
Many times when I explain features and aspects of DICOM I get questions like, “Why do you need DICOM if you have JPEG and XML?”; or, ”why is DICOM so complicated?”. Many variants of this question come up over and over again. These types of questions can be very broad or very specific and relate to all kind of choices that the people who write the standard make and the options that they take.

Introduction to DICOM - Chapter 1 - Introduction

Introduction to DICOM

Chapter 1: Introduction

DICOM is a software integration standard that is used in Medical Imaging. All modern medical imaging systems (AKA Imaging Modalities) Equipment like X-Rays, Ultrasounds, CT (Computed Tomography), and MRI (Magnetic Resonance Imaging) support DICOM and use it extensively.

In this tutorial I present a high level review of DICOM. We will look at DICOM from the user point of view trying to avoid the fine details when possible.

Thursday, April 6, 2023

New releases of MODALIZER+ and MODALIZER-SDK

A quick update on HRZ latest software releases. We've released MODALIZER+ V6.1 with video capture capabilities. Check the post on HRZ web site. And also a new release of MODALIZER-SDK (version 3.2.2.4) that is available on HRZ downloads page.

Wednesday, February 1, 2023

Hello Dubai! A visit to ArabHealth 2023

The Moon over Burj Khalifa tower in Dubai

The Abraham Accords opened the UAE to Israelis and here I am in Dubai for the ArabHealth 2023 convention. I'm not a big fan of trade shows but when the opportunity came up I just couldn't say no. Add to that the 10% discount on Emirates flights a week before and after the show and the connection flight to Colombo, Sri Lanka, one of my favorite surf destinations, and there you go, business and pleasure comes together. 

Business first, how can you make business in a trade show? 

  1. Set up a booth, you may say? Well, for a small company like HRZ, when looking at the huge pavilions of GE and Siemens, I don't think so. Actually I tried this once at MEDICA and wasn't happy at all with the results.