firehelm
firehelm

Reputation: 49

Multiframe Ultrasound DICOM file creation

I am new at DICOM and DCMTK. I have a set of BITMAP Ultrasound data that I would like to save as a lossless DICOM file.

After loadding the data in a queue frame_queue and setting all the mandatory DICOM necessary parameters for Ultrasound Multiframe images I realise a loop to add the images in the DcmDataset as follows:

std::unique_ptr<DcmDataset> dataset;

/*** 
DICOM parameters A setted not added here as many parameters are set
***/


std::shared_ptr<unsigned char[]> frame;
std::shared_ptr<RGBQUAD[]> colorTable;

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

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

while (frame_queue.popFrame(frame, colorTable)) // we extract a new frame from the queue
{
    DcmPixelItem* newItem = new DcmPixelItem(DcmTag(DCM_Item, EVR_OB));
    if (newItem != NULL)
    {
        sequence->insert(newItem);
        /* put pixel data into the item */
        std::shared_ptr<Uint8[]> newDCMFrame;
        
        colorTableToRGB(frame, colorTable, newDCMFrame, m_frameWidth, m_frameHeight);
        result = newItem->putUint8Array((Uint8*)newDCMFrame.get(), m_frameHeight * m_frameWidth * 3).good(); // this returns true in my test
        frame.reset();
        colorTable.reset();
    }
}

dataset->chooseRepresentation(EXS_JPEGProcess14, &params); 
dataset->saveFile(path.c_str());

The call of dataset->chooseRepresentation(EXS_JPEGProcess14, &params); raises the error:

DcmDataset: Wrong class for pixel data element, cannot change representation

A DICOM File is saved but it is empty.

Does anyone know what's causing this error?

Upvotes: 0

Views: 1051

Answers (2)

firehelm
firehelm

Reputation: 49

So I finaly got it to work:

std::unique_ptr<DcmDataset> dataset;

/*** 
DICOM parameters A setted not added here as many parameters are set
***/


std::shared_ptr<unsigned char[]> frame;
std::shared_ptr<RGBQUAD[]> colorTable;

DJEncoderRegistration::registerCodecs();
DJ_RPLossless params; // codec parameters, we use the defaults
// this causes the lossless JPEG version of the m_dataset to be created
    
/**/
E_TransferSyntax xfer = DcmXfer(EXS_JPEGProcess14).getXfer();

DcmPixelData* newPixelData = new DcmPixelData(DCM_PixelData);
dataset->insert(newPixelData , OFTrue);


bool result = true;
static const int imageSize = m_frameWidth * m_frameHeight * 3;
std::shared_ptr<Uint8[]> imagesBufferPtr(new Uint8[imageSize * m_nbFrames], array_deleter<Uint8>());

std::vector<std::vector<Uint8>> dataImages(m_nbFrames, std::vector<Uint8>(imageSize));

int frameId = 0;

while (this->popFrame(frame, colorTable) == cwlibdicom::frameBufferStatus::BUFFER_SUCCESS && result)
{
    Uint8 *img = imagesBufferPtr.get();
    img = &img[frameId];
    colorTableToRGB(frame, colorTable, img, m_frameWidth, m_frameHeight);

    std::memcpy(&imagesBufferPtr.get()[frameId * imageSize], img.data(), imageSize);

    frameId++;
    frame.reset();
    colorTable.reset();
}
result = newPixelData->putUint8Array(imagesBufferPtr.get(), imageSize * m_nbFrames).good();
header->setProperty(DCM_NumberOfFrames, nb_frame);
header->setProperty(DCM_SamplesPerPixel, "3");
header->setProperty(DCM_PhotometricInterpretation, "RGB");
header->setProperty(DCM_Rows, m_imageHeight);
header->setProperty(DCM_Cols, m_imageWidth);
header->setProperty(DCM_BitsAllocated, "8");
header->setProperty(DCM_BitsStored, "8");
header->setProperty(DCM_HighBit, "7");
header->setProperty(DCM_PixelRepresentation, "0");
header->setProperty(DCM_FrameIncrementPointer, "(0018, 1065)\\(F9E4, 3317)"); // Found this in a multiframe image that already existed.

dataset->chooseRepresentation(EXS_JPEGProcess14, &params); 
dataset->saveFile(path.c_str(), EXS_JPEGProcess14); 

Upvotes: 1

Markus Sabin
Markus Sabin

Reputation: 4013

Just a guess but you are creating the dataset in uncompressed representation. In this case, the pixel data must NOT be represented as a sequence of frames. You should try calling putUint8Array() directly on the DcmPixelData element instead of inserting sequences to it.

DCMTK will change that way of encoding to the one you want to achieve directly, when you call DcmDataset::chooseRepresentation().

For uncompressed pixel data, it is not allowed to used the "encapsulated" pixel data encoding with sequences, and I suspect that this is why DcmDataset::chooseRepresentation() complains about "not finding what was expected".

Upvotes: 1

Related Questions