网上关于相关系列的文章非常的零散,特别不方便查找,于是查看img2dcm的源码,并将其提取出来作为项目需要,特记录于此。
前提
在dcm文件中,bmp格式图片和jpg格式图片保存方式完全不同,无压缩的bmp图片是直接将像素信息以tag:value的形式存储在dcm文件中,而有压缩的jpg图片则是先将图片的像素点信息插入进DcmPixelSequence中,然后将DcmPixelSequence以tag:value的形式存储在dcm文件中。
具体含义,便用代码分析,边解释。
在具体分析之前,先将主体代码贴下来,如下:
DcmFileFormat *fileFormat = new DcmFileFormat();
DcmDataset *dataSet = fileFormat->getDataset();
I2DImgSource *imgSource = 0;
if(imgName.endsWith("jpg", Qt::CaseInsensitive)) {
imgSource = new I2DJpegSource();
}
else if(imgName.endsWith("bmp", Qt::CaseInsensitive)) {
imgSource = new I2DBmpSource();
}
std::string temp = imgName.toStdString();//注:这句和下一句不可和为一句,否则,转换为char*会失败
const char *value = temp.c_str();
imgSource->setImageFile(OFString(value));
Uint16 samplesPerPixel, rows, cols, bitsAlloc, bitsStored, highBit, pixelRepr, planConf;
Uint16 pixAspectH =1; Uint16 pixAspectV = 1;
OFString photoMetrInt;
E_TransferSyntax outputTS = EXS_Unknown;
char* pixData = 0;
Uint32 length;
OFCondition cond = imgSource->readPixelData(rows, cols,
samplesPerPixel, photoMetrInt, bitsAlloc, bitsStored, highBit, pixelRepr,
planConf, pixAspectH, pixAspectV, pixData, length, outputTS);
if(cond.bad()) {
qDebug()<<"read image data failed:"<<cond.text();
return false;
}
DcmXfer transport(outputTS);
if (transport.isEncapsulated()) {
jpg格式处理
}
else {
bmp格式处理
}
其中,基类I2DImgSource就要根据输入文件格式不同,分别予以不同的初始化。然后插入像素信息。
BMP格式
直接将像素信息添加到dataSet中即可:
dataSet->putAndInsertUint8Array(DCM_PixelData, OFreinterpret_cast(Uint8*, pixData), length);
JPG格式
详细解释,如图所示:
由此可见,在插入像素信息时,先插入4个像素的tag,然后插入像素长度,然后插入像素值。所以,具体代码信息为:
DcmPixelSequence* pixelSequence = new DcmPixelSequence(DCM_PixelSequenceTag);
if (pixelSequence == NULL) {
qDebug()<<"allocate pixel sequence failed"<<endl;
return false;
}
// insert empty offset table into sequence
DcmPixelItem *offsetTable = new DcmPixelItem(DCM_PixelItemTag);
if (offsetTable == NULL) {
delete pixelSequence;
pixelSequence = 0;
qDebug()<<"allocate pixel item tag failed"<<endl;
return false;
}
//插入像素tag
OFCondition status = pixelSequence->insert(offsetTable);
if(status.bad()) {
delete offsetTable;
offsetTable = 0;
delete pixelSequence;
pixelSequence = 0;
qDebug()<<"insert table failed:"<<status.text()<<endl;
return false;
}
// store compressed frame into pixel sequence
DcmOffsetList dummyList;
status = pixelSequence->storeCompressedFrame(dummyList, OFreinterpret_cast(Uint8*,pixData), length, 0);
if (status.bad()) {
delete pixelSequence;
pixelSequence = 0;
qDebug()<<"store frame failed:"<<status.text()<<endl;
return false;
}
// insert pixel data attribute incorporating pixel sequence into dataset
DcmPixelData *pixelData = new DcmPixelData(DCM_PixelData);
if (pixelData == NULL) {
delete pixelSequence;
pixelSequence = 0;
qDebug()<<"allocate DcmPixelData failed"<<endl;
return false;
}
/* tell pixel data element that this is the original presentation of the pixel data
* pixel data and how it compressed
*/
pixelData->putOriginalRepresentation(outputTS, NULL, pixelSequence);
status = dset->insert(pixelData, OFTrue);
if (status.bad()) {
delete pixelData;
pixelData = 0; // also deletes contained pixel sequence
qDebug()<<"put origin failed:"<<status.text()<<endl;
return false;
}
status = dset->chooseRepresentation(outputTS, NULL);
return true;
最后才将相关信息保存到dcm中。注意,此时在保存成dcm文件时,E_TransferSyntax信息一定要和outputTS的信息保持一致,否则,有可能出现保存出来的dcm文件像素信息丢失。
具体的源代码,见CSDN链接:
http://download.csdn.net/detail/syz9011/9261663
注意,该链接内文件中,并未给出PatientData和ExaminationData源代码,里面只是常见的get和set,请各位自行去掉。或者,直接将里面用到该类的get的地方,替换为任意值即可。