I get asked, and am often in need myself, of sample DICOM files in various formats. By sample I mean no weird private tags and all of the identifying patient information has been removed. The files below are part of the collection I have built up over the years.

These files can be used to test applications you write using my PHP DICOM Class and can be opened in any image viewer, such as MicroDICOM.

Click on the thumbnail to get the DICOM file.

In this tutorial I’m going to post some example code and walk you through converting a DICOM multi-frame image (CINE Loop) into an mp4 video file. I chose MP4 because it works well with Apple and Microsoft products.

You’ll need ffmpeg installed with the ability to do x264. The ffmpeg site has many guides on how to do this. I used this guide for CentOS 6 for this tutorial.

You’ll need a copy of my PHP DICOM class installed.

You’ll need a copy of the example files.

Once you’ve got the prerequisites out of the way, run the commands below to download and run a copy of the example files.

wget http://www.deanvaughan.org/projects/multi-frame-to-mp4.tar.gz
tar zxvf multi-frame-to-mp4.tar.gz
cd Mutli-Frame_to_MP4/
./dcm2mp4.php sample.dcm

Your freshly created MP4 file is ./video_temp/sample.dcm.mp4, a copy is playing below:

Now take a look at dcm2mp4.php, it should be commented well enough to make it easy to understand what it is doing.

This article will cover writing a storage server that is able to receive images, store them on your hard drive, create thumbnails of the images, parse out important header information, and store that header information in a database.

In my continuing effort to show off how handy my PHP DICOM class and the OFFIS DCMTK are, I’ve decided to write a series of articles on how to implement a PACS in PHP.

These articles will be focused on Linux, though I may amend them in the future to cover Windows. They will assume that you have some knowledge of PHP, mySQL, and the Linux command line.

You will need my PHP DICOM class installed. You will also need mySQL installed and have access to add users and databases.

One of the things I dislike about programming books is that they’ll spend pages upon pages showing snippets of code and explaining everything line by line. I’m not going to use that approach, I’m going to walk you through getting the example code running on your computer, testing it, and explaining how it works in a high level fashion. I tried to write the code plainly, simply, and use verbose comments through out explaining what is going on.

Lets get the sample code up and running!

Step 1:

wget http://www.deanvaughan.org/projects/PACS_Tutorial.tar.gz
tar xvf PACS_Tutorial.tar.gz
cd PACS_Tutorial/part1
chmod 755 import.php store_server.php send_test_image.php
chmod -R 777 received_images temp

Download all of the sample code and set permissions.

Step 2:

mysql -uroot -p < db.sql

We need to create a database and user for our PACS. The file db.sql will create a user, ‘pacs’, with password ‘pacspassword’, and grant it all privileges to a new database called ‘pacs’. It will then create two tables, studies and images.

If at all possible, don’t change any of this, it’ll make the tutorial a lot less of a headache. If you do change it, open up import.php, and look for mysql_connect. Change the values there as needed.

Step 3:

./store_server.php

With that command we’ve launched our storage server on port 1104. Notice that the script didn’t launch in the background? Don’t worry, I’ll cover that later on.

If you don’t want your server running on port 1104, edit store_server.php and its easy enough to change.

The storage server as is doesn’t care about AE titles, its promiscuous and will accept images from anyone.

Step 4:

Since our storage server is using our terminal, leave it running and open a new terminal for the next steps.

store_server.php is going to be receiving your images, after an image is received it will run another script, import.php. import.php will be responsible for moving the image to a safe place on the hard drive, parsing the image’s header information, placing that information into a database, and creating a JPEG thumbnail of the image for later use.

You can test to see if all of this works by sending an image to your computer’s IP address using port 1104. You can make something up for the AE title.

If you don’t have a way to send yourself images, I’ve included a small script that will send your new server one image.

./send_test_image.php

That will send dean.dcm from class_dicom.php’s examples over to your new server.

Once you have sent an image you can switch back to your terminal running store_server.php and see the log entries regarding the image transmission. Among many things the log will show you where the image was saved.

Step 5:

mysql -uroot -p < view_db.sql

Let’s take a look at the database. If all went well the command above should show you the contents of the database; information about the images sent to the server.

There are two tables.

The first table is studies. This table contains information obtained from the image pertaining to the study. Each study can have many images, in example, a chest study could have both a PA and lateral view; one study, two images.

The second table is images. This table contains information specific to an image.

You’ll see there isn’t a field for storing the file name of the image, this is because the file name is easily inferred from database information.

Take a look at this snippet from import.php:

$store_dir = "./received_images/$sent_from_ae/" . $img['year'] . "/" . $img['month'] . "/" . $img['day'] . "/" .
  $img['study_uid'];

The image is stored in a directory based on the AE title it came from, the appointment date, and the study uid. The image itself uses the SOP instance plus ‘.dcm’ for its file name. Since all of this information is in the database, we can find the file. Later tutorials will go into more detail on this.

Step 6:

Right now, the storage server is stuck running in its own terminal window, if you close the window the storage server stops running, not cool. You’ll want to get it running in the background and you’ll want it to start at boot.

This gets tricky as different flavors of Linux, and even different versions of those flavors, handle this differently. I’ll discuss the three most common approaches. If you have not done so already, control-c in the storage_server.php terminal to stop it.

CentOS 5.6+, Fedora, Red Hat, Ubuntu:

You should have a /etc/init directory. You can place script in this directory that init will use to start/stop and keep running your programs.

start on runlevel [3]
stop on runlevel [!$RUNLEVEL]
respawn
console output
exec /home/dean/PACS_Tutorial/part1/store_server.php

Create /init/store_server.conf and add all of that. Be sure to change the path to store_server.php to match your own setup.

‘initctl start store_server’ to start your server

inittab:

If you don’t have a /etc/init directory, you can always fall back to editing the inittab itself.

ss:3:respawn:/home/dean/PACS_Tutorial/part1/store_server.php

Edit /etc/inittab and add this line to the bottom of the file. Be sure to change the path so it points to your copy of store_server.php. Once you’re back at the command line, type ‘init q’. This will reload the inittab and start up store_server.php.

All else fails:

nohup store_server.php

nohup will start store_server.php in the background for you. It will not restart the process if it crashes as the methods above will.

The End?

Now you have a multi-threaded DICOM storage server capable of receiving thousands of studies worth of images everyday. The information it receives is placed into a database for easy access by other programs.

Stay tuned for part two where in I’ll show you how to write a user interface to your PACS.

I develop primarily on Linux and wrote class_dicom.php with Linux in mind. This tutorial will be geared towards CentOS or Fedora as that is what I use on a day to day basis. I’ll try to include notes for Ubuntu/Debian when possible.

I’m going to assume you have at minimum, Linux installed on a PC and you can access the command line as root.

1. Let’s get your environment ready

We’re going to install all of the needed development tools, a web server, and MySQL. A web server and MySQL is not needed by class_dicom.php, but since most folks are going to want to use PHP from a web server, we might as well get it installed.

CentOS:

yum -y groupinstall "Web Server" 'Development Tools' "MySQL Database"

yum -y install wget php php-gd ImageMagick libjpeg zlib libpng libtiff libxml2 libpng-devel zlib-devel libjpeg-devel libtiff-devel libxml-devel libxml2-devel libwrap-devel libpng10-devel  php-mysql

Ubuntu:

sudo apt-get install lamp-server^

sudo apt-get install build-essential wget ImageMagick libjpeg zlib libpng libtiff libxml2 libpng-devel zlib-devel libjpeg-devel libtiff-devel libxml-devel libxml2-devel libwrap-devel libpng10-devel

All of the above will probably take a while to finish out. Note that the ^ in the Ubuntu command is not a typo and needs to be present.

2. Build and install DCMTK

DCMTK is what class_dicom.php uses to actually work with DICOM files. Among many other things, it is a collect of command line tools for working with DICOM files.

The process of building and installing is essentially the same between versions of Linux.

wget ftp://dicom.offis.de/pub/dicom/offis/software/dcmtk/dcmtk360/dcmtk-3.6.0.tar.gz 
tar zxvf dcmtk-3.6.0.tar.gz
cd dcmtk-3.6.0
./configure;make;make install

Depending on your computer, the DCMTK can take a long time to build.

3. Install class_dicom.php

Download a copy:

wget --no-check-certificate http://github.com/vedicveko/class_dicom.php/zipball/master
unzip master
mv vedicveko-class_dicom.php* class_dicom_php

and…. you’re done.

Lets make sure it works!

cd class_dicom_php/examples
./get_tags.php dean.dcm

You should see a header dump of dean.dcm printed to the screen.

The script below will look in the directory you specify in $temp_dir and send any images it finds to a DICOM host. When it is done sending it will move the DICOM file to a back up directory.

