首页 前端知识 vue医学图像处理包cornerstone.js基本使用

vue医学图像处理包cornerstone.js基本使用

2024-05-13 10:05:07 前端知识 前端哥 959 326 我要收藏

vue医学图像处理包cornerstone.js基本使用

本文为编辑2D图像的
先上参考链接:
cornerstonejs/cornerstoneTools: A framework for tools built on top of Cornerstone. (github.com)

Introduction · cornerstone-tools (cornerstonejs.org)

Cornerstone Tools: Examples (cornerstonejs.org)

Cornerstone Tools: API Docs (cornerstonejs.org)

Modules · cornerstone-tools (cornerstonejs.org)

cornerstoneTools/docs/latest/modules/segmentation.md at master · cornerstonejs/cornerstoneTools (github.com)

🎉 🎉 🎉 CornerstoneTools 4.0 🎉 🎉 🎉 · Issue #1061 · cornerstonejs/cornerstoneTools (github.com)

安装依赖

npm install --save cornerstone-core cornerstone-math cornerstone-tools hammerjs cornerstone-web-image-loader
复制

PS:这里应该是没落下东西,以防万一,这里写一下package.json

"dependencies": {
"bootstrap": "^5.3.2",
"bootstrap-vue-next": "^0.14.10",
"cornerstone-core": "^2.6.1",
"cornerstone-math": "^0.1.10",
"cornerstone-tools": "^6.0.10",
"cornerstone-web-image-loader": "^2.1.1",
"hammerjs": "^2.0.8",
"nprogress": "^0.2.0",
"vue": "^3.3.4",
"vue-router": "^4.2.5"
},
复制

code

初始化

首先肯定是在html也就是<template>标签里面写好自己要写入的位置:

<div id="cornerstone"/>
复制

<script>标签里面引入需要的依赖

// cornerstone tool
import cornerstone from 'cornerstone-core';
import cornerstoneMath from 'cornerstone-math';
import cornerstoneTools from 'cornerstone-tools';
import Hammer from 'hammerjs';
import cornerstoneWebImageLoader from "cornerstone-web-image-loader"
// external
cornerstoneTools.external.cornerstone = cornerstone;
cornerstoneTools.external.Hammer = Hammer;
cornerstoneTools.external.cornerstoneMath = cornerstoneMath;
cornerstoneWebImageLoader.external.cornerstone = cornerstone;
// init
cornerstoneTools.init(
{
/**
* Most tools have an associated canvas or SVG cursor. Enabling this flag
* causes the cursor to be shown when the tool is active, bound to left
* click, and the user is hovering the enabledElement.
*/
showSVGCursors: true,
outlineWidth: 2
},
{
// 这里的配置项用于裁剪功能
moduleName: 'segmentation',
configuration: {
outlineWidth: 2
}
}
);
// segmentation
const { setters, getters } = cornerstoneTools.getModule('segmentation');
复制

Module属性见(后面导出裁剪后的图片要用):
Modules · cornerstone-tools (cornerstonejs.org)
下面使用的vue3,vue2也差不太多,首先看mounted里面的初始化信息(代码后面有简介):

