Search code examples
pythonpydicom

Bug in pydicom function


I wanted to work with pydicom for processing dicom images. Unfortunately I get the error

File "/usr/local/lib/python2.7/dist-packages/dicom/dataset.py", line 372, in _pixel_data_numpy
    raise TypeError(msg % (numpy_format, self.PixelRepresentation,
UnboundLocalError: local variable 'numpy_format' referenced before assignment

in the function

def _pixel_data_numpy(self):
"""Return a NumPy array of the pixel data.

NumPy is a numerical package for python. It is used if available.

:raises TypeError: if no pixel data in this dataset.
:raises ImportError: if cannot import numpy.

"""
if 'PixelData' not in self:
    raise TypeError("No pixel data found in this dataset.")

if not have_numpy:
    msg = "The Numpy package is required to use pixel_array, and numpy could not be imported.\n"
    raise ImportError(msg)

# determine the type used for the array
need_byteswap = (self.is_little_endian != sys_is_little_endian)

# Make NumPy format code, e.g. "uint16", "int32" etc
# from two pieces of info:
#    self.PixelRepresentation -- 0 for unsigned, 1 for signed;
#    self.BitsAllocated -- 8, 16, or 32
format_str = '%sint%d' % (('u', '')[self.PixelRepresentation],
                          self.BitsAllocated)
try:
    numpy_format = numpy.dtype(format_str)
print numpy_format
except TypeError:
print "Data type not understood by NumPy!"
print format_str
    msg = ("Data type not understood by NumPy: "
           "format='%s', PixelRepresentation=%d, BitsAllocated=%d")
    raise TypeError(msg % (numpy_format, self.PixelRepresentation,
                    self.BitsAllocated))

# Have correct Numpy format, so create the NumPy array
arr = numpy.fromstring(self.PixelData, numpy_format)

# XXX byte swap - may later handle this in read_file!!?
if need_byteswap:
    arr.byteswap(True)  # True means swap in-place, don't make a new copy
# Note the following reshape operations return a new *view* onto arr, but don't copy the data
if 'NumberOfFrames' in self and self.NumberOfFrames > 1:
    if self.SamplesPerPixel > 1:
        arr = arr.reshape(self.SamplesPerPixel, self.NumberOfFrames, self.Rows, self.Columns)
    else:
        arr = arr.reshape(self.NumberOfFrames, self.Rows, self.Columns)
else:
    if self.SamplesPerPixel > 1:
        if self.BitsAllocated == 8:
            arr = arr.reshape(self.SamplesPerPixel, self.Rows, self.Columns)
        else:
            raise NotImplementedError("This code only handles SamplesPerPixel > 1 if Bits Allocated = 8")
    else:
        arr = arr.reshape(self.Rows, self.Columns)
return arr

When I print the variable format_str, I get uint12. Unfortunately I am not able to solve this bug. Is there anything I can do for solving that?
Even if I remove all print commands (I added them for debug) I get the same error.


Solution

  • There are two problems here. First, a bug in pydicom: in raising the error, it is incorrectly using numpy_format, which is undefined. It should use format_str. I'll add an issue to correct this.

    The second problem is that the file claims to have BitsAllocated of 12, which is very unusual. DICOM files typically have 12-bit pixels values but use 16-bits per pixel in the file.

    You can check what it is really allocating by comparing the Rows and Columns to the size of the pixel data. For a single frame image (below example uses pydicom's CT_small.dcm sample file):

    >>> len(ds.PixelData)
    32768
    >>> ds.Rows * ds.Columns * 2  # 2 bytes for 16-bit allocation
    32768
    

    If the image has multiple frames then you would have to multiply the number of frames as well. Similarly for SamplesPerPixel.

    If the size of pixel data matches as above using 2 bytes per pixel, then you can correct your problem by setting ds.BitsAllocated to 16 before asking for pixel_array.