Friedrich-Alexander-Universität
Friedrich-Alexander-Universität
Stanford Radiology

Simple MHD Reader

This is a simple tutorial on how to create a simple reader for MHD image data. We will only consider little endian unsigned short data in the following example. The code could, however, be easily adapted to other MHD image formats. The full MHD reader will be adapted as required.

MHD File Header

View of the MHD header as opened by ImageJ

First, we need to read the ASCII header file that describes the raw data file contents. On the right, this header is shown as it will be opened by ImageJ via drag and drop.

We open a buffered reader to parse the ASCII file:

BufferedReader br = new BufferedReader(new FileReader(MHDfilename));

Next, we read the first line, to initialize the String line

line = br.readLine();

Now we have to go through the file row by row to find the relevant information. We sub-divide each line into variable-name and variable-value. Having done that, we save the value in a predefined variable.

 

The for us relevant variables are as followed: 

  • BinaryDataByteOrderMSB
    String [] split = line.split(" = ");

    if (line.contains("BinaryDataByteOrderMSB")){

      boolean value = Boolean.parseBoolean(split[1]);
     
    intelByteOrder = !value;
    }
  •  Offset
    if (line.contains("Offset")){
      String [] split2 = split[1].split(" ");
      offsets = new double [split2.length];
      for (int i=0; i < split2.length; i++){
        offsets[i] = Double.parseDouble(split2[i]);
      }
    }

  • ElementSpacing
    if (line.contains("ElementSpacing")){
      String [] split2 = split[1].split(" ");
      spacings = new double [split2.length];
      for (int i=0; i < split2.length; i++){
        spacings[i] = Double.parseDouble(split2[i]);
      }
    }
  • DimSize
    if (line.contains("DimSize")){
      String [] split2 = split[1].split(" ");
      width = Integer.parseInt(split2[0]);
      height = Integer.parseInt(split2[1]);
      nImages = Integer.parseInt(split2[2]);
    }

  • ElementType
    if (line.contains("ElementType")){

    if (split[1].equals("MET_USHORT")) fileType = FileInfo.GRAY16_UNSIGNED;

  • ElementDataFile
    if (line.contains("ElementDataFile")){
      datafile = split[1];
    }

Reading the Raw Data File using ImageJ API

Finally we have to use the read values to read the “.raw”-Image. This is performed using a FileInfo object from the ImageJ API:

 

FileInfo fi = new FileInfo();
fi.width = width;
fi.height = height;
fi.offset = offset;
fi.nImages = nImages;
fi.fileType = fileType;
fi.intelByteOrder = intelByteOrder;
fi.fileFormat = FileInfo.RAW;
fi.fileName = datafile;
fi.directory = new File(MHDfilename).getParent();
        

 

The image is then read using the following call:

 

ImagePlus img = new FileOpener(fi).open(false);

 

We can convert the ImagePlus container to CONRAD API using a wrapper call:

 

Grid3D grid = ImageUtil.wrapImagePlus(img, false, true);

 

This call will not create new memory, but just wrap the ImageJ container into the CONRAD API. Note that we have not considered the spacing so far. Thus it need to be set appropriately:

 

grid.setSpacing(spacings);

Code

The code of this example is founded in edu.stanford.rsl.tutorial.basics.

Authors

Rimon Saffoury, Andreas Maier