基于cornerstone3D的dicom影像浏览器 第二十五章 自定义VR调窗工具
文章目录
- 前言
- 一、三维调窗原理
- 二、自定义三维调窗工具
- 三、调用流程
- 1. 修改mprvr.js
- 2. 修改DispalyerArea3D.vue
- 3. view3d.vue
- 4. Toolbar3D.vue
- 总结
前言
从cornerstoneTools BaseTool派生VolumeShiftColorTool,实现鼠标键按下并移动时,对3D窗口的preset进行偏移,达到三维调窗的目的。
演示视频中绑定鼠标右键进行调窗,和其他工具一样,也可以绑定左键,中键。
效果如下:
一、三维调窗原理
观察cornerstonejs中 viewport preset 数据结构:
源码位置:packages\core\src\constants\viewportPresets.ts
const presets: ViewportPreset[] = [
{name: 'CT-AAA',gradientOpacity: '4 0 1 255 1',specularPower: '10',scalarOpacity:'12 -3024 0 143.556 0 166.222 0.686275 214.389 0.696078 419.736 0.833333 3071 0.803922',specular: '0.2',shade: '1',ambient: '0.1',colorTransfer:'24 -3024 0 0 0 143.556 0.615686 0.356863 0.184314 166.222 0.882353 0.603922 0.290196 214.389 1 1 1 419.736 1 0.937033 0.954531 3071 0.827451 0.658824 1',diffuse: '0.9',interpolation: '1',},...
]
我们关心两个数据
- scalarOpacity:图像灰度值映射不透明度
值为字符串,以空格为分隔符:
第一个数据(12)表示有效映射数据个数,即第二个数据(-3024)到最后一个数据(0.803922)的个数。从第二个数据~最后一个数据,每两个数据为一组映射,如第一组[-3024 0],表示像素值为-3024时对应的不透明度为0。第一个数据为12,计算可知有6组映射。 - colorTransfer:图像灰度值映射RGB值
值为字符串,以空格为分隔符:
第一个数据(24)表示有效映射数据个数,即第二个数据(-3024)到最后一个数据(1)的个数。从第二个数据~最后一个数据,每四个数据为一组映射,如第一组:[-3024 0 0 0],表示像素值为-3024时对应的RGB值 为(0,0,0)。此处为归一化的RGB值,乘255可得RGB值
。第一个数据为24,计算可知有6组映射。
实现三维调窗的方法:在鼠标按下并移动时,修改preset中scalarOpacity和colorTransfer中每组映射中的第一个值,即图像灰度值,再把修改后的preset值设置到vieport即可实现。
_shiftVRColor(viewport, preset, pos) {const volumeActor = viewport.getDefaultActor().actor;// 字符串以空格为分割符转为数值数组const color = preset.colorTransfer.split(" ").map(Number);// 偏移数据for (let i = 1; i < color.length; i += 4) {color[i] = color[i] + pos;}// 字符串以空格为分割符转为数值数组const opacity = preset.scalarOpacity.split(" ").map(Number);// 偏移数据for (let i = 1; i < opacity.length; i += 2) {opacity[i] = opacity[i] + pos;}// 生成新的presetconst newPreset = { ...preset };newPreset.colorTransfer = color.join(" ");newPreset.scalarOpacity = opacity.join(" ");// 记录偏移preset.shiftPos = pos;// 应用新的presetcsUtils.applyPreset(volumeActor, newPreset);viewport.render();}
二、自定义三维调窗工具
新建VolumeShiftColorTool.js
参考WindowLevelTool,从BaseTool派生,重写mouseDragCallback。在mouseDragCallback中调用上一节的_shiftVRColor函数
源码位置:packages\tools\src\tools\WindowLevelTool.ts
import {getEnabledElement,utilities as csUtils,VolumeViewport3D
} from "@cornerstonejs/core";
import * as cornerstoneTools from "@cornerstonejs/tools";
const { BaseTool } = cornerstoneTools;export default class VolumeShiftColorTool extends BaseTool {static toolName;constructor(toolProps = {},defaultToolProps = {supportedInteractionTypes: ["Mouse", "Touch"]}) {super(toolProps, defaultToolProps);}touchDragCallback(evt) {this.mouseDragCallback(evt);}mouseDragCallback(evt) {const { element, deltaPoints } = evt.detail;const enabledElement = getEnabledElement(element);const { viewport } = enabledElement;if (viewport instanceof VolumeViewport3D) {const { preset } = viewport.getProperties();let shiftPos = preset.shiftPos || 0;// 鼠标上下移动const yDelta = deltaPoints.canvas[1];shiftPos += yDelta;this._shiftVRColor(viewport, preset, shiftPos);}}_shiftVRColor(viewport, preset, pos) {const volumeActor = viewport.getDefaultActor().actor;const color = preset.colorTransfer.split(" ").map(Number);for (let i = 1; i < color.length; i += 4) {color[i] = color[i] + pos;}const opacity = preset.scalarOpacity.split(" ").map(Number);for (let i = 1; i < opacity.length; i += 2) {opacity[i] = opacity[i] + pos;}const newPreset = { ...preset };newPreset.colorTransfer = color.join(" ");newPreset.scalarOpacity = opacity.join(" ");preset.shiftPos = pos;csUtils.applyPreset(volumeActor, newPreset);viewport.render();}
}VolumeShiftColorTool.toolName = "VolumeShiftColor";
三、调用流程
1. 修改mprvr.js
- 导入、添加VolumeShiftColorTool
- 添加函数enableVolumeShiftColor,切换ZoomTool和VolumeShiftColorTool绑定鼠标右键
import VolumeShiftColorTool from "./VolumeShiftColorTool";export default class MPR {constructor(params) {this.toolGroup = null;this.vrToolGroup = null;this.renderingEngine = null;this.registered = false;...this.init(params);}init(config = {}) {const { elAxial, elSagittal, elCoronal, elVR } = config;cornerstoneTools.addTool(CrosshairsTool);...this.vrToolGroup = ToolGroupManager.getToolGroup(vrToolGroupId);cornerstoneTools.addTool(VolumeShiftColorTool);if (!this.vrToolGroup) {...this.vrToolGroup.addTool(VolumeShiftColorTool.toolName);}}enableVolumeShiftColor(enable) {if (enable) {this.vrToolGroup.setToolDisabled(ZoomTool.toolName);this.vrToolGroup.setToolActive(VolumeShiftColorTool.toolName, {bindings: [{mouseButton: MouseBindings.Secondary // Right Click}]});} else {this.vrToolGroup.setToolDisabled(VolumeShiftColorTool.toolName);this.vrToolGroup.setToolActive(ZoomTool.toolName, {bindings: [{mouseButton: MouseBindings.Secondary // Right Click}]});}}
}
2. 修改DispalyerArea3D.vue
const enableVRShiftColor = enable => {theMPR.enableVolumeShiftColor(enable);
};defineExpose({...enableVRShiftColor
});
3. view3d.vue
响应工具栏enableVRShift事件
async function OnToolbarAction(action) {switch (action.name) {...case "enableVRShift":displayArea.value.enableVRShiftColor(action.value);break;default:break;}
}
4. Toolbar3D.vue
添加“VR调窗” el-checkbox, 绑定变量enableVRShift
const enableVRShift = ref(false);
watch(enableVRShift, (newValue) => {emit("action", { name: "enableVRShift", value: newValue });
});<template><div class="toolbar">...<div class="toolbar-row"><el-checkbox v-model="enableVRShift" label="VR调窗" size="large" /></div>...</div>
</template>
总结
- 讲解三维调窗原理
- 自定义工具流程