Problem with getOutputdata()

All other questions regarding DCMTK

Moderator: Moderator Team

Post Reply
Message
Author
konis
Posts: 28
Joined: Mon, 2015-11-23, 16:05

Problem with getOutputdata()

#1 Post by konis »

Hi,

I have a problem where I get strange colors when I try to get the pixel data from a single-frame US image file (UID_UltrasoundImageStorage, 1.2.840.10008.5.1.4.1.1.6.1) with EXS_JPEGProcess14SV1TransferSyntax (1.2.840.10008.1.2.4.70) Transfer Syntax. To get an idea, the black background of the image comes out as 50% green and the white letters come out as magenta. Using the dcmj2pnm command line tool I get a .bmp file with the correct colors.

A stripped down version of the code I use to read the pixels follows:

Code: Select all

const char *srcPath = "full path to image file";

unsigned long accessFlags = CIF_DecompressCompletePixelData;

DicomImage *dcmImage = new DicomImage( srcPath, accessFlags, 0, 1 );    // get the first frame

if ((dcmImage != NULL) && (dcmImage->getStatus() == EIS_Normal))
{
    unsigned long frameWidth = dcmImage->getWidth();    // width is 1024
    unsigned long frameHeight = dcmImage->getHeight();    // height is 768
    int pixelDepth = dcmImage->getDepth();    // pixelDepth is 8 for the problem file
    
    unsigned long dataSize = dcmImage->getOutputDataSize( pixelDepth );    // datasize is 2359296 for 1024x768 RGB image
	
    Uint8 *pixelData = (Uint8 *) malloc( dataSize );
	
    dcmImage->hideAllOverlays( 0 );    // don't render overlays
    dcmImage->hideAllOverlays( 1 );    // don't render overlays
	
    int getErr = dcmImage->getOutputData( pixelData, dataSize, 8, 0, 0 );
    if (getErr != 0)
    {
        // access/copy the frame pixels
    }
}
I am using the dcmtk-3.6.1_20150924 version of the toolkit on the latest Mac OSX 10.11 and the code above works fine with monochrome images with the same Transfer Syntax.

Is there something I am doing wrong in my code, or, is this a problem with getOutputData() and I should get the frame pixels using a lower level call ?

Thanks,
Christos

Michael Onken
DCMTK Developer
Posts: 2049
Joined: Fri, 2004-11-05, 13:47
Location: Oldenburg, Germany
Contact:

Re: Problem with getOutputdata()

#2 Post by Michael Onken »

Hi Christos,

what's the color model (Photometric Interpretation)?

Also, try looking into the output of dcm2pnm -d in order to see the steps dcm2pnm applies in order to render the image correctly (maybe it corrects some issues automatically).

Best,
Michael

konis
Posts: 28
Joined: Mon, 2015-11-23, 16:05

Re: Problem with getOutputdata()

#3 Post by konis »

Michael,

Photometric Interpretation is RGB and here is the tool debug output:

Code: Select all

D: $dcmtk: dcmj2pnm v3.6.1 DEV $
D: 
I: reading DICOM file: /Users/konis/Desktop/Brooks problem 19Nov2015/Image-39.dcm
D: DcmMetaInfo::checkAndReadPreamble() TransferSyntax="Little Endian Explicit"
D: DcmDataset::read() TransferSyntax="JPEG Lossless, Non-hierarchical, 1st Order Prediction"
I: preparing pixel data
D: transfer syntax of DICOM dataset: JPEG Lossless, Non-hierarchical, 1st Order Prediction (1.2.840.10008.1.2.4.70)
D: Start of Image
D: Unknown APP0 marker (not JFIF), length 13
D: Miscellaneous marker 0xfe, length 20
D: Define Huffman Table 0x00
D: Define Huffman Table 0x01
D: Define Huffman Table 0x02
D: Start Of Frame 0xc3: width=1024, height=768, components=3
D:     Component 1: 1hx1v q=0
D:     Component 2: 1hx1v q=0
D:     Component 3: 1hx1v q=0
D: Start Of Scan: 3 components
D:     Component 1: dc=0 ac=0
D:     Component 2: dc=1 ac=0
D:     Component 3: dc=2 ac=0
D:   Ss=1, Se=0, Ah=0, Al=0
D: End Of Image
D: decompressed complete pixel data in memory: 2359296 bytes
D: reading uncompressed pixel data completely into memory
D: convert input pixel data: case 2a (simple mask)
D: detach pixel data
I: writing frame 1 to /Users/konis/Desktop/Brooks problem 19Nov2015/Image-converted24.bmp
I: cleaning up memory
Program ended with exit code: 0

