医学影像DICOM 处理(一)
与医学、医院相关的项目搞起来真的是要命。。。完全生疏的方向 。。。其中合作伙伴说,让我用AI直接生成代码就可以了。。我就在想,区域链、人工智能、AI等等这些喙头啥时候是个头儿。。。资本用来圈钱的各种概念总是那么不务实!
DICOM是医学图像和相关信息的国际标准,它定义了满足临床需要的可用于数据交换的医学图像格式,被广泛用于放射、成像的诊疗诊断设备。也就是说,在医院放射科使用的设备上读取的影像基本都是DICOM格式,包括CT、MRI、超声等的讲解及技术规范。咱就不展开讨论了,网上一堆,大家去查阅即可。
咱的项目基本都是趋于实战,很少讲原理,因为有些原理讲起来可能我就没那么多心血来写作了,那么大篇幅的进行整理及输出。我还有我的事情要做。。。
下来就讲讲如何在web端进行dicom图像的展示有相关操作。本次分享实现两点功能:
1、影像加载
2、影像标注
其他功能后续再一一补充实现 。
项目安装以下依赖:
"cornerstone-core": "^2.6.1", "cornerstone-math": "^0.1.10", "cornerstone-tools": "^6.0.10", "cornerstone-wado-image-loader": "^4.13.2", "dicom-parser": "^1.8.21", "hammerjs": "^2.0.8",
在你项目中创建一个Vue组件页面粘贴以下代码实现一个预览组件:
<template> <div v-loading="loading" class="dicom" ref="dicomImage"> <span v-if="loadFailed">加载失败</span> </div> </template> <script> import cornerstone from 'cornerstone-core'; import dicomParser from 'dicom-parser'; import wadoImageLoader from 'cornerstone-wado-image-loader'; import cornerstoneMath from "cornerstone-math" import cornerstoneTools from "cornerstone-tools" import Hammer from "hammerjs" // 配置 Web Worker var config = { webWorkerPath: "cornerstone-wado-image-loader/cornerstoneWADOImageLoaderNoWebWorkers.bundle.min.js", taskConfiguration: { decodeTask: { codecsPath: "cornerstone-wado-image-loader/cornerstoneWADOImageLoaderCodecs.js" } } }; wadoImageLoader.webWorkerManager.initialize(config); cornerstoneTools.external.cornerstone = cornerstone; cornerstoneTools.external.cornerstoneMath = cornerstoneMath; cornerstoneTools.external.Hammer = Hammer; // 初始化cornerstoneTools工具 cornerstoneTools.init({ mouseEnabled: true,// 当元素被启用时,是否监听鼠标事件 touchEnabled: true, // 当元素被启用时,是否监听触摸事件 globalToolSyncEnabled: true,// 全局工具同步 showSVGCursors: true, // 显示svg光标 autoResizeViewports: true,// 自动调整视口大小 lineDash: [4, 4] // 虚线样式 }); wadoImageLoader.external.cornerstone = cornerstone; wadoImageLoader.external.dicomParser = dicomParser; export default { name: 'DicomPreview', props: { imageId: { type: String, required: true } }, data() { return { loading: true, loadFailed: false, } }, // watch:{ // imageId(newValue,oldValue){ // var url = `wadouri:${this.imageId}`; // this.loadAndViewImage(url); // } // }, mounted() { var url = `wadouri:${this.imageId}`; this.loadAndViewImage(url); }, methods: { loadAndViewImage(imageId) { let element = this.$refs.dicomImage const lengthProps = { configuration: { handleRadius: 1, drawHandlesOnHover: true, hideHandlesIfMoving: true, digits: 2 } }; const LengthTool = cornerstoneTools.LengthTool; //添加获取到的窗宽,窗高工具 cornerstoneTools.addTool(LengthTool, lengthProps); cornerstoneTools.addToolForElement(element, LengthTool, lengthProps); // 绑定工具操作功能到鼠标左键 cornerstoneTools.setToolActive('Length', { mouseButtonMask: 1 }) //所有工具在此行前添加 cornerstone.enable(element) cornerstone.loadAndCacheImage(imageId).then((image) => { var viewport = cornerstone.getDefaultViewportForImage(element, image); cornerstone.displayImage(element, image, viewport); this.loading = false this.loadFailed = false this.$nextTick(this.enableLengthTools()) }, (err) => { console.log(err) this.loading = false this.loadFailed = true }); }, enableLengthTools() { }, clearTools() { cornerstoneTools.clearToolState(element, 'Length'); cornerstone.updateImage(element); // 刷新图像 } } } </script> <style lang="scss" scoped> .dicom { height: 100%; width: 500px; height: 500px; } </style>
在使用的父页面中引入此子组件使用,并传参数即可:
import DicomPreview from './dicom/index.vue' components: { DicomPreview }, data() { return { lineChartData: lineChartData.newVisitis, imageIds: [{ dicIds: 'http://47.107.255.46:1000/wado/SERVERAE?requestType=WADO&studyUID=1.2.392.200036.9116.2.5.1.3268.2047634718.1719992618.411948&seriesUid=840.113747.1719992443.59096.130764.1965210712314854.1337&objectUid=4.59096.130764.1965210712314854.1341&contentType=application%2Fdicom' }, { dicIds: "https://tools.cornerstonejs.org/examples/assets/dicom/bellona/chest_lung/1.dcm" }] } }, <el-row :gutter="20"> <el-col :span="12"> <div class="w-100 flex-row"> <dicom-preview :imageId="imageIds[1].dicIds" style="width: 500px;height:500px;"></dicom-preview> </div> </el-col> <el-col :span="12"> <dicom-preview :imageId="imageIds[0].dicIds" style="width: 500px;height:500px;"></dicom-preview> </el-col> </el-row>
如你所见,为啥两张影像显示的单位不同呢?来我们分析一下源码显示单位的逻辑:
第一个影像数据为:
第二个影像数据为:
可以看到,虽然都为影像图片,但是有些输出设备输出dicom时未携带横纵像素间距导致无法将pixel转为mm单位所致!
再贴两个页面,你自己创建两个html文件,将代码分别粘贴进去,使用浏览器打开查看体验即可:
web.html页面:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="https://unpkg.com/hammerjs@2.0.8/hammer.js"></script> <script src="https://unpkg.com/cornerstone-core@2.6.1/dist/cornerstone.js"></script> <script src="https://unpkg.com/cornerstone-math@0.1.10/dist/cornerstoneMath.min.js"></script> <script src="https://unpkg.com/cornerstone-wado-image-loader@4.1.3/dist/cornerstoneWADOImageLoader.bundle.min.js"></script> <script src="https://unpkg.com/cornerstone-web-image-loader@2.1.1/dist/cornerstoneWebImageLoader.min.js"></script> <script src="https://unpkg.com/cornerstone-tools@6.0.7/dist/cornerstoneTools.js"></script> <script src="https://unpkg.com/dicom-parser@1.8.13/dist/dicomParser.min.js"></script> </head> <body> <!-- 用于加载图片的div区域 --> <div id="dicomImage" style="width: 512px;height: 512px;"></div> </body> <script> // 注册并挂载cornerstone及其cornerstoneTools,固定操作 cornerstoneTools.external.cornerstone = cornerstone; cornerstoneTools.external.cornerstoneMath = cornerstoneMath; cornerstoneTools.external.Hammer = Hammer; cornerstoneWADOImageLoader.external.dicomParser = dicomParser; cornerstoneWADOImageLoader.external.cornerstone = cornerstone; // imageId就是cornerstone要求的.dcm图片地址,例如:var imageId = "wadouri:http://127.0.0.1:6699/ctdcm1.dcm"; var imageId = "wadouri:https://tools.cornerstonejs.org/examples/assets/dicom/bellona/chest_lung/1.dcm"; // 初始化cornerstoneTools工具 cornerstoneTools.init(); // 获取要用于加载图片的div区域 var element = document.getElementById('dicomImage'); //激活获取到的用于图片加载的区域 cornerstone.enable(element); // 从cornerstoneTools库中获取窗宽,窗高工具 const WwwcTool = cornerstoneTools.WwwcTool; //添加获取到的窗宽,窗高工具 cornerstoneTools.addTool(WwwcTool); // 绑定工具操作功能到鼠标左键 cornerstoneTools.setToolActive('Wwwc', { mouseButtonMask: 1 }) //使用loadAndCacheImage()方法加载并缓存图片,然后使用displayImage()方法显示图片。 cornerstone.loadAndCacheImage(imageId).then(function (image) { cornerstone.displayImage(element, image); }) </script> </html>
web2.html页面:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>CornerstoneTools Demo</title> <script src="https://unpkg.com/cornerstone-core@2.3.0/dist/cornerstone.js"></script> <script src="https://unpkg.com/cornerstone-wado-image-loader@3.3.1/dist/cornerstoneWADOImageLoader.min.js"></script> <script src="https://unpkg.com/dicom-parser@1.8.7/dist/dicomParser.min.js"></script> <script src="https://unpkg.com/cornerstone-tools@6.0.7/dist/cornerstoneTools.js"></script> <script src="https://unpkg.com/cornerstone-math@0.1.10/dist/cornerstoneMath.min.js"></script> </head> <body> <div id="dicomImage" style="width: 512px;height: 512px;"></div> <button onclick="EllipticalRoiToolFun()">椭圆测量</button> <button onclick="removeTool()">清除工具</button> <button onclick="hideLabel()">隐藏标注</button> <button onclick="showLabel()">显示标注</button> <button onclick="getToolInfo()">获取指定工具的信息</button> <button onclick="clearMarker()">清除图像上的所有标注</button> <script> let imageId = "wadouri:" + "http://47.107.255.46:1000/wado/SERVERAE?requestType=WADO&studyUID=1.2.392.200036.9116.2.5.1.3268.2047634718.1719992618.411948&seriesUid=840.113747.1719992443.59096.130764.1965210712314854.1337&objectUid=4.59096.130764.1965210712314854.1341&contentType=application%2Fdicom"; let element = document.querySelector("#dicomImage"); /*** * @description cornerstone初始化 * @param imageId */ function cornerstoneInit(imageId) { cornerstoneTools.external.cornerstone = cornerstone; cornerstoneTools.external.cornerstoneMath = cornerstoneMath; cornerstoneWADOImageLoader.external.cornerstone = cornerstone; // 初始化cornerstoneTools cornerstoneTools.init({ mouseEnabled: true,// 当元素被启用时,是否监听鼠标事件 touchEnabled: false, // 当元素被启用时,是否监听触摸事件 globalToolSyncEnabled: true,// 全局工具同步 showSVGCursors: true, // 显示svg光标 autoResizeViewports: true,// 自动调整视口大小 lineDash: [4, 4] // 虚线样式 }); cornerstone.enable(element); // 初始并启用绘制的元素 const ApiTool = cornerstoneTools[`EllipticalRoiTool`]; cornerstoneTools.addToolForElement(element, ApiTool); // 给指定启用元素添加指定工具 // cornerstoneTools.addTool(ApiTool);或者,直接给全部启用元素添加指定工具 loadImage(element, imageId); // 加载并且绘制影像到指定元素上 } /*** * @description 加载并图像 * @param element 承载影像的容器div元素 * @param imageId 影像Id */ function loadImage(element, imageId) { cornerstone.loadAndCacheImage(imageId).then(image => { cornerstone.displayImage(element, image); // 渲染影像到指定元素 }) } /*** * @description 椭圆测量 * @constructor */ function EllipticalRoiToolFun(){ const options = {mouseButtonMask: 1}; setToolActive('EllipticalRoi',options); } /*** *@description 获取已添加的指定工具 , 可以查看工具当前的mode状态 * mode: "disabled" , "active" */ function getTool(toolName){ const tools = cornerstoneTools.getToolForElement(element, toolName); console.log("已添加的工具 " + toolName +" 信息") return tools } /*** * @description 给指定启用元素激活指定工具 * @param toolName 工具名 * @param element 影像渲染元素 * @param options 公户配置项 */ function setToolActive(toolName,options){ cornerstoneTools.setToolActiveForElement(element, toolName, options); // cornerstoneTools.setToolActive(toolName, options); 或者,直接激活全部启用元素的指定工具 } /*** *@description 清除工具 */ function removeTool() { cornerstoneTools.removeToolForElement(element,'EllipticalRoi'); // 给指定启用元素清除指定工具 // cornerstoneTools.removeTool(toolName); 或者,直接清除全部启用元素的指定工具 } /*** * @description 隐藏标注 * @desc 特此说明,当需要重新隐藏标注时,直接将工具状态禁用即可 * @param toolName 工具名 */ function hideLabel(){ cornerstoneTools.setToolDisabledForElement(element,'EllipticalRoi'); // cornerstoneTools.setToolDisabled(toolItem.toolName); 或者,直接将全部的启用元素隐藏标注 cornerstone.updateImage(element); // 刷新图像, } /*** * @description 显示标注 * @desc 特此说明,当需要重新显示标注时,需要重新将所有工具激活即可 * @param toolName 工具集 */ function showLabel(toolName){ EllipticalRoiToolFun(); cornerstone.updateImage(element); // 刷新图像 , 需要重新刷新 } /*** * @description 获取指定工具的信息 * @constructor */ function getToolInfo() { console.log(getTool('EllipticalRoi')); } /*** * @description 清除图像上的所有标注,永久清除 * @desc 当需要清除图像上显示的测量标注时,需要先清空工具的 state 记录 */ function clearMarker(){ cornerstoneTools.clearToolState(element, 'EllipticalRoi'); cornerstone.updateImage(element); // 刷新图像 } cornerstoneInit(imageId); </script> </body> </html>
右键使用浏览器打开预览即可。细节的代码注释则不进行讲解了,自己研究查看。
下面给一些官方API文档连接:打开自行研读哦。
原文地址:https://blog.csdn.net/yunhuaikong/article/details/143664039
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!