如何使用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
相关产品推荐
相关产品推荐

