【问题标题】:Multiframe Ultrasound DICOM file creation多帧超声 DICOM 文件创建
【发布时间】:2021-07-19 12:36:12
【问题描述】:

我是 DICOM 和 DCMTK 的新手。我有一组 BITMAP 超声数据,我想将其保存为无损 DICOM 文件。

在将数据加载到队列frame_queue 并为超声多帧图像设置所有必需的 DICOM 必要参数后,我实现了一个循环以将图像添加到 DcmDataset 中,如下所示:

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());

dataset-&gt;chooseRepresentation(EXS_JPEGProcess14, &amp;params); 的调用引发错误:

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

DICOM 文件已保存,但为空。

有谁知道是什么导致了这个错误?

【问题讨论】:

    标签: c++ c++17 dicom dcmtk


    【解决方案1】:

    只是一个猜测,但您正在以未压缩的表示形式创建数据集。在这种情况下,像素数据不得表示为帧序列。您应该尝试直接在 DcmPixelData 元素上调用 putUint8Array(),而不是向其中插入序列。

    当您调用DcmDataset::chooseRepresentation()时,DCMTK 会将这种编码方式更改为您想要直接实现的方式。

    对于未压缩的像素数据,不允许使用带有序列的“封装”像素数据编码,我怀疑这就是DcmDataset::chooseRepresentation()抱怨“没有找到预期的东西”的原因。

    【讨论】:

    • 谢谢 kritzel_sw,我会调查一下,然后再回来,但首先要说一句,据我了解,putUint8Array() 仅用于单帧,因为多次调用它会删除以前的图像.或者我应该给包含所有帧的缓冲区一次? link
    • @firehelm:是的。所有帧的一个缓冲区将是一种可能的解决方案。如果您担心内存消耗,也可以从 DcmInputStream 中逐块分配和属性值(如果是像素数据:逐帧)。
    • 内存应该不是问题,因为我将长流划分为子文件,因此我控制缓冲区中存在的图像数量。现在,如果我创建一个 DICOM 缓冲区,我猜我应该将对象中的图像复制为Uint8[imageSize * nbFrames] imagesBuffer,然后使用对象DcmPixelData* dcmData 并将帧添加为result = dcmData-&gt;putUint8Array(imagesBuffer, imageSize * nbFrames).good();?但在这种情况下,dcmtk 如何定义帧之间的分隔?
    • 是的,完全正确。仅在封装表示中才需要帧之间的分隔。对于未压缩的多帧数据,帧的大小由相应的标题元素定义:Rows、Columns、BitsAllocated 和(对于彩色图像)SamplesPerPixel
    • 所以我认为这目前进展顺利,因为新错误是 True lossless encoder: Unable to get relevant attributes from dataset 我猜一些 DICOM 标签丢失了,我正在扫描我拥有的其他 Multiframe US 的标签看看哪些丢失并找到(0028,0004) CS RGB # 1, 4 Photometric Interpretation 调查这个我看到RGB 可以替换为PALETTE COLOR。我猜我可以避免将调色板颜色图像转换为 RGB 图像。
    【解决方案2】:

    所以我终于让它工作了:

    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); 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多