cornerstone Tools 切换影像篇
在搭建 Pacs 影像阅片系统时,序列内图像切换使用场景较多,流畅与效率将影响用户使用的直观感受。本篇将详细介绍如何通过 cornerstoneTools 实现影像快速流畅的切换。
切换影像工具
cornerstoneTools 提供了两个切换影像的工具:StackScrollTool、StackScrollMouseWheelTool,分别通过鼠标按钮或鼠标滚轮操作实现切换图像,下面将介绍详细的使用方法。
StackScrollTool
StackScrollTool 通过鼠标滑动,进行序列内影像快速滚动切换,并且支持配置循环与跳帧。
const element = document.getElementById("enabledElement");
// 为启用元素添加 stack 状态管理器
cornerstoneTools.addStackStateManager(element, ["stack"]);
const stack = {
currentImageIdIndex: 0,
// 需要切换的影像 id 集合
imageIds: [
"https://tools.cornerstonejs.org/examples/assets/dicom/bellona/chest_lung/1.dcm",
"https://tools.cornerstonejs.org/examples/assets/dicom/bellona/chest_lung/2.dcm",
"https://tools.cornerstonejs.org/examples/assets/dicom/bellona/chest_lung/3.dcm",
"https://tools.cornerstonejs.org/examples/assets/dicom/bellona/chest_lung/4.dcm",
"https://tools.cornerstonejs.org/examples/assets/dicom/bellona/chest_lung/5.dcm"
]
};
// 为启用元素添加 stack 工具状态
cornerstoneTools.addToolState(element, "stack", stack);
const StackScrollTool = cornerstoneTools.StackScrollTool;
const props = {
configuration: {
// 是否在序列内循环
loop: true,
// 是否跳帧
allowSkipping: true
}
};
cornerstoneTools.addTool(StackScrollTool, props);
cornerstoneTools.setToolActive("StackScroll", { mouseButtonMask: 1 });
StackScrollMouseWheelTool
StackScrollMouseWheelTool 通过鼠标滚轮滚动,进行序列内影像快速滚动切换,并且支持配置循环、跳帧与滚动方向。
const element = document.getElementById("enabledElement");
// 为启用元素添加 stack 状态管理器
cornerstoneTools.addStackStateManager(element, ["stack"]);
const stack = {
currentImageIdIndex: 0,
// 需要切换的影像 id 集合
imageIds: [
"https://tools.cornerstonejs.org/examples/assets/dicom/bellona/chest_lung/1.dcm",
"https://tools.cornerstonejs.org/examples/assets/dicom/bellona/chest_lung/2.dcm",
"https://tools.cornerstonejs.org/examples/assets/dicom/bellona/chest_lung/3.dcm",
"https://tools.cornerstonejs.org/examples/assets/dicom/bellona/chest_lung/4.dcm",
"https://tools.cornerstonejs.org/examples/assets/dicom/bellona/chest_lung/5.dcm"
]
};
// 为启用元素添加 stack 工具状态
cornerstoneTools.addToolState(element, "stack", stack);
const StackScrollMouseWheelTool = cornerstoneTools.StackScrollMouseWheelTool;
const props = {
configuration: {
// 是否在序列内循环
loop: true,
// 是否跳帧
allowSkipping: true,
// 倒转方向
invert: false
}
};
cornerstoneTools.addTool(StackScrollMouseWheelTool, props);
cornerstoneTools.setToolActive("StackScrollMouseWheel", { mouseButtonMask: 4 });
切换原理
快速的切换影像,实际就是通过一些机制进行高效、准确、动态的渲染影像。
StackScrollTool 与 StackScrollMouseWheelTool 的主要区别为交互不同,其内部的实现原理是一致的,均是通过调用 scroll 函数进行切换影像。
scroll 函数解析:
/**
* Scrolls through the stack.
* @export @public @method
* @name scroll
*
* @param {HTMLElement} element The element to scroll.
* @param {number} images The number of images to scroll through.
* @param {type} [loop = false] Whether to loop the scrolling.
* @param {type} [allowSkipping = true] Whether frames can be skipped.
* @returns {void}
*/
export default function (element, images, loop = false, allowSkipping = true) {
// 获取 cornerstoneTools.addToolState(element, "stack", stack) 添加的状态
const toolData = getToolState(element, "stack");
if (!toolData || !toolData.data || !toolData.data.length) {
return;
}
const stackData = toolData.data[0];
if (!stackData.pending) {
stackData.pending = [];
}
/**
* 计算新的影像索引,此处通过 iamges 参数控制向前切换还是向后切换。
* iamges 参数为 StackScroll 与 StackScrollMouseWheel 工具通过用户交互操作而计算得来。
* 例如:
* StackScroll 通过计算鼠标滑动方向判断向前或向后。
* StackScrollMouseWheel 通过鼠标滚轮方向判断向前或向后。
*/
let newImageIdIndex = stackData.currentImageIdIndex + images;
/**
* 再次计算影像索引,此处通过 loop 参数控制是否循环。
* 允许循环时,%= 运算符在不存在余数时返回 newImageIdIndex,
* 当 newImageIdIndex 与 nbImages 相等时,返回 0,通过此方法达到重头开始的效果。
*/
if (loop) {
const nbImages = stackData.imageIds.length;
newImageIdIndex %= nbImages;
} else {
newImageIdIndex = clip(newImageIdIndex, 0, stackData.imageIds.length - 1);
}
/**
* 渲染图像,此处通过 allowSkipping 参数控制是否跳帧。
* 当允许跳帧时,将直接渲染最新的影像,当切换过快时,会跳过未来得及渲染的影像。
* 当不允许跳帧时,将所有触发的影像索引放入 stackData.pending 数组中,通过递归逐条渲染,直至清空 stackData.pending。
*/
if (allowSkipping) {
scrollToIndex(element, newImageIdIndex);
} else {
const pendingEvent = {
index: newImageIdIndex
};
stackData.pending.push(pendingEvent);
scrollWithoutSkipping(stackData, pendingEvent, element);
}
}
最简单的例子
本篇已详细介绍 cornerstoneTools 的切图工具,已下例子将展现最基本的具有切换影像功能的预览程序。
ps:由于一些原因,网络 dcm 文件资源下载较慢,可先将所有影像滚动切换一遍,等待所有 dcm 文件下载完成后,在体验切换交互效果。