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
Tag | Tag 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
Tag | Tag 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
Tag | Tag 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
Tag | Tag 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;
});
最简单的例子
老规矩,最后放上案例,以便更加直观查看效果。