当前位置: 首页 > article >正文

基于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',},...
]

我们关心两个数据

  1. scalarOpacity:图像灰度值映射不透明度
    值为字符串,以空格为分隔符:
    第一个数据(12)表示有效映射数据个数,即第二个数据(-3024)到最后一个数据(0.803922)的个数。从第二个数据~最后一个数据,每两个数据为一组映射,如第一组[-3024 0],表示像素值为-3024时对应的不透明度为0。第一个数据为12,计算可知有6组映射。
  2. 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>

总结

  1. 讲解三维调窗原理
  2. 自定义工具流程
http://www.lryc.cn/news/2396471.html

相关文章:

  • 针对 Harmony-Cordova 性能优化,涵盖原生插件开发、线程管理和资源加载等关键场景
  • 【SCI论文实现】信息引导的高质量三维重建——系统架构设计 PYTHON
  • 经典面试题:一文了解常见的缓存问题
  • Vue3处理number输入框避免NaN
  • GC1267F:单相全波风扇电机预驱动芯片解析
  • Linux --进程状态
  • 如何设计一个支持线上线下的通用订单模块 —— 面向本地生活服务行业的架构思路
  • 智能手机上用Termux安装php+Nginx
  • 【线上故障排查】缓存穿透攻击的识别与布隆过滤器(面试题 + 3 步追问应对 + 案例分析)
  • Visual Studio 调试中 PDB 与图像不匹配
  • 设计模式——策略设计模式(行为型)
  • 保持本地 Git 项目副本与远程仓库完全同步
  • 高效Excel数据净化工具:一键清除不可见字符与格式残留
  • 设计模式——模版方法设计模式(行为型)
  • Deepin 20.9社区版安装Docker
  • Node.js 全栈技术栈的开发者,Web3 面试题
  • 纯数据挖掘也能发Microbiome?
  • 2025年05月30日Github流行趋势
  • 跨平台猫咪桌宠 BongoCat v0.4.0 绿色版
  • 【课堂笔记】标签传播算法Label Propagation Algorithm(LPA)
  • Dify案例实战之智能体应用构建(一)
  • 从模式到架构:Java 工厂模式的设计哲学与工程化实践
  • docker问题记录
  • 设计模式——代理设计模式(结构型)
  • Elasticsearch的集群管理介绍
  • Spring MVC + Tomcat 8.5 踩坑实录:Servlet 版本引发的部署失败
  • 从“固定“到“流动“:移动充电如何重塑用户体验?
  • 玩客云 OEC/OECT 笔记(1) 拆机刷入Armbian固件
  • docker环境添加安装包持久性更新
  • GIS数据类型综合解析