#!/usr/bin/php
<!--?PHP 

require_once('class_dicom.php');

# WHERE YOUR DICOM FILES ARE
$temp_dir = '../temp';

# WHERE YOU ARE SENDING THEM
$target_host = 'some IP address';
$target_port = '105';
$target_ae = 'BK';
$my_ae = 'BK';

if(!file_exists('bk')) {
  mkdir('bk');
}

$d = new dicom_net;

if($handle = opendir($temp_dir)) {
  while(false !== ($file = readdir($handle))) {
    if($file != "." &#038;& $file != "..") {

      print "Sending $file...\n";

      $d--->file = "$temp_dir/$file";
      $ret = $d-&gt;send_dcm($target_host, $target_port, $my_ae, $target_ae);
      if($ret) {
        print "Send Error: $ret\n";
        continue;
      }
      else {
        print "Good Send\n";
        print "Moving $temp_dir/$file\n";
        rename("$temp_dir/$file", "bk/$file");
      }

    }
  }
  closedir($handle);
}

?&gt;

I had the opportunity today to help someone get class_dicom.php working under windows. I was pretty surprised to learn that you do not have to modify the class much, but it does take some time to install the other prerequisite software.

If you’re using IIS, you can skip step #1. You will need to get a copy of PHP installed under IIS. PHP on IIS (http://php.iis.net/) will allow you to do that easily. If you are using IIS, change the file locations below as appropriate for your enviroment.

1. You’ll need a copy of PHP.

Since you’ll probably want to run your PHP scripts under a web server you might as well kill two (three) birds with one stone.  The Wamp (http://www.wampserver.com/)  package is an easy as pie installer that will install and configure Apache, mySQL, PHP, and several other handy tools at once.

Once installed, be sure to find it in the system tray, left click it, and then select Put Online to start it up.

You can then go to http://localhost to test your install out.

The files you’re serving are all under C:\wamp\www\

2. You’ll need the Windows binaries of the DCMTK.

Head on over to the DCMTK website (http://dicom.offis.de/dcmtk.php.en/) and under executable binaries, grab the zip file for Windows.

Unzip it an copy the result to C:\dcmtk so it’s easy to find.

3. Get a copy class_dicom.php.

You can download a zipped version from GitHub (https://github.com/vedicveko/class_dicom.php/zipball/master). Once downloaded unzip it to C:\wamp\www\class_dicom.

You should be able to visit your web server at http://localhost/class_dicom and see a directory listing.

We’re going to need to make some modifications to the class. Open C:/wamp/www/class_dicom/class_dicom.php in an editor.

Near the top of a file is a line that looks like this:

define('TOOLKIT_DIR', '/usr/local/bin');

We need to change that to point to where we installed DCMTK. Change the line to look like this:

define('TOOLKIT_DIR', 'C:/dcmtk/bin');

Save class_dicom.php and you’re done with it.

4. Finishing up

All of the scripts in the examples directory for class_dicom.php are meant to run on the UNIX command line. This won’t work out too well when you try to run them under a web server on Windows. We need to change up one of the examples to run in this environment so you can see that it works. Take the code below and copy it into the C:\wamp\www\class_dicom\examples\get_tags.php file.

<?PHP
#
# Prints out the DICOM tags in a file specified on the command line
#

require_once('../class_dicom.php');

$file = 'dean.dcm';

if(!file_exists($file)) {
  print "$file: does not exist\n";
  exit;
}

$d = new dicom_tag;
$d->file = $file;
print "TEST: " . $d->load_tags();

print "<pre>";

print_r($d->tags);

$name = $d->get_tag('0010', '0010');
print "Name: $name\n";

?>

Once that is done go to http://localhost/class_dicom/examples/get_tags.php. You’ll see a header dump of the dean.dcm sample DICOM file.

(Or skip all of that and open get_tags_webbased.php in your browser instead.)

You now have a functional install of class_dicom.php to work with!

For the first time ten months I’ve decided to update my DICOM PHP class (class_dicom.php).

I’ve added two new functions:

is_dcm(): This function will return true if the provided file is a DICOM file, false otherwise.

multiframe_to_video():  Convert a DICOM multi-frame file into a video (.mp4, .avi, .mpg, ect)

multiframe_to_video() is the big one. This functionality is driven by ffmpeg and is easily extendable and modifiable. Think of it as DICOM to AVI or DICOM to MPG.

Check it out!