JPEG decompression / save dcm / memory insufficiency

All other questions regarding DCMTK

Moderator: Moderator Team

Post Reply
Message
Author
Vural
Posts: 3
Joined: Tue, 2009-06-16, 13:10

JPEG decompression / save dcm / memory insufficiency

#1 Post by Vural »

Hi all,
I'm a new user of DCMTK and I'm trying to load and register 2 sets of 512x512x508 slices of CT dicom images with the loader I provided below. My dicom data is jpeg compressed and the loader was designed accordingly. When I try to load the data with that loader, my PC with a RAM of 3.2GB turns out to be insufficient. The code cannot allocate enough memory for the data. I need two things at this point:

1) To obtain the jpeg uncompressed version of the data and save them into .dcm files. There seems to be just a line for uncompression:

Code: Select all

 DJDecoderRegistration::registerCodecs(); 
Does the rest of the process go over jpeg uncompressed version of the data after calling registerCodecs? How can I save jpeg uncompressed data into files?

2) To overcome the memory insufficiency problem, which stems from the loader. I couldn't deallocate the datatypes of DCMTK since I have just began dealing with them. delete methods do not work and I couldn't use the clear methods within different classes of DCMTK. Could anyone point me out how to free the memory through the steps within the loader below? If I don't free them step by step, memory allocation problem will remain.


Any kind of solution/suggestion will be appreciated. Thanks in advance.


Code: Select all

DICOMLoader::dicomReader ( char* firstFile, int modal, int numSlices, int loc1, int loc2, int numberPart )
{
      DJDecoderRegistration::registerCodecs(); 
		
		int currentSlice = 0;
		long int numBits;
		long int depth;
		char* fileName = new char[255];

		//converting char* firstFile to string fileNameStr
		string fileNameStr ( firstFile ); 
		
		int lengthOfFileName = fileNameStr.length();
		int numberLength = loc2 - loc1 + 1;
		string numberPartStr = fileNameStr.substr(loc1, numberLength);

		string numberPartStrShort;

		DcmFileFormat *dfile = new DcmFileFormat();


		for ( currentSlice = 0; currentSlice < numSlices; currentSlice++ )
		{
			//this loop searches for the next file, in case file number of the next slice is not equal to (its antecedent's file number + 1)

			while(1)
			{
				stringstream intToStr;
				intToStr << numberPart;
				numberPartStrShort = intToStr.str();
				int numberLength2 = numberPartStrShort.length();
	
				for(int i = 0 ; i < (numberLength-numberLength2); i++)
					numberPartStrShort = "0" + numberPartStrShort;
				
				//update fileName according to the current slice
				fileNameStr.replace ( loc1, numberLength, numberPartStrShort );
	
				//converting string fileNameStr to char* fileName
				strcpy ( fileName, fileNameStr.c_str() );
	
				OFCondition status = dfile->loadFile ( fileName );
	
				numberPart++;

				if(status.good())
				{
					//cout << fileName << endl;
					break;
				}
				
			}

			DcmDataset *ds = dfile->getDataset();

			unsigned long opt_compatibilityMode = CIF_MayDetachPixelData | CIF_TakeOverExternalDataset; 
		
			E_TransferSyntax xfer = ds->getOriginalXfer();
			DicomImage *di = new DicomImage ( dfile, xfer, opt_compatibilityMode, 0, 0); 		
			imWidth = di->getWidth();
			imHeight = di->getHeight();
			numBits = di->getDepth(); //returns number of bits per sample
			
			//determine the image depth according to the bit info
			if ( numBits % 8 == 0 )
				depth = numBits/8;
			else
				depth = ( numBits/8 ) + 1;

			vtkImageData *image = vtkImageData::New();
	
			if ( currentSlice == 0 )
			{
				switch ( depth )
				{			
					case 1:
					{
						image -> SetScalarTypeToUnsignedChar();
						break;
					}
					case 2:
					{
						image -> SetScalarType ( VTK_TYPE_UINT16 );
						break;
					}
					case 3:
					{
						image -> SetScalarType ( VTK_TYPE_UINT32 );
						break;
					}
					case 4:
					{
						image -> SetScalarType ( VTK_UNSIGNED_LONG );
						break;
					}
					case 8:
					{
						image -> SetScalarType ( VTK_DOUBLE );
						break;
					}
					default:
					{
						cout << "Invalid scalar type!" << endl;
					}
				}
			}

			const DiPixel *dmp = di -> getInterData ();	
			const void *pixelData = dmp -> getData();
 			Uint32 *castedPixelData = new Uint32(imWidth*imHeight);
			castedPixelData = (Uint32*)pixelData;	
			image -> SetDimensions ( imWidth, imHeight, 1 );
			image -> SetOrigin ( 0, 0, 0 );
			image -> SetNumberOfScalarComponents ( 1 );
			image -> AllocateScalars();
			image -> Update();
			Sint16* imagePointer = ( Sint16* ) image -> GetScalarPointer(); 		
			imagePointer = ( Sint16* )castedPixelData;
			image -> Update();

			//initialize variable when processing the first slice
			if ( currentSlice == 0 )
			{

				double* spacing = NULL;
				spacing = image->GetSpacing();

				double* origin = NULL;
				origin = image->GetOrigin();

				int* dimension = NULL;
				dimension = image->GetDimensions();
						
				data_scalar->setInitials ( dimension[0], dimension[1], numSlices, spacing[0], spacing[1], spacing[2], origin[0], origin[1], origin[2] );
				data_scalar->createData();
				vtkData = data_scalar->getDataArray();
			}

			for(int m=0; m<imWidth*imHeight; m++)
				vtkData->InsertNextValue (  imagePointer[m] + 1024 );
		}

	// clean up the registered codecs
	DJDecoderRegistration::cleanup();
}

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

Re: JPEG decompression / save dcm / memory insufficiency

#2 Post by Michael Onken »

Hi,
Vural wrote:
1) To obtain the jpeg uncompressed version of the data and save them into .dcm files. There seems to be just a line for uncompression:

Code: Select all

 DJDecoderRegistration::registerCodecs(); 
Does the rest of the process go over jpeg uncompressed version of the data after calling registerCodecs?
The image (jpeg) data is compressed on demand; in your case the demand arises when putting the image data into the DicomImage class which then leads to an internal conversion of the pixel data to uncompressed transfer syntax (format). So during decompression you have the pixel data 2-3 times in memory.
Vural wrote: How can I save jpeg uncompressed data into files?
Look into dcmdjpeg.cc how conversion to an uncompressed DICOM file is achieved (if this is what you want). Mainly it's about calling "chooseRepresentation()" on the dataset for changing the transfer syntax. The file then can be saved with saveFile() on the fileformat.

If you want to have rendered uncompressed pixel data, then use DicomImage to render the (automatically uncompressed) pixel data into a BMP or whatever. Look into dcmj2pnm.cc how this is done -- pretty easy, mainly by calling DicomImage's getOutputData(...).
Vural wrote: 2) To overcome the memory insufficiency problem, which stems from the loader. I couldn't deallocate the datatypes of DCMTK since I have just began dealing with them. delete methods do not work and I couldn't use the clear methods within different classes of DCMTK. Could anyone point me out how to free the memory through the steps within the loader below? If I don't free them step by step, memory allocation problem will remain.
I hope I don't oversee something, but why not allocating the DcmFileFormat for each run of the for loop (ie. allocate DcmFileformat for each file)? Just use the destructor to clean up the memory from old data.

Code: Select all


for ( currentSlice = 0; currentSlice < numSlices; currentSlice++ ) 
{
  // also could do non-dynamic "DcmFileFormat dfile;"?
  DcmFileFormat *dfile = new DcmFileFormat();
  [...]
  if (dfile != NULL)
  {
    delete dfile; dfile = NULL;
  }
} // end for loop
Hope that helps a bit ;-)
Regards,
Michael

Vural
Posts: 3
Joined: Tue, 2009-06-16, 13:10

#3 Post by Vural »

Thank you so much for the workaround you offered Michael, I succeeded to save the JPEG uncompressed version of the data.

Regards
Vural

Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest