Multiframe DICOM File Save problem

All other questions regarding DCMTK

Moderator: Moderator Team

Post Reply
Message
Author
alwittta
Posts: 111
Joined: Wed, 2006-03-15, 08:30

Multiframe DICOM File Save problem

#1 Post by alwittta »

Dear Friends

I am trying to save a multiframe DICOM image using DCMTK toolkit.
I am getting in correct image after saving the file.
The image pixel is in RGB format.
Following is my code.
Could any one please tell me whether the problem is with my code?

Code: Select all

DcmFileFormat fileformat; 
DcmDataset *dataset = fileformat.getDataset(); 

dataset->putAndInsertString(DCM_SOPClassUID,		UID_SecondaryCaptureImageStorage);      
	dataset->putAndInsertString(DCM_SOPInstanceUID,		strUID);   

dataset->putAndInsertString(DCM_PatientsName,	"Test Dicom");
dataset->putAndInsertString(DCM_PatientID,"");
dataset->putAndInsertString(DCM_PatientsBirthDate,"");
dataset->putAndInsertString(DCM_PatientsSex,"");
....
....
....
....
....
....
DcmSequenceOfItems oSPSSeq(DCM_ScheduledProcedureStepSequence);

DcmTag oTag(0xfffe, 0xe000, EVR_SQ);
DcmItem oItem( oTag );

for (int n=0; n<FrameCount; n++)
{
      dataset->putAndInsertUint8Array(DCM_PixelData, PixelArray[n], height * width * 3 ); 

      dataset->insert(&oSPSSeq);

}
// now save the file

Jörg Riesmeier
ICSMED DICOM Services
ICSMED DICOM Services
Posts: 2217
Joined: Fri, 2004-10-29, 21:38
Location: Oldenburg, Germany

#2 Post by Jörg Riesmeier »

Short comment: Currently, you are replacing the pixel data each time when you call putAndInsertUint8Array() in the loop. I'm also not sure what the sequence/item stuff is meant for.

alwittta
Posts: 111
Joined: Wed, 2006-03-15, 08:30

#3 Post by alwittta »

Dear Jörg Riesmeier,

Thanks for the reply.

From your Post I understand that the usage of putAndInsertUint8Array function is incorrect.
Could you please tell me, how can I correct this code so that I will get a multiframe DICOM image.

From an earlier post
viewtopic.php?t=497&highlight=putandinsertuint8array
I understand that there is a separator item(0xfffe, 0xe000) between each frame in a multiframe image.
Since the tag 0xfffe, 0xe000 is of VR type VR_SQ
Thats why I created DcmSequenceOfItems object.
Please tell me what is the separator between each frame in a multiframe DICOM image?

Thanks and Regards
Alvin

Jörg Riesmeier
ICSMED DICOM Services
ICSMED DICOM Services
Posts: 2217
Joined: Fri, 2004-10-29, 21:38
Location: Oldenburg, Germany

#4 Post by Jörg Riesmeier »

From your Post I understand that the usage of putAndInsertUint8Array function is incorrect.
Could you please tell me, how can I correct this code so that I will get a multiframe DICOM image.
First, you have to prepare the RGB pixel data for all frames of your image according to part 5 of the DICOM standard. Then you could use putAndInsertUint8Array() to put and insert the memory buffer into the dataset (in a single step).
Please tell me what is the separator between each frame in a multiframe DICOM image?
For uncompressed pixel data there is no separator at all.

alwittta
Posts: 111
Joined: Wed, 2006-03-15, 08:30

#5 Post by alwittta »

Dear Jörg

Thank you for the reply. It is very much informative and pointing me in the correct direction.

could you please tell me, what is the separator for compressed pixel data?

And how can we inform this to putAndInsertUint8Array function?


Thanks and Regards
Alvin

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

#6 Post by Marco Eichelberg »

The putAndInsert-methods are not the right way to create pixel data in DCMTK. See the API of class DcmPixelData which defines methods both for uncompressed and for compressed pixel data. Please note compressed pixel data does NOT use a sequence structure in DICOM - the structure is just similar to a sequence. Use class DcmPixelData to do this correctly. The various codec classes in the toolkit (such as DcmRLEEncoder and DcmRLEDecoder) show how the API is used to create compressed and uncompressed image content.

alwittta
Posts: 111
Joined: Wed, 2006-03-15, 08:30

#7 Post by alwittta »

Dear Marco,

Thanks for the reply.
The putAndInsert-methods are not the right way to create pixel data in DCMTK.
...
Use class DcmPixelData to do this correctly
But putAndInsertUint8Array function initernally calling the DcmPixelData class, am I right?

Thanks and Regards
Alvin

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

#8 Post by Marco Eichelberg »

But putAndInsertUint8Array function initernally calling the DcmPixelData class, am I right?
For pixel data, yes. However, this method causes pixel data to be stored in uncompressed format with OB value representation, and this is a special case that is permitted in DICOM only under very specific circumstances.

alwittta
Posts: 111
Joined: Wed, 2006-03-15, 08:30

#9 Post by alwittta »

Dear Marco,

Thank you very much for the answer.

From your answer I am started coding as following.
Please correct me if i am on the wrong direction

Code: Select all

Create DcmPixelData object

Create a DcmPixelSequence from DcmPixelData 

while (no of frames)
{
    create DcmPixelItem object and insert it to Sequnce object

}
Thanks and Regards
Alvin

alwittta
Posts: 111
Joined: Wed, 2006-03-15, 08:30

#10 Post by alwittta »

Dear friends,

When I try to create a multiframe DICOM image using DcmPixelData class , I got an empty file.

I am having an Uncompressed RGB Multiframe image:

Following is my code:

Code: Select all

DcmFileFormat fileformat;
DcmDataset *dataset = fileformat.getDataset();

dataset->putAndInsertString(DCM_SOPClassUID,      UID_SecondaryCaptureImageStorage);     
   dataset->putAndInsertString(DCM_SOPInstanceUID,      strUID);   

dataset->putAndInsertString(DCM_PatientsName,   "Test Dicom");
dataset->putAndInsertString(DCM_PatientID,"");
dataset->putAndInsertString(DCM_PatientsBirthDate,"");
dataset->putAndInsertString(DCM_PatientsSex,"");
....
....
....
....
....

DcmPixelData *newPixelData = new DcmPixelData(DcmTag(DCM_PixelData, EVR_UL)); 

// OFCondition cond = dataset->insert(newPixelData, OFTrue);


DcmPixelSequence *sequence = new DcmPixelSequence(DcmTag(DCM_PixelData, EVR_OB));

newPixelData->insert(sequence);

OFstatic_cast(DcmPixelData *, newPixelData)->putOriginalRepresentation(EXS_Unknown, NULL, sequence); 

for (int n=0; n<FrameCount; n++)
{
                 DcmPixelItem *newItem = new DcmPixelItem(DcmTag(DCM_Item, EVR_OB));
		if (newItem != NULL)
		{

			sequence->insert(newItem);
			/* put pixel data into the item */
			OFCondition result = newItem->putUint8Array((Uint8 *)image_buffer, sx*sy*3);

			
		}
}

fileformat.saveFile("c:\\test.dcm");
could anyone please tell me what is the wrong with my code?

Thanks and Ragards
Alvin

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

#11 Post by Marco Eichelberg »

Passing the VR explicitly to a new attribute is wrong in most of the cases, especially when you pass the wrong VR as in

Code: Select all

new DcmPixelData(DcmTag(DCM_PixelData, EVR_UL))
. Then, the insert method should never be explicitly called for class DcmPixelData. The call to putOriginalRepresentation with parameter EXS_Unknown will tell the codec that you are storing compressed information, but you don't know which kind of compression that is - not very helpful for the codec. Finally, your list of fragments (pixel items) is missing the offset table. I would suggest that you carefully read the section in DICOM part 5 where the actual encoding of compressed image data is described, and also take a look at one of the encoders in DCMTK which essentially do the same job that your code is supposed to do: to create a compressed image representation within an instance of class DcmPixelData. DcmRLECodecEncoder::encode() in module dcmdata might be a good choice to start with.

alwittta
Posts: 111
Joined: Wed, 2006-03-15, 08:30

#12 Post by alwittta »

Dear Marco

Thank you very much for the reply.
new DcmPixelData(DcmTag(DCM_PixelData, EVR_UL))
I changed this to

Code: Select all

DcmPixelData *newPixelData = new DcmPixelData(DCM_PixelData);
The insert method should never be explicitly called for class DcmPixelData.
And I removed the code

Code: Select all

dataset->insert(newPixelData, OFTrue;
newPixelData->insert(sequence);

OFstatic_cast(DcmPixelData *, newPixelData)->putOriginalRepresentation(EXS_Unknown, NULL, sequence);

for (int n=0; n<FrameCount; n++)
{
                 DcmPixelItem *newItem = new DcmPixelItem(DcmTag(DCM_Item, EVR_OB));
      if (newItem != NULL)
      {

         sequence->insert(newItem);
         /* put pixel data into the item */
         OFCondition result = newItem->putUint8Array((Uint8 *)image_buffer, sx*sy*3);
         
      }
}
fileformat.saveFile("c:\\test.dcm");
And added the code

Code: Select all

DJEncoderRegistration::registerCodecs();
DJ_RPLossless params; // codec parameters, we use the defaults
// this causes the lossless JPEG version of the dataset to be created
dataset->chooseRepresentation(EXS_JPEGProcess14SV1TransferSyntax, &params);
/**/
E_TransferSyntax xfer = DcmXfer(EXS_JPEGProcess14SV1TransferSyntax).getXfer();
DcmPixelSequence *sequence = new DcmPixelSequence(DcmTag(DCM_PixelData, EVR_OB));

// newPixelData->insert(sequence);
OFstatic_cast(DcmPixelData *, newPixelData)->putOriginalRepresentation(xfer, NULL, sequence);
for (int n=0; n<FrameCount; n++)
{
                 DcmPixelItem *newItem = new DcmPixelItem(DcmTag(DCM_Item, EVR_OB));
      if (newItem != NULL)
      {

         sequence->insert(newItem);
         /* put pixel data into the item */
         OFCondition result = newItem->putUint8Array((Uint8 *)image_buffer, sx*sy*3);
         
      }
} 
missing the offset table
I would like to know,in the function

Code: Select all

DJEncoderRegistration::registerCodecs()
there is a default argument
pCreateOffsetTable
Default value is TRUE and by using the call of this function will internally create Off set table, am I right?

But after including these codes chnages also doesn't make any difference.
Could you please provide a sample program on the correct usage of these classes?

Thanks and Regards
Alvin

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

#13 Post by Marco Eichelberg »

would like to know,in the function DJEncoderRegistration::registerCodecs() there is a default argument pCreateOffsetTable. Default value is TRUE and by using the call of this function will internally create Off set table, am I right?
This parameter controls the creation of the offset table when you use the dcmjpeg encoder class to convert an uncompressed DICOM image into a compressed DICOM image. When you try to store compressed fragments directly within a DICOM dataset, you have to compute the offsets and create the offset table on your own.
A sample application that shows the usage of the dcmjpeg API is, of course, dcmcjpeg in dcmjpeg/apps.

Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest