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

网站建设要具备那些住房和城乡建设官网

网站建设要具备那些,住房和城乡建设官网,连云港网站设计,易企秀怎么制作系列文章目录 第一章 下载源码 运行cornerstone3D example 第二章 修改示例crosshairs的图像源 第三章 vitevue3cornerstonejs项目创建 第四章 加载本地文件夹中的dicom文件并归档 第五章 dicom文件生成png,显示检查栏,序列栏 第六章 stack viewport 显…

系列文章目录

第一章 下载源码 运行cornerstone3D example
第二章 修改示例crosshairs的图像源
第三章 vite+vue3+cornerstonejs项目创建
第四章 加载本地文件夹中的dicom文件并归档
第五章 dicom文件生成png,显示检查栏,序列栏
第六章 stack viewport 显示dicom序列
第七章 在Displayer四个角落显示文字
第八章 在Displayer中显示图像方位
第九章 自动加载、清空显示、修改布局
第十章 显示标尺
第十一章 测量工具
第十二章 镜像、负像、旋转、伪彩、复位
第十三章 自定义垂直滚动条
第十四章 参考线、同步调窗、同步缩放、同步移动
第十五章 预设窗值
第十六章 工具栏svg按钮
第十七章 同步滚动
第十八章 自定义序列自动播放条
第十九章 显示overlay
第二十章 显示多帧图
第二十一章 显示DICOM TAGS


文章目录

  • 系列文章目录
  • 前言
  • 一、程序结构
    • 1. view3d.vue
    • 2. DisplayerArea3D.vue
    • 3. mprvr.js
  • 二、代码
    • 1. view3d.vue
    • 2. DisplayerArea3D.vue
    • 3. mprvr.js
      • 1)init函数
      • 2)loadImages函数
      • 3)getSliceCount, getSliceIndex 函数
      • 4) resize函数
      • 5) bindRenderEvent, bindCameraEvent
      • 6)destory函数
      • getDicomInfo函数
  • 总结


前言

实现一个简单的mpr + vr 功能。
cornerstone3D已经全都实现了,修改为自己的界面。
查看官方示例-cursor3d
cornerstonejs源码位置packages\tools\examples\cursor3D\index.ts
效果如下:
在这里插入图片描述


一、程序结构

1. view3d.vue

  • 包含Toolbar3d.vue组件和DispalyerArea3D.vue组件
  • Toolbar3d.vue与前面章节中的Toolbar.vue组件一样,主要放置一些操作按钮

2. DisplayerArea3D.vue

  • 包含四个窗口div: axial, sagittal, coronal, vr
  • cornerstone3D相关的函数全写到mprvr.js中,由DisplayerArea3D.vue调用

3. mprvr.js

  • 实现MPR类,整理了下官方示例-curso3d中的代码,方便调用

二、代码

1. view3d.vue

<script setup name="View3d">
import { ref, onMounted, computed, watch } from "vue";
import { useRoute } from "vue-router";
import DisplayerArea3D from "../components/DisplayerArea3D.vue";
import Toolbar3D from "../components/Toolbar3D.vue";
import { useArchiveStore } from "../stores/archive";
import { useAppStore } from "../stores/appStore";
import { storeToRefs } from "pinia";const archiveStore = useArchiveStore();
const appStore = useAppStore();const route = useRoute();
const view3d = ref(null);
const displayArea = ref(null);
const toolbar = ref(null);
const toolbarHW = ref(300);const { toolbarPos, navbarPos } = storeToRefs(appStore);const mainClass = computed(() => {const vorh = toolbarPos.value === "top" ? "vertical" : "horizontal-reverse";return "flex-" + vorh;
});const toolbarClass = computed(() => {return "toolbar-" + toolbarPos.value;
});const toolbarStyle = computed(() => {if (toolbarPos.value === "top") {return {height: toolbarHW.value + "px"};} else {return {width: toolbarHW.value + "px"};}
});function resizeToolbar(e) {e.stopPropagation();view3d.value.style.cursor = "ew-resize";view3d.value.onmousemove = function (e) {let delta, minVal, maxVal;if (toolbarPos.value === "top") {delta = e.movementY;minVal = 146;maxVal = 220;} else {delta = -e.movementX;minVal = 110;maxVal = 520;}const value = toolbarHW.value + delta;if (value < minVal || value > maxVal) return;toolbarHW.value = value;};document.onmouseup = function () {view3d.value.onmousemove = null;document.onmouseup = null;view3d.value.style.cursor = "";};
}async function OnToolbarAction(action) {switch (action.name) {case "layoutMpr":displayArea.value.setLayout("layoutmpr");break;case "layoutMprVr":displayArea.value.setLayout("layoutmprvr");break;default:break;}
}</script><template><div class="container flex-vertical" ref="view3d" @contextmenu.prevent><div class="main" :class="mainClass"><div :class="toolbarClass" :style="toolbarStyle"><Toolbar3D ref="toolbar" @action="OnToolbarAction" /></div><div class="resizer-vertical" @mousedown="resizeToolbar"></div><div class="display-area"><DisplayerArea3D ref="displayArea" /></div></div><div class="footer">Statusbar</div></div>
</template><style scoped lang="scss">
$bg-color: #333;
$main-color: lightblue;
$header-color: #45b7ec;
$footer-color: #45b7ec;
$resizer-width: 2px;
$header-height: 100px;
$footer-height: 34px;.container {background-color: $bg-color;height: 100vh;width: 100vw;max-width: 100%;max-height: 100%;justify-content: center;color: black;user-select: none;
}.flex-vertical {display: flex;flex-direction: column;
}.flex-vertical-reverse {display: flex;flex-direction: column-reverse;
}.flex-horizontal {display: flex;flex-direction: row;
}.flex-horizontal-reverse {display: flex;flex-direction: row-reverse;
}.resizer-vertical {cursor: ew-resize;width: $resizer-width;background-color: gray;flex-shrink: 0;z-index: 10;
}.resizer-horizontal {cursor: ns-resize;height: $resizer-width;background-color: gray;width: 100%;flex-shrink: 0;z-index: 10;
}.main {width: 100%;height: 100%;background-color: $main-color;.toolbar-top {height: 200px;width: 100%;}.toolbar-right {width: 200px;height: 100%;flex-shrink: 0;}.display-area {flex: 1;flex-shrink: 0;}
}.footer {background-color: $footer-color;height: $footer-height;border-top: gray solid 1px;
}
</style>

2. DisplayerArea3D.vue

  • 包含四个窗口div: axial, sagittal, coronal, vr
  • cornerstone3D相关的函数全写到mprvr.js中,由DisplayerArea3D.vue调用
<template><divclass="container3d"ref="elContainer"v-loading="loading"element-loading-text="正在处理..."element-loading-background="rgba(0, 0, 0, 0.8)"@mousedown.prevent="OnSelectView"><div class="axialparent" :style="axialStyle" v-show="showAxial"><div ref="elAxial" class="sliceview" @contextmenu.prevent><h4 class="desc">Axial</h4><span class="text_studyinfo">{{ studyInfo }}</span><span class="text_wwwc">{{ axialText.wwwc }}</span><span class="text_slice">{{ axialText.slice }}</span><span class="orient_top">{{ axialText.orient.top }}</span><span class="orient_bottom">{{ axialText.orient.bottom }}</span><span class="orient_left">{{ axialText.orient.left }}</span><span class="orient_right">{{ axialText.orient.right }}</span></div></div><div class="vrcprparent" v-show="showVR" @dblclick="OnDbClick"><div ref="elVR" class="sliceview" @contextmenu.prevent><h4 class="desc">VR</h4><span class="text_studyinfo">{{ studyInfo }}</span></div></div><div class="sagittalparent" v-show="showSagittal"><div ref="elSagittal" class="sliceview" @contextmenu.prevent><h4 class="desc">Sagittal</h4><span class="text_studyinfo">{{ studyInfo }}</span><span class="text_wwwc">{{ sagittalText.wwwc }}</span><span class="text_slice">{{ sagittalText.slice }}</span><span class="orient_top">{{ sagittalText.orient.top }}</span><span class="orient_bottom">{{ sagittalText.orient.bottom }}</span><span class="orient_left">{{ sagittalText.orient.left }}</span><span class="orient_right">{{ sagittalText.orient.right }}</span></div></div><div class="coronalparent" v-show="showCoronal"><div ref="elCoronal" class="sliceview" @contextmenu.prevent><h4 class="desc">Coronal</h4><span class="text_studyinfo">{{ studyInfo }}</span><span class="text_wwwc">{{ coronalText.wwwc }}</span><span class="text_slice">{{ coronalText.slice }}</span><span class="orient_top">{{ coronalText.orient.top }}</span><span class="orient_bottom">{{ coronalText.orient.bottom }}</span><span class="orient_left">{{ coronalText.orient.left }}</span><span class="orient_right">{{ coronalText.orient.right }}</span></div></div></div>
</template><script setup name="DisplayerArea3D">
import { ref, onMounted, onBeforeUnmount, computed, reactive, watch, onUnmounted } from "vue";
import MPR from "../cornerstone3D/mprvr.js";
import { ViewportId, getDicomInfo } from "../cornerstone3D/mprvr.js";
import { useAppStore } from "../stores/appStore";
import { storeToRefs } from "pinia";const appStore = useAppStore();
const { currentDisplayer } = storeToRefs(appStore);let theMPR = null;
const loading = ref(false);
const layout = reactive({type: "layoutmprvr",viewIds: [],maxViewId: null
});let resizeObserver = null;const studyInfo = ref("");
const defWL = ref(40);
const defWW = ref(400);
const showAxial = ref(true);
const showSagittal = ref(true);
const showCoronal = ref(true);
const showVR = ref(true);
const currentViewportId = ref("");const elContainer = ref(null);
const elAxial = ref(null);
const elSagittal = ref(null);
const elCoronal = ref(null);
const elVR = ref(null);const cornerText = reactive({[ViewportId.AXIAL]: {wwwc: "",slice: "",orient: {top: "",bottom: "",left: "",right: ""}},[ViewportId.SAGITTAL]: {wwwc: "",slice: "",orient: {top: "",bottom: "",left: "",right: ""}},[ViewportId.CORONAL]: {wwwc: "",slice: "",orient: {top: "",bottom: "",left: "",right: ""}}
});const axialText = computed(() => {return cornerText[ViewportId.AXIAL];
});
const sagittalText = computed(() => {return cornerText[ViewportId.SAGITTAL];
});const coronalText = computed(() => {return cornerText[ViewportId.CORONAL];
});const axialStyle = computed(() => {if (layout.type == "layoutmpr") {return {gridRowStart: 1,gridColumnStart: 2,gridRowEnd: 3,gridColumnEnd: 3};} else if (layout.type == "layoutmprvr") {return {gridRowStart: 1,gridColumnStart: 1,gridRowEnd: 2,gridColumnEnd: 2};}
});watch(() => layout.type,(newVal, oldVal) => {layout.viewIds.length = 0;if (newVal === "layoutmpr") {showAxial.value = true;showSagittal.value = true;showCoronal.value = true;showVR.value = false;} else if (newVal === "layoutmprvr") {showAxial.value = true;showSagittal.value = true;showCoronal.value = true;showVR.value = true;}if (showAxial.value) {layout.viewIds.push(ViewportId.AXIAL);}if (showSagittal.value) {layout.viewIds.push(ViewportId.SAGITTAL);}if (showCoronal.value) {layout.viewIds.push(ViewportId.CORONAL);}if (showVR.value) {layout.viewIds.push(ViewportId.VOLUME);}resizeViews();}
);const setLayout = type => {layout.type = type;
};const renderHandler = e => {UpdateText(e);
};const UpdateText = e => {const { viewportId } = e.detail;const wwwl = theMPR.getWindow(viewportId);const text = `WL: ${wwwl.windowCenter} WW: ${wwwl.windowWidth}`;const sliceCount = theMPR.getSliceCount(viewportId);const sliceIdx = theMPR.getSliceIndex(viewportId);const sliceText = `Im: ${sliceIdx + 1} / ${sliceCount}`;cornerText[viewportId].wwwc = text;cornerText[viewportId].slice = sliceText;
};const onSelectView = e => {const elem = e.target.closest(".sliceview");if (!elem) {return;}currentViewportId = elem.getAttribute("data-viewport-uid");
};const load = async () => {const imageIds = currentDisplayer.value.getImageIds();loading.value = true;const info = await getDicomInfo(imageIds[0]);studyInfo.value = info.studyInfo;defWL.value = info.defWL;defWW.value = info.defWW;theMPR.loadImages(imageIds).then(() => {loading.value = false;});
};const resizeViews = () => {const resizeTimer = setTimeout(() => {theMPR.resize(layout.viewIds, layout.maxViewId);clearTimeout(resizeTimer);}, 100);
};defineExpose({setLayout,
});onMounted(() => {theMPR = new MPR({elAxial: elAxial.value,elSagittal: elSagittal.value,elCoronal: elCoronal.value,elVR: elVR.value});load();theMPR.bindRenderEvent(renderHandler);});onBeforeUnmount(() => {theMPR.destroy();theMPR = null;
});
</script><style lang="scss" scoped>
$font-size: 14px;
@mixin text() {position: absolute;color: white;font-size: $font-size;font-family: Arial, Helvetica, sans-serif;text-align: left;z-index: 10;
}@mixin orient($text-align: left) {position: absolute;color: white;font-size: $font-size;text-align: $text-align;z-index: 10;
}.container3d {display: grid;grid-template-columns: 1fr 1fr;grid-template-rows: 1fr 1fr;grid-gap: 1px 1px;height: 100%;background-color: black;color: #fff;
}:deep(.el-loading-spinner) {font-size: 80px;font-weight: bold;
}:deep(.el-loading-mask .el-loading-spinner .el-loading-text) {font-size: 20px;
}.desc {@include text();top: 2px;left: 2px;
}.text_studyinfo {@include text();top: 24px;left: 2px;
}.text_wwwc {@include text();top: 2px;right: 2px;
}.text_slice {@include text();top: 24px;right: 2px;
}.orient_top {@include orient(center);top: 2px;left: calc(50% - 30px);width: 60px;
}.orient_bottom {@include orient(center);bottom: 2px;left: calc(50% - 30px);width: 60px;
}.orient_left {@include orient();top: calc(50% - 20px);left: 2px;
}.orient_right {@include orient();top: calc(50% - 20px);right: 2px;
}.axialparent {padding: 1px;border: 1px solid rgb(135, 206, 250);background-color: black;
}.sagittalparent {padding: 1px;border: 1px solid red;background-color: black;
}.coronalparent {padding: 1px;border: 1px solid green;background-color: black;
}.vrcprparent {padding: 1px;border: 1px solid white;background-color: black;
}.sliceview {position: relative;width: 100%;height: 100%;
}</style>

3. mprvr.js

把官方示例中的代码整理成一个类, MPR

1)init函数

  • 创建toolGroup,管理mpr三个窗口的操作工具,添加工具WindowLevelTool、CrosshairsTool、PanTool、ZoomTool、StackScrollTool
  • 创建vrToolGroup,管理vr窗口操作工具,添加工具TrackballRotateTool、ZoomTool、PanTool
  • 创建renderingEngine
  • 定义mpr三个 ViewportType.ORTHOGRAPHIC类型窗口, 方向分别为:Enums.OrientationAxis.AXIAL,Enums.OrientationAxis.CORONAL,Enums.OrientationAxis.SAGITTAL
  • 定义vr 一个ViewportType.VOLUME_3D类型窗口,方向指定为Enums.OrientationAxis.CORONAL

2)loadImages函数

  • 加载imageIds, 生成volume数据
  • 四个窗口添加到renderingEngine
  • 激活窗口操作工具
  • 绘制窗口,设置vr窗口配色方案

3)getSliceCount, getSliceIndex 函数

  • 获取mpr窗口slice位置,显示在右上角

4) resize函数

  • 窗口尺寸变化时,调用此函数重绘,否则显示的图像比例变形

5) bindRenderEvent, bindCameraEvent

  • 用于绑定cornerstone3D 中的IMAGE_RENDERED, CAMERA_MODIFIED事件
  • IMAGE_RENDERED发生时调用UpdateText可以绘制四个角落的文字
  • CAMERA_MODIFIED发生时可能mpr的三个窗口方向发生变化,用于以后更新方位文字

6)destory函数

删除绑定元素,清理缓存

getDicomInfo函数

  • 获取姓名,性别、年龄等信息,显示在窗口右上角
import {RenderingEngine,Enums,setVolumesForViewports,volumeLoader,getRenderingEngine,eventTarget,getEnabledElement,utilities as csUtils,cache,imageLoader
} from "@cornerstonejs/core";
import { Enums as toolsEnums, utilities } from "@cornerstonejs/tools";import cornerstoneDICOMImageLoader from "@cornerstonejs/dicom-image-loader";
import * as cornerstoneTools from "@cornerstonejs/tools";import { readTagAsString, decodeChinese, desensitizeSubstring } from "@/utils";import { renderingEngineId } from "../cornerstone3D";const {ToolGroupManager,Enums: csToolsEnums,TrackballRotateTool,StackScrollTool,WindowLevelTool,PanTool,ZoomTool,
} = cornerstoneTools;const { MouseBindings, KeyboardBindings } = csToolsEnums;
const { ViewportType } = Enums;
const { IMAGE_RENDERED, CAMERA_MODIFIED, VOI_MODIFIED } = Enums.Events;const ViewportId = Object.freeze({AXIAL: "DICOM3D_AXIAL",SAGITTAL: "DICOM3D_SAGITTAL",CORONAL: "DICOM3D_CORONAL",VOLUME: "DICOM3D_VOLUME"
});const idAxial = ViewportId.AXIAL;
const idSagittal = ViewportId.SAGITTAL;
const idCoronal = ViewportId.CORONAL;
const idVolume = ViewportId.VOLUME;const volumeId = "DICOM3D_VOLUME_ID";
const viewportIds = [idAxial, idSagittal, idCoronal, idVolume];
const mprViewportIds = [idAxial, idSagittal, idCoronal];const cameraSynchronizerId = "CAMERA_SYNCHRONIZER_ID";
const voiSynchronizerId = "VOI_SYNCHRONIZER_ID";
const toolGroupId = "MPR_TOOLGROUP_ID";
const vrToolGroupId = "VR_TOOL_GROUP_ID";const viewportColors = {[idAxial]: "rgb(135, 206, 250)",[idSagittal]: "rgb(255, 0, 0)",[idCoronal]: "rgb(0, 255, 0)",[idVolume]: "rgb(128, 128, 128)"
};const viewportReferenceLineControllable = [idAxial, idSagittal, idCoronal, idVolume];
const viewportReferenceLineDraggableRotatable = [idAxial, idSagittal, idCoronal, idVolume];
const viewportReferenceLineSlabThicknessControlsOn = [idAxial, idSagittal, idCoronal, idVolume];function getReferenceLineColor(viewportId) {return viewportColors[viewportId];
}function getReferenceLineControllable(viewportId) {const index = viewportReferenceLineControllable.indexOf(viewportId);return index !== -1;
}function getReferenceLineDraggableRotatable(viewportId) {const index = viewportReferenceLineDraggableRotatable.indexOf(viewportId);return index !== -1;
}
function getReferenceLineSlabThicknessControlsOn(viewportId) {const index = viewportReferenceLineSlabThicknessControlsOn.indexOf(viewportId);return index !== -1;
}export default class MPR {constructor(params) {this.toolGroup = null;this.vrToolGroup = null;this.renderingEngine = null;this.registered = false;this.viewportInputArray = null;this.crosshairsToolActive = true;this.loaded = false;this.selecteToolName = "";this.params = params;this.volume = null;this.init(params);}init(config = {}) {const { elAxial, elSagittal, elCoronal, elVR } = config;cornerstoneTools.addTool(CrosshairsTool);cornerstoneTools.addTool(TrackballRotateTool);cornerstoneTools.addTool(ZoomTool);cornerstoneTools.addTool(PanTool);cornerstoneTools.addTool(WindowLevelTool);this.vrToolGroup = ToolGroupManager.getToolGroup(vrToolGroupId);if (!this.vrToolGroup) {this.vrToolGroup = ToolGroupManager.createToolGroup(vrToolGroupId);this.vrToolGroup.addTool(TrackballRotateTool.toolName);this.vrToolGroup.addTool(ZoomTool.toolName, {zoomToCenter: true,invert: true,minZoomScale: 0.15,maxZoomScale: 20});this.vrToolGroup.addTool(PanTool.toolName);this.vrToolGroup.setToolActive(TrackballRotateTool.toolName, {bindings: [{mouseButton: MouseBindings.Primary // Left Click}]});this.vrToolGroup.setToolActive(ZoomTool.toolName, {bindings: [{mouseButton: MouseBindings.Secondary}]});this.vrToolGroup.setToolActive(PanTool.toolName, {bindings: [{mouseButton: MouseBindings.Auxiliary}]});}// Instantiate a rendering enginethis.renderingEngine = new RenderingEngine(renderingEngineId);this.viewportInputArray = [{viewportId: idAxial,type: ViewportType.ORTHOGRAPHIC,element: elAxial,defaultOptions: {orientation: Enums.OrientationAxis.AXIAL,background: [0, 0, 0]}},{viewportId: idSagittal,type: ViewportType.ORTHOGRAPHIC,element: elSagittal,defaultOptions: {orientation: Enums.OrientationAxis.SAGITTAL,background: [0, 0, 0]}},{viewportId: idCoronal,type: ViewportType.ORTHOGRAPHIC,element: elCoronal,defaultOptions: {orientation: Enums.OrientationAxis.CORONAL,background: [0, 0, 0]}},{viewportId: idVolume,type: ViewportType.VOLUME_3D,element: elVR,defaultOptions: {background: [0, 0, 0],orientation: Enums.OrientationAxis.CORONAL}}];// Define tool groups to add the segmentation display tool tothis.toolGroup = ToolGroupManager.getToolGroup(toolGroupId);if (!this.toolGroup) {this.toolGroup = ToolGroupManager.createToolGroup(toolGroupId);this.toolGroup.addTool(WindowLevelTool.toolName);const isMobile = window.matchMedia("(any-pointer:coarse)").matches;this.toolGroup.addTool(CrosshairsTool.toolName, {getReferenceLineColor,getReferenceLineControllable,getReferenceLineDraggableRotatable,getReferenceLineSlabThicknessControlsOn,referenceLinesCenterGapRadius: 14,mobile: {enabled: isMobile,opacity: 0.8,handleRadius: 9}});this.addManipulationBindings(this.toolGroup);}// For the crosshairs to operate, the viewports must currently be// added ahead of setting the tool active. This will be improved in the future.this.toolGroup.addViewport(idAxial, renderingEngineId);this.toolGroup.addViewport(idSagittal, renderingEngineId);this.toolGroup.addViewport(idCoronal, renderingEngineId);this.vrToolGroup.addViewport(idVolume, renderingEngineId);}destroy() {this.renderingEngine.disableElement(idVolume);this.renderingEngine.disableElement(idAxial);this.renderingEngine.disableElement(idSagittal);this.renderingEngine.disableElement(idCoronal);this.toolGroup.removeViewports(renderingEngineId);this.vrToolGroup.removeViewports(renderingEngineId);cache.purgeCache();}addManipulationBindings(toolGroup, options = {}) {const zoomBindings = [{mouseButton: MouseBindings.Secondary}];const { is3DViewport = false, enableShiftClickZoom = false, toolMap = new Map() } = options;if (enableShiftClickZoom === true) {zoomBindings.push({mouseButton: MouseBindings.Primary, // Shift Left ClickmodifierKey: KeyboardBindings.Shift});}if (!this.registered) {for (const [, config] of toolMap) {if (config.tool) {cornerstoneTools.addTool(config.tool);}}}this.registered = true;toolGroup.addTool(PanTool.toolName);toolGroup.addTool(ZoomTool.toolName, {zoomToCenter: true,invert: true,minZoomScale: 0.1,maxZoomScale: 20});if (is3DViewport) {toolGroup.addTool(TrackballRotateTool.toolName);} else {toolGroup.addTool(StackScrollTool.toolName);}toolGroup.addTool(StackScrollTool.toolName);toolGroup.setToolActive(PanTool.toolName, {bindings: [{mouseButton: MouseBindings.Auxiliary},{numTouchPoints: 1,modifierKey: KeyboardBindings.Ctrl}]});toolGroup.setToolActive(ZoomTool.toolName, {bindings: zoomBindings});// Need a binding to navigate without a wheel mousetoolGroup.setToolActive(StackScrollTool.toolName, {bindings: [{mouseButton: MouseBindings.Primary,modifierKey: KeyboardBindings.Alt},{numTouchPoints: 1,modifierKey: KeyboardBindings.Alt},{mouseButton: MouseBindings.Wheel}]});if (is3DViewport) {toolGroup.setToolActive(TrackballRotateTool.toolName, {bindings: [{mouseButton: MouseBindings.Primary}]});} else {toolGroup.setToolActive(StackScrollTool.toolName);}// Add extra tools from the toolMapfor (const [toolName, config] of toolMap) {if (config.baseTool) {if (!toolGroup.hasTool(config.baseTool)) {toolGroup.addTool(config.baseTool, toolMap.get(config.baseTool)?.configuration);}toolGroup.addToolInstance(toolName, config.baseTool, config.configuration);} else if (!toolGroup.hasTool(toolName)) {toolGroup.addTool(toolName, config.configuration);}if (config.passive) {// This can be applied during add/remove contourstoolGroup.setToolPassive(toolName);}if (config.bindings || config.selected) {toolGroup.setToolActive(toolName,(config.bindings && config) || {bindings: [{ mouseButton: MouseBindings.Primary }]});}}}async loadImages(imageIds) {let newImageIds = [...new Set(imageIds)];for (let i = 0; i < newImageIds.length; i++) {await cornerstoneDICOMImageLoader.wadouri.loadImage(newImageIds[i]).promise;}// Define a volume in memorythis.volume = await volumeLoader.createAndCacheVolume(volumeId, {imageIds: newImageIds});this.renderingEngine.setViewports(this.viewportInputArray);this.volume.load();// Set volumes on the viewportsawait setVolumesForViewports(this.renderingEngine,[{volumeId,callback: null}],viewportIds);this.toolGroup.setToolActive(CrosshairsTool.toolName, {bindings: [{ mouseButton: MouseBindings.Primary }]});this.renderingEngine.renderViewports(viewportIds);const viewport = this.renderingEngine.getViewport(idVolume);await setVolumesForViewports(this.renderingEngine, [{ volumeId }], [idVolume]).then(() => {viewport.setProperties({preset: "CT-Coronary-Arteries-2"});});this.loaded = true;}getSliceCount(viewportId) {if (!this.loaded) {return;}const viewport = this.renderingEngine.getViewport(viewportId);return viewport.getNumberOfSlices();}getSliceIndex(viewportId) {if (!this.loaded) {return;}const viewport = this.renderingEngine.getViewport(viewportId);return viewport.getSliceIndex();}resize(viewIds, maxViewId) {if (!this.loaded) return;this.renderingEngine.resize(true, true);viewIds.forEach(viewportId => {const viewport = this.renderingEngine.getViewport(viewportId);if (viewport) {const presentation = viewport.getViewPresentation();viewport.setViewPresentation(presentation);}});if (maxViewId) {this.toolGroup.setToolDisabled(CrosshairsTool.toolName);this.toolGroup.setToolEnabled(WindowLevelTool.toolName);this.toolGroup.setToolActive(WindowLevelTool.toolName, {bindings: [{mouseButton: MouseBindings.Primary}]});} else {this.toolGroup.setToolEnabled(CrosshairsTool.toolName);this.toolGroup.setToolDisabled(WindowLevelTool.toolName);this.toolGroup.setToolActive(CrosshairsTool.toolName, {bindings: [{ mouseButton: MouseBindings.Primary }]});}}bindRenderEvent(callback) {for (let i = 0; i < this.viewportInputArray.length; i++) {if (this.viewportInputArray[i].viewportId !== idVolume) {const elem = this.viewportInputArray[i].element;elem.addEventListener(IMAGE_RENDERED, callback);}}}bindCameraEvent(callback) {for (let i = 0; i < this.viewportInputArray.length; i++) {if (this.viewportInputArray[i].viewportId !== idVolume) {const elem = this.viewportInputArray[i].element;elem.addEventListener(CAMERA_MODIFIED, callback);}}}
}async function getDicomInfo(imageId, lang = "zh_CN") {const image = await imageLoader.loadAndCacheImage(imageId);const defWL = Math.round(image.windowCenter);const defWW = Math.round(image.windowWidth);const charset = image.data.string("x00080005") || "ISO_IR 100";const isUtf8 = charset.indexOf("ISO_IR 192") != -1;let studyInfo = "";let val = "";let tag = image.data.elements.x00100010; // 姓名if (tag) {val = readTagAsString(image.data.byteArray, tag.dataOffset, tag.length);}if (val) {val = decodeChinese(val, isUtf8);if (config.desensitize) {val = desensitizeSubstring(val, 1, -1);}studyInfo += val + " ";}val = image.data.string("x00101010");if (!val || val.length <= 0) {val = image.data.string("x00100030");if (val === undefined) val = "";} else {if (lang == "zh_CN") {val = val.replace(/Y|y/, "岁");val = val.replace(/M|m/, "月");val = val.replace(/D|d/, "天");}}val = val.replace(/^0+/g, "");if (val) {studyInfo += val + " ";}val = image.data.string("x00100040");if (lang == "zh_CN") {if (!val || val.length <= 0) tmp = "未知";if (val === "M" || val === "m") val = "男";else if (val === "F" || val === "f") val = "女";else val = "未知";}if (val) {studyInfo += val;}return {defWL,defWW,studyInfo};
}export { presetColors, ViewportId, getDicomInfo, loadDicom };

总结

整理cornerstone3D中的官方示例 cursor3d的代码,实现mpr功能

http://www.dtcms.com/a/430157.html

相关文章:

  • react网站开发介绍浙江省财务开发公司官网
  • 黑河百姓网免费发布信息网网站seo的主要优化内容
  • 湖南好搜网站建设公众号链接制作
  • 网站建设的目标是什么 提供了哪些栏目深圳福田口岸
  • 护肤品 网站建设策划做网站哪一家比较好
  • 网站建设的目标用户网站空间与服务器的区别
  • 公关策划公司网站源码数码网站名
  • 网站开发和网络开发区别seo可以提升企业网站的
  • 怎么注册自己网站wordpress 幻灯片 插件下载
  • 网站推广怎么做有效果杭州网站建设公司排名
  • 如何查看网站开发商石家庄网站建设seo公司
  • 外贸一站式推广服务网站开发流程任务
  • 做网站运维应该看的书主机屋wordpress建站
  • 苏州工业园区规划建设局网站哈尔滨门户网站设计报价
  • 公司名称变更网站备案怎么处理花桥网站建设公司
  • 宣城老品牌网站建设岳阳网站建设公司
  • 主题资源网站制作平台专业建设内容
  • 家纺网站设计做网站设计需求
  • 企业网站建设方案 功能规划公司内网怎么搭建
  • 天津建设网站的公司简介网站和公众号的区别是什么
  • 垦利网页设计小红书搜索优化
  • 开发电商网站要多少钱网站模板
  • 网站开发用户需求说明书宁波网站搭建定制非模板网站建设
  • 利用黑群晖做网站婚礼策划公司排名
  • 网站的反爬一般怎样做建筑公司企业愿景文案
  • 如何在自己网站上做支付宝吗深圳市网络营销公司
  • 淄博网站排名优化报价上海某家具网站建设方案
  • 秦皇岛pc端网站建设网络推广优化培训
  • 国外红色企业网站中国企业网信息查询系统
  • 如何用ftp登陆网站网站建设jiage