cornerstone 之覆盖层信息

660 阅读4分钟

cornerstone 之覆盖层信息

在一些 PACS 软件进行阅片时,会发现显示影像的区域的左上角、右上角、右下角、左下角会有一些关于影像或患者的信息展示,为阅片者提供最直观的数据展示。本章我们将介绍如何通过 cornerstone 实现这个功能:覆盖层信息(四角信息)。

Dicom 中的 Tag

DICOM(Digital Imaging and Communications in Medicine)即医学数字成像和通信,是医学图像和相关信息的国际标准(ISO 12052)。它定义了能满足临床需要的可用于数据交换的医学图像格式。

DICOM 格式的文件包含的影像与患者的信息通常是以 key、value 的形式提供,每对 key、value 包含一种信息,这其中的 key 通常称之为 Tag。

Tag 由分组号(Group Number)与元素号(Element Number)两部分组成,Dicom 标准规定了具体的每个 Tag 保存什么样的信息。相当于 Dicom 标准定义了信息的字典,在使用时只需要知道字典中该条信息的索引(Tag)就可以获取到相对应的信息。

常用的 Tag 整理

常用的 Tag 主要分为四类:患者信息、study 检查信息、series 序列信息、image 影像信息。

患者信息 Tag

TagTag Description注释
(0010,0010)Patient’s Name患者姓名
(0010,0020)Patient ID患者 ID
(0010,0030)Patient’s Birth Date患者出生日期
(0010,0032)Patient’s Birth Time患者出生时间
(0010,0040)Patient’s Sex患者性别
(0010,1010)Patient’s Age患者年龄

study 检查信息 Tag

TagTag Description注释
(0008,0020)Study date检查日期
(0008,0030)Study time检查时间
(0008,0050)Accession Number检查号
(0008,0080)Institution Name机构名称
(0008,1030)Study description检查描述
(0020,000D)Study Instance UID检查实例号
(0020,0010)Study ID检查 ID

series 序列信息 Tag

TagTag Description注释
(0008,0021)Series Date序列日期
(0008,0031)Series Time序列时间
(0008,0060)Modality检查的类型
(0008,103E)Series Description序列描述
(0018,0050)Slice Thickness层厚、切片厚度,单位:mm
(0018,0060)KVP球管电压,单位:kV
(0018,1150)Exposure time曝光时间,单位:ms
(0018,1151)X-ray tube current球管电流,单位:mA
(0020,000E)Series Instance UID序列实例号
(0020,0011)Series Number序列号

image 影像信息 Tag

TagTag Description注释
(0008,0018)SOP Instance UID影像实例号
(0008,0023)Content Date影像拍摄日期
(0008,0033)Content Time影像拍摄时间
(0020,0013)Instance Number影像号
(0020,1041)Slice Location实际的相对位置,单位:mm
(0028,0010)Rows影像的总行数
(0028,0011)Columns影像的总列数
(0028,1050)Window Center窗位
(0028,1051)Window Width窗宽

Tag 信息的获取

cornerstone 中获取 Tag 信息有两种方式,一种是通过 Image 对象获取,此方法需要先 loadImage 图像,另外一种,通过 dicomParser 库中的方法直接解析 dicom 文件。

Image 对象方式:

// 通过激活元素获取 Image 对象
const image = cornerstone.getImage(enabledElement);

// 封装获取影像信息的方法
function getImageInfoByDataSet(dataSet) {
  const imageInfo = {
    patientName: dataSet.string("x00100010"),
    patientBirthday: dataSet.string("x00100030"),
    patientSex: dataSet.string("x00100040"),
    patientAge: dataSet.string("x00101010")
    // ...
  };

  return imageInfo;
}

const imageInfo = getImageInfoByDataSet(image.data);

通过 dicomParser 库方式:

// 封装解析 dicom 文件获取影像信息的方法
function getImageInfoByFile(file) {
  return new Promise((resolve) => {
    const reader = new FileReader();

    reader.onload = function () {
      const arrayBuffer = reader.result as ArrayBuffer;
      const byteArray = new Uint8Array(arrayBuffer);
      const dataSet = dicomParser.parseDicom(byteArray);
      const imageInfo = getImageInfoByDataSet(dataSet);

      resolve(imageInfo);
    };
    reader.readAsArrayBuffer(file);
  });
}

但是,通过情况下,一般会在 cornerstone 的 cornerstoneimagerendered 事件中获取当前图像的信息:

enabledElement.addEventListener("cornerstoneimagerendered", (e) => {
  const image = e.detail.image;
  const imageInfo = getImageInfoByDataSet(image.data);
});

生成覆盖层

生成覆盖层有两种方式可以实现,一种是 html 标签通过定位的方式覆盖到加载影像的元素上,另外一种是获取当前影像的 canvas ,通过 canvas 的 fillText 方法进行渲染。本次只介绍相对来说更容易实现的 html 标签覆盖的方式,这种方式对于影像的渲染不会产生任何的影像。

页面结构:

<div class="container">
  <div class="enabledElement"></div>
  <div class="overlay topleft"></div>
  <div class="overlay topright"></div>
  <div class="overlay bottomright"></div>
  <div class="overlay bottomleft"></div>
</div>

相应的样式:

.container {
  position: relative;
  width: 700px;
  height: 500px;
  margin-top: 10vh;
  margin-left: 10px;
}

.enabledElement {
  width: 100%;
  height: 100%;
  border: 1px solid rgb(0, 164, 217);
  box-sizing: border-box;
}

.overlay {
  position: absolute;
  padding: 2px 5px;
  color: greenyellow;
  user-select: none;
}

.topleft {
  top: 0px;
  left: 0px;
}

.topright {
  top: 0px;
  right: 0px;
  text-align: right;
}

.bottomright {
  bottom: 0px;
  right: 0px;
  text-align: right;
}

.bottomleft {
  bottom: 0px;
  left: 0px;
}

将信息实时的显示到影像上方:

enabledElement.addEventListener("cornerstoneimagerendered", (e) => {
  const image = e.detail.image;
  const imageInfo = getImageInfoByDataSet(image.data);

  const topLeftHtml = `Patient Name: ${imageInfo.patientName}`;
  const topRightHtml = `Patient Birthday: ${imageInfo.patientBirthday}`;
  const bottomRightHtml = `Patient Sex: ${imageInfo.patientSex}`;
  const bottomLeftHtml = `Patient Age: ${imageInfo.patientAge}`;

  document.getElementByClassName("topleft").innerHTML = topLeftHtml;
  document.getElementByClassName("topright").innerHTML = topRightHtml;
  document.getElementByClassName("bottomright").innerHTML = bottomRightHtml;
  document.getElementByClassName("bottomleft").innerHTML = bottomLeftHtml;
});

最简单的例子

老规矩,最后放上案例,以便更加直观查看效果。