DCMTK 学习笔记2 传输语法

2021/08/22 医学影像

传输语法表示了某个dicom在传输过程中的一些状态封装,有三种形式

  • 值表示法(VR):显式VR、 隐式VR
  • 字节顺序: Little Endian、 Big Endian
  • 压缩格式: JPEG/RLE/有损/无损等好几种

如果是压缩文件,则需要先进行解压操作

官方Demo

压缩文件

DJEncoderRegistration::registerCodecs(); // register JPEG codecs
DcmFileFormat fileformat;
if (fileformat.loadFile("test.dcm").good())
{
  DcmDataset *dataset = fileformat.getDataset();
  DcmItem *metaInfo = fileformat.getMetaInfo();
  DJ_RPLossless params; // codec parameters, we use the defaults
 
  // this causes the lossless JPEG version of the dataset to be created
  if (dataset->chooseRepresentation(EXS_JPEGProcess14SV1, &params).good() &&
      dataset->canWriteXfer(EXS_JPEGProcess14SV1))
  {
    // store in lossless JPEG format
    fileformat.saveFile("test_jpeg.dcm", EXS_JPEGProcess14SV1);
  }
}
DJEncoderRegistration::cleanup(); // deregister JPEG codecs

压缩的时候示例采用的是默认参数,这个有多个

默认

DJ_RPLossless params;

常用的

D2RepresentationParameter(
    double compressionRatio = 1,
    Uint32 compressedSize = 0,
    OFBool losslessProcess = OFTrue,
    const OFString &imageComment = "")

这个类有三个参数

  • compressionRatio 压缩比,必须小于1.0,无损压缩时忽略该参数
  • compressedSize 压缩帧大小,以字节为单位,默认为0,非零值将被覆盖,无损压缩时忽略该参数
  • losslessProcess 如果在有损传输语法中也应该使用无损处理,则为真
  • imageComment 要写入jp2k头的注释

压缩某个dicom文件可能会出现这样的错误

Pixel representation cannot be changed

查看源码后得知错误原因可能有

    ......
    if (resultStack.top()->ident() == EVR_PixelData)
    {
        DcmPixelData *pixelData = OFstatic_cast(DcmPixelData *, resultStack.top());
        if (!pixelData->canChooseRepresentation(repType, repParam))
            l_error = EC_CannotChangeRepresentation;
        pixelStack.push(resultStack);
    }
    else
        l_error = EC_CannotChangeRepresentation;
    ......

错误类型正是这个

makeOFConditionConst(EC_CannotChangeRepresentation,  OFM_dcmdata, 14, OF_error, "Pixel representation cannot be changed"     );
  • 可能数据已经是压缩后的,再次压缩会返回失败;
  • 编码器没有找到,可能是没有注册;

解压文件

DJDecoderRegistration::registerCodecs(); // register JPEG codecs
DcmFileFormat fileformat;
if (fileformat.loadFile("test_jpeg.dcm").good())
{
  DcmDataset *dataset = fileformat.getDataset();
 
  // decompress data set if compressed
  if (dataset->chooseRepresentation(EXS_LittleEndianExplicit, NULL).good() &&
      dataset->canWriteXfer(EXS_LittleEndianExplicit))
  {
    fileformat.saveFile("test_decompressed.dcm", EXS_LittleEndianExplicit);
  }
}
DJDecoderRegistration::cleanup(); // deregister JPEG codecs

源码部分代码示例

dcmtk内部初始化时,枚举了所有的压缩类型对应的属性,下面这个是基本数据结构,每个压缩类型对应一个结构体对象

typedef struct
{
    const char         *xferID;
    const char         *xferName;
    E_TransferSyntax    xfer;
    E_ByteOrder         byteOrder;
    E_VRType            vrType;
    E_JPEGEncapsulated  encapsulated;
    Uint32              JPEGProcess8;
    Uint32              JPEGProcess12;
    OFBool              lossy;
    OFBool              retired;
    E_StreamCompression streamCompression;
} S_XferNames;

压缩效果

  • 采用默认压缩参数,使用 EXS_JPEGProcess2_4有损压缩

    DJ_RPLossless params; // codec parameters, we use the defaults

    E_TransferSyntax xfer = EXS_JPEGProcess2_4;

    OFCondition ofResult = dataset->chooseRepresentation(xfer, &params);
    if (ofResult.good() && dataset->canWriteXfer(xfer))
    {
        // store in lossless JPEG format
        OFCondition ofResult = fileformat.saveFile("G:/dicomFile/8_test_jpeg.dcm", xfer);
    }

可以很明显看到图像被压缩的太狠,查看文件大小仅有大概 5KB,原始文件大小288KB

这种方式几乎不会用,因为图像被压缩的太狠,很多关键信息都丢失了

  • 采用自定义压缩参数 使用 EXS_JPEGProcess2_4有损压缩
    int nQuality = 50;
    // this causes the lossless JPEG version of the dataset to be created
    D2RepresentationParameter rpp( nQuality*0.01, OFstatic_cast(Uint32, 1), OFFalse, "");

    OFCondition ofResult = dataset->chooseRepresentation(xfer, &rpp);

这种情况下,压缩后文件大小为 33KB左右,显示效果比上一个好点

常见图像压缩方式

一般默认可以采用 EXS_JPEGProcess2_4进行压缩,如果图像包含Overlay层,则要使用 ` EXS_JPEG2000协议,对于常见的CT,MR,NM,PET等,如果图像宽高小于 1024 情况下可以采用 EXS_JPEGProcess14SV1`协议


作者:鹅卵石
时间:  2021年8月22日
版本:V 0.0.1
邮箱:kevinlq@163.com
版权:本博客若无特别声明,均属于作者原创文章,欢迎大家转载分享。但是,
希望您注明来源,并留下原文地址,这是对作者最大的尊重,也是对知识的尊重。

如果您对本文有任何问题,可以在下方留言,或者Email我.

捐赠

如果觉得分享的内容不错,可以请作者喝杯咖啡.


Show Disqus Comments

Search

    欢迎关注我的微信号

    一个不羁的码农

    不羁的程序员

    转载请注明出处!

    Table of Contents