export default defineComponent({
mounted() {
this.imageUrl = '你的图片地址';
this.tools = {
PanTool: cornerstoneTools.PanTool,
LengthTool: cornerstoneTools.LengthTool,
MagnifyTool: cornerstoneTools.MagnifyTool,
AngleTool: cornerstoneTools.AngleTool,
FreehandScissorsTool: cornerstoneTools.FreehandScissorsTool,
CircleScissorsTool: cornerstoneTools.CircleScissorsTool,
RectangleScissorsTool: cornerstoneTools.RectangleScissorsTool
}
// Make sure we have at least one element Enabled
this.element = document.querySelector('#cornerstone');
cornerstone.enable(
this.element,
{
colormap: "" // 玄学的对象,留着吧
}
);
const viewport = cornerstone.getViewport(this.element);
/*
简单列一下属性,我这里没用他们
hflip : 水平旋转
vflip : 垂直旋转
invert : 颜色反转
rotation : 旋转角度
scale : 缩放
translation : 位移
voi : 切片
windowWidth : 窗口宽度
windowCenter : 窗口中心
*/
const imageIds = [
this.imageUrl
];
// stack,使用裁剪功能需要的东西,Segmentation required
const stack = {
currentImageIdIndex: 0,
imageIds: imageIds,
};
cornerstone.loadAndCacheImage(imageIds[0]).then((image) => {
// 图片的大小
this.imgShape = [image.width, image.height];
// 图片的数据
this.imgData = image.getPixelData();
cornerstoneTools.addStackStateManager(this.element, ['stack']); // Segmentation required
cornerstoneTools.addToolState(this.element, 'stack', stack); // Segmentation required
cornerstone.displayImage(this.element, image);
cornerstone.setViewport(this.element, viewport);
// default add zoom tool to ALL currently Enabled elements
cornerstoneTools.addTool(cornerstoneTools.ZoomMouseWheelTool);
cornerstoneTools.setToolActive('ZoomMouseWheel', { mouseButtonMask: 1 })
});
},
data() {
return {
imageUrl: '',
element: null,
tools: [],
selected: '',
name: {
PanTool: 'Pan',
LengthTool: 'Length',
MagnifyTool: 'Magnify',
AngleTool: 'Angle',
FreehandScissorsTool: 'FreehandScissors',
CircleScissorsTool: 'CircleScissors',
RectangleScissorsTool: 'RectangleScissors'
},
imgData: [],
imgShape: []
}
},
...
复制

这里的this.toolsthis.name里面的数据可以参考:
Cornerstone Tools: Examples (cornerstonejs.org)

PS:截止本人写博客的时间2023.12.13,这个页面还是没有完善

methods

接下来看methods里面的方法

激活工具
activaTool(tool) {
// Adds tool to ALL currently Enabled elements
this.selected = tool;
/*
下面是将裁剪工具设置为FILL_INSIDE,也就是内部填充
还有属性:
FILL_OUTSIDE: 外部填充,
ERASE_OUTSIDE: 擦除外部,
ERASE_INSIDE: 擦除内部,
*/
if(tool.includes('Scissors')) {
cornerstoneTools.addTool(this.tools[tool], { defaultStrategy: "FILL_INSIDE" });
}else {
cornerstoneTools.addTool(this.tools[tool]);
}
cornerstoneTools.setToolEnabled(this.name[tool], { mouseButtonMask: 1 });
cornerstoneTools.setToolActive(this.name[tool], { mouseButtonMask: 1 })
},
复制

使用的时候传入工具名称就好,例如在this.tool里面的属性LengthTool

activaTool('LengthTool')
复制
清空所有基本工具

这个方法清空所有工具,除了scissors

clearAllTool() {
for(let k in this.name) {
cornerstoneTools.clearToolState(this.element, this.name[k]);
}
// 写了他才能让界面也更新清除了tool的视图
cornerstone.updateImage(this.element);
// reset viewport将视图重置位置
cornerstone.reset(this.element);
},
复制
直接保存视图,所见所得
saveRes() {
// 直接保存viewport,所见所得
cornerstoneTools.SaveAs(this.element, “你的文件名” + Date.now() + ".jpg");
},
复制

图片后缀是jpg还是png都行

※※※保存Scissors工具覆盖的区域
saveCrop() {
const labelmap2D = getters.labelmap2D(this.element).labelmap2D;
// 获取像素数据
const pixelData = labelmap2D.pixelData;
// 使用 filter 过滤出非0值
let nonZeroValues = pixelData.filter(element => element !== 0);
// 非0 的数量不为0(有mask)
if(nonZeroValues.length) {
// 初始化边界值为图像覆盖区域的的宽度和高度
let minX = this.imgShape[0];
let minY = this.imgShape[1];
let maxX = 0;
let maxY = 0;
// 创建一个新的Uint8ClampedArray,用于存储标记区数据
var roi = new Uint8ClampedArray(this.imgData.length);
// 遍历 pixelData
for (let i = 0; i < pixelData.length; i++) {
// 如果像素值不为0
if (pixelData[i] !== 0) {
// 计算像素的坐标
const x = i % this.imgShape[0];
const y = Math.floor(i / this.imgShape[0]);
// 更新边界值
minX = Math.min(minX, x);
minY = Math.min(minY, y);
maxX = Math.max(maxX, x);
maxY = Math.max(maxY, y);
// 如果mask值非零,则将对应位置的data值复制到roi数组
roi[i * 4] = this.imgData[i * 4]; // R component
roi[i * 4 + 1] = this.imgData[i * 4 + 1]; // G component
roi[i * 4 + 2] = this.imgData[i * 4 + 2]; // B component
roi[i * 4 + 3] = this.imgData[i * 4 + 3]; // Alpha component
}else {
// 如果mask值为零,则将对应位置的roi值设为0
roi[i * 4] = 0;
roi[i * 4 + 1] = 0;
roi[i * 4 + 2] = 0;
roi[i * 4 + 3] = 0; // 设置 alpha 值为 0,表示完全透明
}
}
// 计算覆盖区域的长度和宽度
const coveredWidth = maxX - minX + 1;
const coveredHeight = maxY - minY + 1;
// 下面是导出标记区域
// 创建一个Canvas元素
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// 设置Canvas的宽度和高度
canvas.width = coveredWidth;
canvas.height = coveredHeight;
// 创建ImageData对象,用于设置图像数据
const imageData = ctx.createImageData(coveredWidth, coveredHeight);
// 将roi数据复制到ImageData对象中,但是要根据有效区域进行偏移
for (let i = 0; i < coveredHeight; i++) {
for (let j = 0; j < coveredWidth; j++) {
const sourceIndex = ((minY + i) * this.imgShape[0] + minX + j) * 4;
const targetIndex = (i * coveredWidth + j) * 4;
for (let k = 0; k < 4; k++) {
imageData.data[targetIndex + k] = roi[sourceIndex + k];
}
}
}
// 将ImageData对象绘制到Canvas上
ctx.putImageData(imageData, 0, 0);
// 将Canvas转换为DataURL
const dataURL = canvas.toDataURL('image/png');
// 创建一个虚拟链接
const a = document.createElement('a');
// 设置链接的href属性为DataURL
a.href = dataURL;
// 设置链接的下载属性和文件名
let fileName = “自己设置自己的文件名字”;
// 文件名加上随机值
a.download = fileName + Math.floor(Math.random() * new Date().getTime()) + '.png';
// 模拟点击链接以触发下载
a.click();
}else {
alert('请选择一个区域');
}
},
复制

最后保存的是png后缀的,只有标记区域,就算是不规则形状也是
其余区域透明

undo框选

PS:框选不能用我的clearAllTool函数清除

myUndo() {
setters.undo(this.element);
},
复制
redo框选
myRedo() {
setters.redo(this.element);
}
复制
清除所有框选区域
clearMask() {
const labelmap2D = getters.labelmap2D(this.element).labelmap2D;
const pixelData = labelmap2D.pixelData;
pixelData.fill(0);
setters.updateSegmentsOnLabelmap2D(labelmap2D)
// 写了他才能让界面也更新清除了mask的视图
cornerstone.updateImage(this.element);
},
复制
还原所有操作

这里需要调用前面写好的两个函数了就

resetAll() {
this.clearAllTool();
this.clearMask();
}
复制
转载请注明出处或者链接地址:https://www.qianduange.cn//article/8457.html
标签
图像处理
评论
还可以输入200
共0条数据,当前/页
发布的文章

JQuery中的load()、$

2024-05-10 08:05:15

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!