3

Provided following information from a DICOM header, how can I calculate the third value of voxel size? I assume the first two values are 0.515625 and 0.515625.

BitsAllocated: "16"
BitsStored: "12"
Columns: 512
HighBit: "11"
ImageOrientation: "1\0\0\0\-1\0"
ImagePosition: "-144\-34.7242241\925.599976"
ImageType: "ORIGINAL\PRIMARY\AXIAL\HELIX"
InstanceNumber: "456"
Modality: "CT"
PhotometricInterpretation: "MONOCHROME2"
PixelRepresentation: "0"
PixelSpacing: "0.515625\0.515625"
RescaleIntercept: "1"
Rows: 512
SamplesPerPixel: "1"
SeriesDescription: "CERVEAU SANS IV"
SeriesNumber: "3"
SliceThickness: "1.50"
WindowCenter: "00040\00040"
WindowWidth: "00120\00120"
imagesFormat: "jpg"
modality: "CT"
name: "soft tissue"
nodeId: "557621"
pixelHeight: "0.515625"
pixelWidth: "0.515625"

Note: I receive a JPEG image stack, not DICOM, and it come with a file that had the values I posted above. I can go back and ask for additional information in file if needed.

Amit Joshi
  • 15,448
  • 21
  • 77
  • 141

2 Answers2

5

Given only the tags of one slice, you have to use SliceThickness as the third dimension, though I would advice against this, as this is not guaranteed to give the distance between slices. There is the tag SpacingBetweenSlices that provides this information, though it seems not to be present in your case.

The best way is to use the difference in ImagePositionPatient between adjacent slices. For this, you need of course the tag of the next slice, additionally. As a side note: in your listing, ImageOrientation and ImagePosition should better read ImageOrientationPatient and ImagePositionPatient, as ImageOrientation and ImagePosition are other tags (not present in CT images).

ImagePositionPatient gives the position of the upper left hand corner of the slice in DICOM patient coordinates, and to calculate the distance you have to take into account the orientation of the slice in that coordinate system. This is given by ImageOrientationPatient, which contains the normalized rows and columns direction cosine vectors of the slices in DICOM coordinates. You can read that up in the DICOM standard.

The first two components of the orientation matrix is provided by ImageOrientationPatient (e.g. the first and second three numbers), the third component can be calculated by taking the cross product of these 2 components.

So, in pseudo code this will look something like this:

orient1 = vector(ImageOrientationPatient[0], ImageOrientationPatient[1], ImageOrientationPatient[2])
orient2 = vector(ImageOrientationPatient[3], ImageOrientationPatient[4], ImageOrientationPatient[5])
orient3 = orient1 x orient2 // cross product
orient_matrix = matrix(orient1, orient2, orient3)

pos1 = vector(ImagePositionPatient[0], ImagePositionPatient[1], ImagePositionPatient[2]) // from current slice
pos2 = vector(ImagePositionPatient[0], ImagePositionPatient[1], ImagePositionPatient[2]) // from adjacent slice
diff_pos = pos2 - pos1

image_pos = orient_matrix o diff_pos / length(orient3) // normalized dot product

voxel_z = image_pos.z

Update: As pointed out by @gofal, the first version was incorrect. I also included the normalization (e.g. delete by length(orient3)), though strictly speaking the values should already be normalized.

MrBean Bremen
  • 14,916
  • 3
  • 26
  • 46
  • I had a look at two actual dicom images and the ImagePositionPatient's read: -63.9843\-61.87500\-1270.300 : -63.9843\-61.87500\-1270.500 The difference between the last numbers is .2 which matches what the software suggests is the voxel size last value. Did I do it right? – daftcranberry2 Dec 21 '20 at 10:41
  • Well, in your case it is correct, because the orientation is axial (e.g. the same as the DICOM coordinate system). so the z coordinate can be directly taken. In other cases (orientations) it would not work. – MrBean Bremen Dec 21 '20 at 10:44
  • 1
    @itchynutsack69 take a look at the actual dicom image. If you are lucky, then the modality already did the math for you and added a value in SpacingBetweenSlices (0018,0088). This should be the distance in mm between two adjaced slices. – gofal3 Dec 21 '20 at 10:54
  • @gofal3 I should have specified I was given a jpg image stack not dicom, and it came with a file that had the values I posted here. I'll have to go back and ask for the ImagePositionPatient of a second slice – daftcranberry2 Dec 21 '20 at 10:57
4

PixelSpacing (0028,0030) gives you the two sizes in direction of Columns and Row in the image. The third value you are asking for is Slice Thickness (0018,0050).

In case of some reconstructions (MIP or similar), the Slice thickness may be a higher value than the distance of two neighboring images. So if you are using this single image as its own, then you will have to use Slice Thickness. But if you have a stack of images and want do do 3d-rendering or reconstruction or similar, then I would recommend to calculate the third voxel size by the distance of two adjacent images.

References: https://dicom.innolitics.com/ciods/ct-image/image-plane http://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.34.12.html

gofal3
  • 1,213
  • 10
  • 16
  • It is a stack of images, so when I use 1.5 as the third value of voxel size it just looks too long. I am not sure how I would do the calculation to get the correct value math is not my strong point as I usually just open dicoms, but in this case they didn't come in dicom format but had a separate file showing these values – daftcranberry2 Dec 21 '20 at 09:23
  • 1
    using slice thickness for the voxel size is not recommended. The slice thickness tells how wide the area was to calculate the gray value for the voxel. Slices may overlap with their thickness or there may be spaces between them. MrBean already explained that unless you are using the physical position (Image Position Patient) you may have a distorted rendering. – Markus Sabin Jan 11 '21 at 09:03