You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用DCMTK创建符合要求的多帧DICOM格式图像?

解决DCMTK创建多帧DICOM像素序列的问题

问题根源分析

你的代码存在以下几个关键问题:

  • 未添加多帧DICOM必需的NumberOfFrames标签,DICOM标准要求多帧图像必须声明帧数
  • 注释掉了像素项(Pixel Item)的创建逻辑,导致像素序列为空(#=0)
  • 错误计划使用DcmItem而非DcmPixelItem创建像素项,普通Item无法正确承载像素数据,会导致长度计算异常(出现4294967295的错误长度)

修正后的代码

#include <dcmtk/dcmdata/dctk.h>
#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;

int main() {
    // 生成测试用的2帧图像
    cv::Mat image1(10, 10, CV_8UC1, cv::Scalar(128));
    cv::Mat image2(10, 10, CV_8UC1, cv::Scalar(255));

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

    // 基础DICOM标签设置
    dataset->putAndInsertString(DCM_PatientName, "TestName");
    dataset->putAndInsertString(DCM_PatientSex, "M");
    dataset->putAndInsertUint16(DCM_Rows, image1.rows);
    dataset->putAndInsertUint16(DCM_Columns, image1.cols);
    dataset->putAndInsertString(DCM_PhotometricInterpretation, "MONOCHROME2");
    dataset->putAndInsertUint16(DCM_BitsAllocated, 8);
    dataset->putAndInsertUint16(DCM_BitsStored, 8);
    dataset->putAndInsertUint16(DCM_HighBit, 7);
    dataset->putAndInsertUint16(DCM_PixelRepresentation, 0); // 无符号
    dataset->putAndInsertUint32(DCM_NumberOfFrames, 2); // 关键:声明多帧数量

    // 创建像素序列
    DcmPixelSequence *pixelSeq = new DcmPixelSequence(DCM_PixelData);

    // 处理第一帧像素数据
    Uint8 *pixels1 = new Uint8[image1.rows * image1.cols];
    for (unsigned long i = 0; i < image1.rows; i++) {
        for (unsigned long j = 0; j < image1.cols; j++) {
            pixels1[i * image1.cols + j] = image1.at<uchar>(i, j);
        }
    }
    // 创建第一帧的像素项(必须用DcmPixelItem)
    DcmPixelItem *item1 = new DcmPixelItem(DCM_PixelItem);
    item1->putAndInsertUint8Array(DCM_PixelItem, pixels1, image1.rows * image1.cols);
    pixelSeq->insert(item1); // 将像素项加入序列
    delete[] pixels1; // 释放临时像素数组

    // 处理第二帧像素数据
    Uint8 *pixels2 = new Uint8[image2.rows * image2.cols];
    for (unsigned long i = 0; i < image2.rows; i++) {
        for (unsigned long j = 0; j < image2.cols; j++) {
            pixels2[i * image2.cols + j] = image2.at<uchar>(i, j);
        }
    }
    DcmPixelItem *item2 = new DcmPixelItem(DCM_PixelItem);
    item2->putAndInsertUint8Array(DCM_PixelItem, pixels2, image2.rows * image2.cols);
    pixelSeq->insert(item2);
    delete[] pixels2;

    // 将像素序列插入数据集,使用putAndInsertSequence确保属性正确
    dataset->putAndInsertSequence(DCM_PixelData, pixelSeq);

    // 保存DICOM文件
    OFCondition writeStatus = fileformat.saveFile("multiframe.dcm", EXS_LittleEndianExplicit);
    if (writeStatus.bad()) {
        cout << "Failed to write the DICOM file! Status: " << writeStatus.text() << endl;
        return 1;
    }

    cout << "DICOM file saved successfully." << endl;
    return 0;
}

关键修改点说明

  • 添加NumberOfFrames标签:这是多帧DICOM的核心属性,必须明确声明帧数,否则阅读器无法识别为多帧图像
  • 使用DcmPixelItem创建像素项:DcmPixelItem是DCMTK中专门用于承载像素数据的Item类型,对应DICOM中的(fffe,e000)标签,普通DcmItem无法正确处理像素数据的长度计算
  • 正确插入像素项到序列:创建每个帧的像素项后,必须调用pixelSeq->insert(item)将其加入像素序列,否则序列为空
  • 内存管理:手动分配的像素数组使用后及时释放,而DcmPixelItem和DcmPixelSequence的内存会由数据集自动管理,无需手动delete
  • 使用putAndInsertSequence插入序列:相比insert方法,putAndInsertSequence会确保像素数据的VR(Value Representation)和属性符合DICOM标准

验证结果

生成的DICOM文件用dcmdump查看时,(7fe0,0010)标签会显示:

(7fe0,0010) OB (PixelSequence #=2)
(fffe,e000) pi (100 bytes)
(fffe,e000) pi (100 bytes)
(fffe,e0dd) (SequenceDelimitationItem)

符合你期望的格式,且不会出现长度错误的报错。

内容的提问来源于stack exchange,提问作者Lazyyedi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 02:43:14