I need to use the GDCM for converting DICOM images to PNG-format. While this example works, it does not seem to take the LUT into account and thus I get a mixture of inverted/non-inverted images. While I'm familiar with both C++ and Python I can't quite grasp the black magic inside the wrapper. The documentation is purely written in C++ and I need some help in connecting the dots.
The main task
Convert the following section in the example:
def gdcm_to_numpy(image):
....
gdcm_array = image.GetBuffer()
result = numpy.frombuffer(gdcm_array, dtype=dtype)
....
to something like this:
def gdcm_to_numpy(image):
....
gdcm_array = image.GetBuffer()
lut = image.GetLUT()
gdcm_decoded = lut.Decode(gdcm_array)
result = numpy.frombuffer(gdcm_decoded, dtype=dtype)
....
Now this gives the error:
NotImplementedError: Wrong number or type of arguments for overloaded function 'LookupTable_Decode'.
Possible C/C++ prototypes are:
gdcm::LookupTable::Decode(std::istream &,std::ostream &) const
gdcm::LookupTable::Decode(char *,size_t,char const *,size_t) const
From looking at the GetBuffer definition I guess the first parameter is the assigned variable bool GetBuffer(char *buffer) const;
. I guess that the latter 4-argument version is the one I should aim for. Unfortunately I have no clue to what the size_t
arguments should be. I've tried with
gdcm_in_size = sys.getsizeof(gdcm_array)
gdcm_out_size = sys.getsizeof(gdcm_array)*3
gdcm_decoded = lut.Decode(gdcm_out_size, gdcm_array, gdcm_in_size)
also
gdcm_in_size = ctypes.sizeof(gdcm_array)
gdcm_out_size = ctypes.sizeof(gdcm_array)*3
gdcm_decoded = lut.Decode(gdcm_out_size, gdcm_array, gdcm_in_size)
but with no success.
ImageApplyLookupTable
according to @malat's suggestion...
lutfilt = gdcm.ImageApplyLookupTable();
lutfilt.SetInput( image );
if (not lutfilt.Apply()):
print("Failed to apply LUT")
gdcm_decoded = lutfilt.GetOutputAsPixmap()\
.GetBuffer()
dtype = get_numpy_array_type(pf)
result = numpy.frombuffer(gdcm_decoded, dtype=dtype)
...
Unfortunately I get "Failed to apply LUT" printed and the images are still inverted. See the below image, ImageJ suggests that it has an inverting LUT.
As a simple solution, I would apply the LUT first. In which case you'll need to use ImageApplyLookupTable. It internally calls the gdcm::LookupTable API. See for example.
Of course the correct solution would be to pass the DICOM LUT and convert it to a PNG LUT.
Update: now that you have posted the screenshot. I understand what is going on on your side. You are not trying to apply the DICOM Lookup Table, you are trying to change the rendering of two different Photometric Interpration DICOM DataSet, namely MONOCHROME1 vs MONOCHROME2.
In this case you can change that using software implementation via the use of: gdcm.ImageChangePhotometricInterpretation. Technically this type of rendering is best done using your graphic card (but that is a different story).