当前位置: 首页 > 工具软件 > DCMTK > 使用案例 >

DCMTK 中源代码中使用 Overlay 的例子

卢志行
2023-12-01

在查找 Dicom 中的 Overlay 相关的 Tag 使用方法时,基本上网上能找到的都是 Overlay Tag 的说明。使用 DCMTK 对 Overlay 读写的实例代码很少。


  1. 收集的几个三方库关于 overlay 的使用
  • leadtools 关于 overlay 使用
    https://www.leadtools.com/help/sdk/v21/dicom/api/class-example.html#!

  • pydicom关于 overlay 使用
    https://pydicom.github.io/pydicom/dev/old/working_with_overlays.html

  • ciods关于 overlay 使用
    https://dicom.innolitics.com/ciods/ct-image/overlay-plane/60xx0050

  • clearcanvas 关于 overlay 使用
    https://documentation.clearcanvas.ca/Documentation/DevelopersGuide/1_5_SP1/index.html?add_a_dicom_bitmap_overlay_plane.htm


  1. 示例源代码
    后来,发现最好的示例代码,就是 DCMTK 的 源代码,而源代码中最好的示例,就是下面的一个类:DVPSOverlay。为了避免再次找源代码,就直接把源代码摘抄如下:
/*
 *
 *  Copyright (C) 1998-2018, OFFIS e.V.
 *  All rights reserved.  See COPYRIGHT file for details.
 *
 *  This software and supporting documentation were developed by
 *
 *    OFFIS e.V.
 *    R&D Division Health
 *    Escherweg 2
 *    D-26121 Oldenburg, Germany
 *
 *
 *  Module: dcmpstat
 *
 *  Author: Marco Eichelberg
 *
 *  Purpose:
 *    classes: DVPSOverlay
 *
 */

#include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
#include "dcmtk/dcmpstat/dvpsov.h"
#include "dcmtk/ofstd/ofstring.h"
#include "dcmtk/dcmpstat/dvpsdef.h"     /* for constants and macros */


/* --------------- class DVPSOverlay --------------- */

DVPSOverlay::DVPSOverlay()
: overlayGroup(0)
, overlayRows(DCM_OverlayRows)
, overlayColumns(DCM_OverlayColumns)
, overlayType(DCM_OverlayType)
, overlayOrigin(DCM_OverlayOrigin)
, overlayBitsAllocated(DCM_OverlayBitsAllocated)
, overlayBitPosition(DCM_OverlayBitPosition)
, overlayData(DCM_OverlayData)
, overlayDescription(DCM_OverlayDescription)
, overlayLabel(DCM_OverlayLabel)
{
}

DVPSOverlay::DVPSOverlay(const DVPSOverlay& copy)
: overlayGroup(copy.overlayGroup)
, overlayRows(copy.overlayRows)
, overlayColumns(copy.overlayColumns)
, overlayType(copy.overlayType)
, overlayOrigin(copy.overlayOrigin)
, overlayBitsAllocated(copy.overlayBitsAllocated)
, overlayBitPosition(copy.overlayBitPosition)
, overlayData(copy.overlayData)
, overlayDescription(copy.overlayDescription)
, overlayLabel(copy.overlayLabel)
{
}

DVPSOverlay::~DVPSOverlay()
{
}

OFCondition DVPSOverlay::read(DcmItem &dset, Uint8 ovGroup, Uint8 asGroup)
{
  OFCondition result = EC_Normal;
  DcmStack stack;

  if (asGroup==0xFF) asGroup=ovGroup;
  overlayGroup = asGroup;
  Uint16 gtag = 0x6000 + ovGroup;

  overlayRows.setGTag(gtag);
  overlayColumns.setGTag(gtag);
  overlayType.setGTag(gtag);
  overlayOrigin.setGTag(gtag);
  overlayBitsAllocated.setGTag(gtag);
  overlayBitPosition.setGTag(gtag);
  overlayData.setGTag(gtag);
  overlayDescription.setGTag(gtag);
  overlayLabel.setGTag(gtag);
  READ_FROM_DATASET(DcmUnsignedShort, EVR_US, overlayRows)
  READ_FROM_DATASET(DcmUnsignedShort, EVR_US, overlayColumns)
  READ_FROM_DATASET(DcmCodeString, EVR_CS, overlayType)
  READ_FROM_DATASET(DcmSignedShort, EVR_SS, overlayOrigin)
  READ_FROM_DATASET(DcmUnsignedShort, EVR_US, overlayBitsAllocated)
  READ_FROM_DATASET(DcmUnsignedShort, EVR_US, overlayBitPosition)
  READ_FROM_DATASET(DcmOverlayData, EVR_OverlayData, overlayData)
  READ_FROM_DATASET(DcmLongString, EVR_LO, overlayDescription)
  READ_FROM_DATASET(DcmLongString, EVR_LO, overlayLabel)

  /* Now perform basic sanity checks and adjust use flags */
  if (overlayRows.getLength() == 0)
  {
    result=EC_IllegalCall;
    DCMPSTAT_WARN("presentation state contains an overlay with overlayRows absent or empty");
  }
  else if (overlayRows.getVM() != 1)
  {
    result=EC_IllegalCall;
    DCMPSTAT_WARN("presentation state contains an overlay with overlayRows VM != 1");
  }

  if (overlayColumns.getLength() == 0)
  {
    result=EC_IllegalCall;
    DCMPSTAT_WARN("presentation state contains an overlay with overlayColumns absent or empty");
  }
  else if (overlayColumns.getVM() != 1)
  {
    result=EC_IllegalCall;
    DCMPSTAT_WARN("presentation state contains an overlay with overlayColumns VM != 1");
  }

  if (overlayType.getLength() == 0)
  {
    result=EC_IllegalCall;
    DCMPSTAT_WARN("presentation state contains an overlay with overlayType absent or empty");
  }
  else if (overlayType.getVM() != 1)
  {
    result=EC_IllegalCall;
    DCMPSTAT_WARN("presentation state contains an overlay with overlayType VM != 1");
  }

  if (overlayOrigin.getLength() == 0)
  {
    result=EC_IllegalCall;
    DCMPSTAT_WARN("presentation state contains an overlay with overlayOrigin absent or empty");
  }
  else if (overlayOrigin.getVM() != 2)
  {
    result=EC_IllegalCall;
    DCMPSTAT_WARN("presentation state contains an overlay with overlayOrigin VM != 2");
  }

  if (overlayBitsAllocated.getLength() == 0)
  {
    result=EC_IllegalCall;
    DCMPSTAT_WARN("presentation state contains an overlay with overlayBitsAllocated absent or empty");
  }
  else if (overlayBitsAllocated.getVM() != 1)
  {
    result=EC_IllegalCall;
    DCMPSTAT_WARN("presentation state contains an overlay with overlayBitsAllocated VM != 1");
  }

  if (overlayBitPosition.getLength() == 0)
  {
    result=EC_IllegalCall;
    DCMPSTAT_WARN("presentation state contains an overlay with overlayBitPosition absent or empty");
  }
  else if (overlayBitPosition.getVM() != 1)
  {
    result=EC_IllegalCall;
    DCMPSTAT_WARN("presentation state contains an overlay with overlayBitPosition VM != 1");
  }

  /* in a presentation state object, the overlay data must always be present in this group */
  if (overlayData.getLength() == 0)
  {
    result=EC_IllegalCall;
    DCMPSTAT_WARN("presentation state contains an overlay with overlayData absent or empty");
  }

  return result;
}


OFCondition DVPSOverlay::write(DcmItem &dset)
{
  OFCondition result = EC_Normal;
  DcmElement *delem=NULL;
  Uint16 repeatingGroup = 0x6000 + overlayGroup;

  ADD_REPEATING_ELEMENT_TO_DATASET(DcmUnsignedShort, overlayRows, repeatingGroup)
  ADD_REPEATING_ELEMENT_TO_DATASET(DcmUnsignedShort, overlayColumns, repeatingGroup)
  ADD_REPEATING_ELEMENT_TO_DATASET(DcmCodeString, overlayType, repeatingGroup)
  ADD_REPEATING_ELEMENT_TO_DATASET(DcmSignedShort, overlayOrigin, repeatingGroup)
  ADD_REPEATING_ELEMENT_TO_DATASET(DcmUnsignedShort, overlayBitsAllocated, repeatingGroup)
  ADD_REPEATING_ELEMENT_TO_DATASET(DcmUnsignedShort, overlayBitPosition, repeatingGroup)
  if (overlayData.getLength() >0)
  {
    ADD_REPEATING_ELEMENT_TO_DATASET(DcmOverlayData, overlayData, repeatingGroup)
  }
  if (overlayDescription.getLength() >0)
  {
    ADD_REPEATING_ELEMENT_TO_DATASET(DcmLongString, overlayDescription, repeatingGroup)
  }
  if (overlayLabel.getLength() >0)
  {
    ADD_REPEATING_ELEMENT_TO_DATASET(DcmLongString, overlayLabel, repeatingGroup)
  }

  return result;
}


OFBool DVPSOverlay::isSuitableAsShutter(unsigned long x, unsigned long y)
{
  // check that overlay is Graphic, not ROI.
  if (isROI()) return OFFalse;

  // check if overlay origin is 1\1
  Sint16 originX=0;
  Sint16 originY=0;
  OFCondition result = overlayOrigin.getSint16(originX,0);
  if (result==EC_Normal) result = overlayOrigin.getSint16(originY,1);
  if ((result != EC_Normal)||(originX != 1)||(originY != 1)) return OFFalse;

  // check if overlay size matches given image size
  Uint16 rows=0;
  Uint16 columns=0;
  result = overlayRows.getUint16(rows,0);
  if (result==EC_Normal) result = overlayColumns.getUint16(columns,0);

  if (result==EC_Normal) return ((columns==x)&&(rows==y));
  return OFFalse;
}

const char *DVPSOverlay::getOverlayLabel()
{
  char *c = NULL;
  if (EC_Normal == overlayLabel.getString(c)) return c; else return NULL;
}

const char *DVPSOverlay::getOverlayDescription()
{
  char *c = NULL;
  if (EC_Normal == overlayDescription.getString(c)) return c; else return NULL;
}

OFBool DVPSOverlay::isROI()
{
  OFString aString;
  if (EC_Normal == overlayType.getOFString(aString,0))
  {
    return (aString == "ROI");
  }
  return OFFalse;
}

OFCondition DVPSOverlay::getValues(
  Sint16& originX,
  Sint16& originY,
  Uint16& sizeX,
  Uint16& sizeY)
{
  OFCondition result = overlayOrigin.getSint16(originX,1);
  if (result.good()) result = overlayOrigin.getSint16(originY,0);
  if (result.good()) result = overlayColumns.getUint16(sizeX,0);
  if (result.good()) result = overlayRows.getUint16(sizeY,0);
  return result;
}

 类似资料: