failure to use the opencv based decompressors in dcm4che 5.21.0

382 views
Skip to first unread message

stephen fogarasi

unread,
Mar 30, 2020, 2:20:07 PM3/30/20
to dcm4che

Im writing some code that reads a dicom file (jpeg baseline) and Im getting a failure in my code - a dead stop actually. 
Im trying to use the image decompressors with dcm4che 5.21.0 (also tried 5.22.0). But I am having problems (at least I think that's problem) configuring the java opencv libraries and dlls.

I get the debug trace coming out as
....
DEBUG DicomImageReader - Decompressor: org.dcm4che3.opencv.NativeImageReader
DEBUG DicomImageReader - Start decompressing frame #1
Mar 30, 2020 12:30:32 PM org.opencv.osgi.OpenCVNativeLoader init
INFO: Successfully loaded OpenCV native library.

where it stops dead, it dies here :

java.lang.NoSuchMethodError: org.opencv.imgcodecs.Imgcodecs.dicomJpgMatRead(Lorg/opencv/core/Mat;II)Lorg/opencv/core/Mat;
at org.dcm4che3.opencv.NativeImageReader.getNativeImage(NativeImageReader.java:287)
at org.dcm4che3.opencv.NativeImageReader.read(NativeImageReader.java:251)
at org.dcm4che3.imageio.plugins.dcm.DicomImageReader.read(DicomImageReader.java:464)
I believe I have the correct java.library.path configured, pointing to the correct library (on my windows 10 system that is C:\bin\dcm4che\dcm4che-5.21.0\lib\win-x86_64) with the correct native dll (opencv_java.dll).
I was getting a different error when setting the path incorrectly.

This is my code, pretty simple :

    public byte[] getCompressedImageBytes(DicomInputStream dicomStream, int index) throws IOException {

        byte[] imageBytes = null;

        if (dicomStream != null) {
            Iterator<ImageReader> iter = ImageIO.getImageReadersByFormatName("DICOM");
            if (iter != null) {
                DicomImageReader reader = (DicomImageReader) iter.next();
                try {
                    reader.setInput(dicomStream);
                    ImageReadParam params = reader.getDefaultReadParam();
// ....DIES IN HERE...
                    java.awt.image.BufferedImage bi = reader.read(index, params);
                    reader.dispose();

                    imageBytes = ((DataBufferByte) bi.getData().getDataBuffer()).getData();
                    
                } catch ( Exception e ) {
                String msg = "Error ! Exception thrown getting imageBytes : " + e.getMessage();
                logger.error( msg );
                throw new IOException ( msg );
                } finally {
                    reader.dispose();
                }
            }
            else {
                String msg = "Error ! no codec has been found to handle this DICOM image";
                logger.error(msg);
                throw new IOException(msg);
            }
        }
        else {
            logger.error("Error ! Dicom stream is null, should not get this far!");
        }

        return imageBytes;
    }

Any idea what I am missing ?

thx

Nicolas Roduit

unread,
Apr 1, 2020, 2:55:14 AM4/1/20
to dcm4che
First, look at this example for reading an image.

There's a problem with the method signature. There has been a change in native method parameters. It's as if the native library has an old API. Check that the native dependency matches the dependency distributed in the package.  

stephen fogarasi

unread,
May 16, 2020, 7:55:51 PM5/16/20
to dcm4che
Sorry for long delay

Yes that was it, there was a mixup in the api versions.
But I am unable to decompress dicom files to full pixel depth.  I start with a 512 x 512 x 16 bit monochrome2 1.2.840.10008.1.2.1 dicom image, The size the decompressed file is half of what I expect, as if it did some short to byte conversion :


    public byte[] getCompressedImageBytes(File input, int index) throws IOException {
        byte[] imageBytes = null;
        if (input != null) {
            try {

                Iterator<ImageReader> iter = ImageIO.getImageReadersByFormatName("DICOM");
                if (iter != null) {
                    DicomImageReader reader = (DicomImageReader) iter.next();
                    try {
                        byte[] data = Files.readAllBytes(input.toPath());
                        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(data);
                        DicomInputStream dicomStream = new DicomInputStream(byteArrayInputStream);
                        reader.setInput(dicomStream);
                        BufferedImage bi = reader.read(index, reader.getDefaultReadParam());
                        reader.dispose();
                        int numBanks = ((DataBufferByte) bi.getData().getDataBuffer()).getNumBanks();
                        imageBytes = ((DataBufferByte) bi.getData().getDataBuffer()).getData();
                    }
                    finally {
                        reader.dispose();
                    }
                }
                else {
                    String msg = "Error ! no codec has been found to handle this DICOM image";
                    logger.error(msg);
                    throw new IOException(msg);
                }
            }
            catch (IOException e) {
                String msg =
                        "Error ! IOException encountered getting decompressed packed pixel stream from File descriptor : "
                                + e.getMessage();

                logger.error(msg);
                throw new IOException(msg);
            }
        }
        else {
            logger.error("Error ! file is null, should not get this far !");
        }
        return imageBytes;
    }


in my example
numRows : 512, numColumns : 512, expectedDataSize : 524288, actualDataSize in imageBytes : 262144

Whats going on ? I must be missing something. The only time this works for me is when I have 3 bytes RGB image (jpeg or raw, both work), but any gray scale depth other than 8 always fails to get the proper size. I did try to unpack the byte array to shorts to see what the number were, but they were nonsense.

Nicolas Roduit

unread,
May 17, 2020, 2:16:42 AM5/17/20
to dcm4che
This is normal because the reader function returns the final image rendering (which is an 8 bit/sample image that can be displayed on a screen) by applying the different LUTs (Modality LUT, VOI LUT and Presentation LUT).

I'm working in the next major version of toolkit to provide an API to get different types of images (raw, modalityLUT, VoiLUT/PresentationLUT). For example, it is not meaningful to get the raw pixels of a CT image, it is best to apply Modality LUT for getting the Hounsfield pixel values (16 bit/pixel).

stephen fogarasi

unread,
May 17, 2020, 8:56:42 AM5/17/20
to dcm4che
Thanks for the fast reply

 I was hoping this was a generic way to get access to the OpenCV image converters and a clean interface to pulling the raw pixels from a dicom image no matter what the transfer syntax.
 
I still have to get to the raw decompressed pixel data, some byte or short array, for our processing. Do you have an example of how I can do that for a compressed tsx that is currently available in 5.21 or 5.22 ?


thanks again

Nicolas Roduit

unread,
May 19, 2020, 4:24:39 AM5/19/20
to dcm4che
You can get the raw image by replacing:
java.awt.image.BufferedImage bi = reader.read(index, params);

with
java.awt.image.BufferedImage bi = reader.readRaster(index, params);

Be careful, the raw image does not give the appropriate values according to the type of modality.
Reply all
Reply to author
Forward
0 new messages