cornerstone支持overlay 数据渲染

1. 引子

在医学影像领域,DICOM(Digital Imaging and Communications in Medicine)是一种广泛使用的标准格式,用于存储和传输医学图像。Overlay 标签在 DICOM 中用于表示图像上的叠加层,它们可以包含图像标记、文本或其他信息。这些 Overlay 数据通过 60xx 标签组进行表示,其中 xx 可以从 001F,这允许在同一图像中存在多个 Overlay 平面。

常用的 Overlay 相关标签包括:

  • (60xx,0010) Overlay Rows: 行数,表示叠加层的高度。
  • (60xx,0011) Overlay Columns: 列数,表示叠加层的宽度。
  • (60xx,0040) Overlay Type: 叠加层的类型,通常为 'G'(图形)或 'R'(区域)。
  • (60xx,0050) Overlay Origin: 叠加层的起始位置(x, y)。
  • (60xx,0100) Overlay Bits Allocated: 每个像素分配的位数,通常为 1。
  • (60xx,0102) Overlay Bit Position: 数据的位位置,通常为 0。
  • (60xx,3000) Overlay Data: 实际叠加层数据,存储为二进制位图。

2. 解析 Overlay 标签

为了从 DICOM 文件中提取并解析 Overlay 数据,首先需要遍历所有可能存在的 Overlay 标签组(即 60xx 标签组),并收集相关的信息。

getOverlayTags 方法

该方法遍历可能的 Overlay 标签组,从 60xx 开始,直到 601F。每个标签组代表一个可能的 Overlay 平面。方法会检查每个标签组是否包含 Overlay 数据,并将这些数据收集到一个数组中。

function getOverlayTags(dataSet) {
  const overlays = [];

  for (let group = 0x6000; group <= 0x601F; group += 2) {
    const groupHex = group.toString(16).padStart(4, '0');

    const overlay = {
      rows: dataSet.uint16(`x${groupHex}0010`),
      columns: dataSet.uint16(`x${groupHex}0011`),
      type: dataSet.string(`x${groupHex}0040`),
      origin: [dataSet.int16(`x${groupHex}0050`, 0), dataSet.int16(`x${groupHex}0050`, 1)],
      bitPosition: dataSet.uint16(`x${groupHex}0102`),
      bitsAllocated: dataSet.uint16(`x${groupHex}0100`),
      data: dataSet.elements[`x${groupHex}3000`],
      description: dataSet.string(`x${groupHex}0022`),
    };

    if (overlay.data) {
      overlays.push(overlay);
    }
  }

  return overlays;
}

getOverlayData 方法

getOverlayData 方法从特定的 Overlay 标签中提取二进制数据。这些数据被存储为 DICOM 数据集的字节数组,并通过位操作提取每个像素的数据。

function getOverlayData (dataSet, overlay) {
  const overlayData = overlay.data
  if (!overlayData) {
    return
  }
  const data = [];

  for (let i = 0; i < overlayData.length; i++) {
    for (let k = 0; k < 8; k++) {
      const byte_as_int = dataSet.byteArray[overlayData.dataOffset + i];
      data[i * 8 + k] = (byte_as_int >> k) & 0b1;
    }
  }

  return data
}

注意事项

  • 字节顺序:在 DICOM 数据中,Overlay 数据通常以位图的形式存储,其中每个字节的每一位代表一个像素。因此,需要通过位操作从字节中提取每一位数据。
  • 位位置Overlay Bit Position 标签指示了 Overlay 数据的位位置,通常为 0。

这部分都是在cornerstoneWADOImageLoader源码里修改的,在其处理了dicom返回image对象里新加了个getOverlayData方法,用于获取overlay data。

因为其他同事做过一次修改,直接将image.data的byteArray给删除了,目的是节约空间,导致我之前都没获取到完整的byteArray,也就无法根据位置信息获取overlay data,没对该js文件做处理可以。

3. 渲染 Overlay 数据

渲染过程通过 handleRender 函数实现。这个函数在 Canvas 上绘制从 getOverlayData 方法获得的二进制 Overlay 数据。

handleRender 方法

此方法监听图像渲染事件,在 Canvas 上绘制解析后的 Overlay 数据。

// 这里Overlay 数据默认取6000
function handleRender(e) {
  const eventData = e.detail;
  const dataSet = eventData.image.data;
  if (eventData && eventData.image && dataSet.uint16 && dataSet.uint16(OVERLAYTAGS.OverlayBitPosition) === 0) {
    context.save();
    const width = dataSet.uint16(OVERLAYTAGS.OverlayRows);
    const height = dataSet.uint16(OVERLAYTAGS.OverlayColumns);
    const overlayData = eventData.image.getOverlayData()

    const layerCanvas = document.createElement('canvas');
    layerCanvas.width = width;
    layerCanvas.height = height;
    const layerContext = layerCanvas.getContext('2d');
    layerContext.save();
    layerContext.fillStyle = "#ffffff";
    if (dataSet.string(OVERLAYTAGS.OverlayType) === 'R') {
      layerContext.fillRect(0, 0, layerCanvas.width, layerCanvas.height);
      layerContext.globalCompositeOperation = 'xor';
    }

    let i = 0;

    for (let y = 0; y < height; y++) {
      for (let x = 0; x < width; x++) {
        const pixel = overlayData[i++];

        if (pixel > 0) {
          layerContext.fillRect(x, y, 1, 1);
        }
      }
    }

    layerContext.restore();
    context.drawImage(layerCanvas, 0, 0);
    context.restore();
  }
}

因为是同步添加覆盖层,所以不需要考虑放大、缩小、旋转等操作,会跟原图保持同步。

关键点

  • 缩放与变换:在渲染之前,确保应用正确的缩放和变换矩阵,以保证 Overlay 数据在图像上的正确位置。
  • 位图绘制:使用 fillRect 方法逐个像素地绘制 Overlay 数据,确保精确显示。

4. 总结

通过上述方法,可以从 DICOM 图像中有效解析并渲染 Overlay 数据。这包括提取相关标签、解析 Overlay 位图数据,以及使用 Canvas 在图像上绘制叠加层。这种方式不仅能处理常见的 Overlay 情况,还能扩展到处理更复杂的多层叠加。

后续优化

  • 性能优化:对于大型 DICOM 图像或多个 Overlay 平面,可以考虑使用 Web Workers 或 OffscreenCanvas 来提升渲染性能。
  • 兼容性处理:确保对各种 DICOM 标准变体和特例的兼容性,如处理不同的 Bit Position 或 Bits Allocated 值。

通过以上步骤,你可以全面、准确地处理 DICOM Overlay 数据。如果在实际应用中遇到特殊情况或需要进一步优化,欢迎继续讨论。

Last Updated 2024/12/27 11:36:49