Michael Onken
DCMTK Developer
Posts: 2049
Joined: Fri, 2004-11-05, 13:47
Location: Oldenburg, Germany
Contact:

Re: Problem with getOutputdata()

#4 Post by Michael Onken »

Hi,

ok that does not reveal the problem :/

I have the feeling that this is a color model conversion issue with the file or you are doing something wrong.

To analyze the first case a bit better: Maybe you can try dcmdjpeg on the file (again use -d and look for lines telling something about automatic color space conversion), and then render the output file with DcmImage. Is the result ok or broken, too? Would be weird if it is broken, though.

In the second case: Are you sure to interpret the output RGB data correctly? Note that getOutputData() does not produce BMP file format in memory. Also, some routines for image display (don't know about Mac and your specific library) expect BMP-ordered data as input and not RGB (BMP does not use RGB order but stores in BGR order!). You can also try DicomImage::writeBMP() directly in order to see whether DicomImage rendering works as expected, but again, I expect no errors since dcm2jpnm does the same.

Hope that helps,
Michael

konis
Posts: 28
Joined: Mon, 2015-11-23, 16:05

Re: Problem with getOutputdata()

#5 Post by konis »

Michael Onken wrote:Hi,
To analyze the first case a bit better: Maybe you can try dcmdjpeg on the file (again use -d and look for lines telling something about automatic color space conversion), and then render the output file with DcmImage. Is the result ok or broken, too? Would be weird if it is broken, though.
The result file is ok. I tried converting the file in memory as a "quick and dirty" solution using canWriteXfer() and then chooseRepresentation() on the DcmFileFormat object but I didn't succeed. Is there any sample code for this, or any other pointers?
Michael Onken wrote:In the second case: Are you sure to interpret the output RGB data correctly? Note that getOutputData() does not produce BMP file format in memory.
Yes, of course I don't expect a BMP format in memory. I expect the getOutputData() to give me the pixel bytes in a raw (generic) memory pointer and then to copy them to the appropriate OSX structures for each color mode. For this specific file, I expect 1024 by 768 groups of R, G and B bytes. Is this correct ?

One thing to note is that the jpeg data precision is 11 bit. I got that value by tracing the execution of the dcmj2pnm tool and my call to getOutputData() trying to find any difference in their handling of the image.

Michael Onken
DCMTK Developer
Posts: 2049
Joined: Fri, 2004-11-05, 13:47
Location: Oldenburg, Germany
Contact:

Re: Problem with getOutputdata()

#6 Post by Michael Onken »

konis wrote:
Michael Onken wrote:Hi,
To analyze the first case a bit better: Maybe you can try dcmdjpeg on the file (again use -d and look for lines telling something about automatic color space conversion), and then render the output file with DcmImage. Is the result ok or broken, too? Would be weird if it is broken, though.
The result file is ok.
So dcmdjpeg does not report something on color space conversion, right? No need to respond if not.
konis wrote: I tried converting the file in memory as a "quick and dirty" solution using canWriteXfer() and then chooseRepresentation() on the DcmFileFormat object but I didn't succeed. Is there any sample code for this, or any other pointers?
You must register the JPEG codec before doing this, from dcmdjpeg.cc:

Code: Select all

#include "dcmtk/dcmjpeg/djdecode.h"    /* for dcmjpeg decoders */
//...
// register global decompression codecs
DJDecoderRegistration::registerCodecs(
  opt_decompCSconversion,
  opt_uidcreation,
  opt_planarconfig,
  opt_predictor6WorkaroundEnable);
Default parameters should be fine, i.e. no need to provide them. dcmj2pnm.cc has the same registerCodecs() call.
konis wrote:
Michael Onken wrote:In the second case: Are you sure to interpret the output RGB data correctly? Note that getOutputData() does not produce BMP file format in memory.
Yes, of course I don't expect a BMP format in memory. I expect the getOutputData() to give me the pixel bytes in a raw (generic) memory pointer and then to copy them to the appropriate OSX structures for each color mode. For this specific file, I expect 1024 by 768 groups of R, G and B bytes. Is this correct?
Yes, that is also what I expect.
konis wrote: One thing to note is that the jpeg data precision is 11 bit. I got that value by tracing the execution of the dcmj2pnm tool and my call to getOutputData() trying to find any difference in their handling of the image.
DicomImage should be able to scale your image to any desired output bit depths so I don't think this is a problem (unless you hit a bug in the code).

So, overall, I have no more ideas :) Maybe Jörg, the original author of DicomImage(), can see immediately what is wrong and can help with this thread.

Since dcm2jpnm works out of the box, it is likely that the problem lies in the interpretation of the getOutputData() call. However, if you can't find something, you may send us the file to info at dcmtk dot org for analysis (may take some time...).

Best,
Michael

konis
Posts: 28
Joined: Mon, 2015-11-23, 16:05

Re: Problem with getOutputdata()

#7 Post by konis »

Michael,

Thank you for taking the time to answer my questions. I'll try converting the file in memory and if I don't succeed I'll send you the image file for inspection.

As for converting the pixels, I handle both the original image and the image produced with dcmdjpeg tool the same way. That's why I suspect it is a bug in the getOutputData() since I don't use any special parameters in either case. Let me know if you need the image for your testing anyway.

Best regards,
Christos

Michael Onken
DCMTK Developer
Posts: 2049
Joined: Fri, 2004-11-05, 13:47
Location: Oldenburg, Germany
Contact:

Re: Problem with getOutputdata()

#8 Post by Michael Onken »

Hi,

yes please provide it so I can check it myself.

Thanks,
Michael

konis
Posts: 28
Joined: Mon, 2015-11-23, 16:05

Re: Problem with getOutputdata()

#9 Post by konis »

Good news. I found where the problem was.
In my program I was registering the JPEG codec with:

Code: Select all

DJDecoderRegistration::registerCodecs( EDC_guess );
when I changed that to:

Code: Select all

DJDecoderRegistration::registerCodecs( EDC_photometricInterpretation );
the file displays correctly.

One final question: What is the best (meaning most generic) constant to use with registerCodecs()? From the wording in the header file, I thought, mistakenly as it turned out, it was EDC_guess. Would it be ok to use EDC_photometricInterpretation from now on?

Thanks again,
Christos

P.S. Do you still want the image file? If yes, tell me where I should send it.

Michael Onken
DCMTK Developer
Posts: 2049
Joined: Fri, 2004-11-05, 13:47
Location: Oldenburg, Germany
Contact:

Re: Problem with getOutputdata()

#10 Post by Michael Onken »

Hi,

ah, good news ;)

I would recommend using the default value that registerCodecs(...) uses for this parameter: EDC_photometricInterpretation, i.e. trust that the creator of the file did everything correctly.

No need for the file since the library behaved as expected ;)

Best regards,
Michael

konis
Posts: 28
Joined: Mon, 2015-11-23, 16:05

Re: Problem with getOutputdata()

#11 Post by konis »

Hi again Michael,

After starting to use EDC_photometricInterpretation in registerCodecs(...), I encountered one US multi frame image (Photometric Interpretation RGB, Transfer Syntax 1.2.840.10008.1.2.4.50) in my test samples, that is not displaying correctly. Using the dcmj2pnm tool with no parameters also creates a .bmp file with shifted colors. I tested all E_DecompressionColorSpaceConversion values with this and the initial problem image and compiled a table with my results:

Code: Select all

  
                                  1.2.840.10008.1.2.4.50    1.2.840.10008.1.2.4.70
EDC_photometricInterpretation              bad                       OK
EDC_lossyOnly                              OK                        OK
EDC_always                                 OK                        bad
EDC_never                                  bad                       OK
EDC_guessLossyOnly                         OK                        OK
EDC_guess                                  OK                        bad
I am not very comfortable to switch to using EDC_guessLossyOnly instead of EDC_photometricInterpretation. Should I send you any of the images for testing? The second image was created in 2002 so it could contain some wrong or deprecated values.

Michael Onken
DCMTK Developer
Posts: 2049
Joined: Fri, 2004-11-05, 13:47
Location: Oldenburg, Germany
Contact:

Re: Problem with getOutputdata()

#12 Post by Michael Onken »

Hi,

some vendors just get the value of Photometric Interpretation wrong, so I expect that this is a bug in the image.

At the moment I don't have time to look into the images a bit more deeply, but if you like you can send it to bugs at dcmtk dot org (refer to the forum thread) and me or one of the team has a quick look later.

Best,
Michael

konis
Posts: 28
Joined: Mon, 2015-11-23, 16:05

Re: Problem with getOutputdata()

#13 Post by konis »

Most probably you are right about the image. I'll send it to bugs.

Is there a way (some parameter or compile flag to use) to make DCMTK more tolerant to these kind of image errors, or, alternatively, produce an error result that signals there is a problem with the image? For our viewer application we would prefer to display the correct image and flag it as problematic instead of showing a distorted image. It is nicer to the end user too :?.

Thank you for your time,
Christos

Marco Eichelberg
OFFIS DICOM Team
OFFIS DICOM Team
Posts: 1444
Joined: Tue, 2004-11-02, 17:22
Location: Oldenburg, Germany
Contact:

Re: Problem with getOutputdata()

#14 Post by Marco Eichelberg »

Thanks for the sample image. This is definitly a faulty DICOM image. The compressed JPEG bitstream uses the YCbCr color model, but the DICOM header states "RGB" as Photometric Interpretation (which would be possible, but unusual for a lossy compressed color image). On the command line,

Code: Select all

dcmdjpeg --conv-always <input> <output>
will create a correctly encoded decompressed image, as it "forces" the decoder to apply the YCbCr to RGB conversion, no matter what Photometric Interpretation contains.

On API level, this behaviour can be implemented by passing the constant "EDC_always" as first parameter in the call to DJDecoderRegistration::registerCodecs(). Note however, that this may cause some (very rare) legal DICOM images to be decompressed incorrectly. Alternatively, you can use "--conv-guess" / "EDC_guess" or "--conv-guess-lossy" / "EDC_guessLossyOnly", which enables some heuristics that try to "guess" whether or not the image to be compressed exhibits this specific problem. In the case of your sample images, both heuristics will yield the correct result.

konis
Posts: 28
Joined: Mon, 2015-11-23, 16:05

Re: Problem with getOutputdata()

#15 Post by konis »

Thank you for looking into the image. It helps to know what is the source of the problem.

If you look at one of my previous posts on this thread you'll see that I've already witnessed the problem with the EDC_always flag. I am currently going with the EDC_guessLossyOnly. Do you know of any compelling reason to select EDC_lossyOnly instead of EDC_guessLossyOnly flag in DJDecoderRegistration::registerCodecs() ?

Thanks again,
Christos

Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest