Vue+vtk.js+itk生成一组.dcm文件的三维模型
相关网站
itk-wasm官网: itk-wasm. – 前端用itk-wasm
itk-wasm包: itk-wasm包.
itk-github: itk-github.
vtk官网实例: vtk官网实例.
vtk-github: vtk-github.
创建vue项目
npm create vite@latest
安装包以及配置
npm install @itk-wasm/dicom
npm install @itk-wasm/image-io
npm install @itk-wasm/mesh-io
npm install vite-plugin-static-copy
npm install @kitware/vtk.js
配置:vite.config.js
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import { viteStaticCopy } from 'vite-plugin-static-copy';
// https://vite.dev/config/
export default defineConfig({
optimizeDeps: {
exclude: ['itk-wasm', '@itk-wasm/image-io']
},
plugins: [
vue(),
// put lazy loaded JavaScript and Wasm bundles in dist directory
viteStaticCopy({
targets: [
// { src: 'dist/pipelines/*', dest: 'pipelines' },
{
src: 'node_modules/@itk-wasm/image-io/dist/pipelines/*.{js,wasm,wasm.zst}',
dest: 'pipelines'
},
{
src: 'node_modules/@itk-wasm/mesh-io/dist/pipelines/*.{js,wasm,wasm.zst}',
dest: 'pipelines'
}
]
})
]
});
仿照官网的例子显示三维模型
参照官网的四个格子的例子
这里.dcm数据通过input上传,再通过itk-wasm转成vtk格式
submitUpload (evt) {
const files = evt.target.files;
readImageDicomFileSeries({ inputImages: Array.from(files), webWorkerPool: null, singleSortedSeries: false }).then((data) => {
console.log(data)
const imageData = vtkITKHelper.convertItkToVtkImage(data.outputImage) //最终要的数据格式
})
},
如果想用官网的例子,https://kitware.github.io/vtk-js/examples/QuadView.html为官网的四个格子的例子代码,
把这句话改成自己的数据就行
const im = imageData //最终要的数据格式
我把其他三个格子删除,仅保留三维模型的代码,以下为全部代码
<template>
<div>
<input ref="img-upload-input" type="file" multiple @change="submitUpload">
<div id="test1" style="height: 500px;width: 500px;"></div>
</div>
</template>
<script>
import { readImageDicomFileSeries } from "@itk-wasm/dicom";
import '@kitware/vtk.js/favicon';
// Load the rendering pieces we want to use (for both WebGL and WebGPU)
import '@kitware/vtk.js/Rendering/Profiles/Volume';
import '@kitware/vtk.js/Rendering/Misc/RenderingAPIs';
import vtkITKHelper from '@kitware/vtk.js/Common/DataModel/ITKHelper'
import '@kitware/vtk.js/favicon';
// Load the rendering pieces we want to use (for both WebGL and WebGPU)
import '@kitware/vtk.js/Rendering/Profiles/Volume';
// Force DataAccessHelper to have access to various data source
import '@kitware/vtk.js/IO/Core/DataAccessHelper/HtmlDataAccessHelper';
import '@kitware/vtk.js/IO/Core/DataAccessHelper/HttpDataAccessHelper';
import '@kitware/vtk.js/IO/Core/DataAccessHelper/JSZipDataAccessHelper';
import '@kitware/vtk.js/Rendering/Profiles/Volume'
import vtkVolume from '@kitware/vtk.js/Rendering/Core/Volume'
import vtkVolumeMapper from '@kitware/vtk.js/Rendering/Core/VolumeMapper'
import vtkFullScreenRenderWindow from '@kitware/vtk.js/Rendering/Misc/FullScreenRenderWindow'
import '@kitware/vtk.js/favicon';
// Load the rendering pieces we want to use (for both WebGL and WebGPU)
import '@kitware/vtk.js/Rendering/Profiles/Volume';
import '@kitware/vtk.js/Rendering/Misc/RenderingAPIs';
import vtkBoundingBox from '@kitware/vtk.js/Common/DataModel/BoundingBox';
import vtkColorTransferFunction from '@kitware/vtk.js/Rendering/Core/ColorTransferFunction';
import vtkPiecewiseFunction from '@kitware/vtk.js/Common/DataModel/PiecewiseFunction';
import vtkVolumeProperty from '@kitware/vtk.js/Rendering/Core/VolumeProperty';
export default {
name: 'HelloWorld',
methods: {
submitUpload (evt) {
const files = evt.target.files;
readImageDicomFileSeries({ inputImages: Array.from(files), webWorkerPool: null, singleSortedSeries: false }).then((data) => {
// webWorker.terminate();
// printImage(image);
console.log(data)
const imageData = vtkITKHelper.convertItkToVtkImage(data.outputImage)
console.log(imageData)
this.testDemo(imageData)
})
},
testDemo (source) {
const renderMainBox = document.getElementById('test1')
const fullScreenRenderer = vtkFullScreenRenderWindow.newInstance({
container: renderMainBox,
background: [0, 0, 0]
})
const renderer = fullScreenRenderer.getRenderer()
const renderWindow = fullScreenRenderer.getRenderWindow()
const volume = vtkVolume.newInstance();
const mapper = vtkVolumeMapper.newInstance();
mapper.setInputData(source)
volume.setMapper(mapper)
const sampleDistance =
0.7 *
Math.sqrt(
source
.getSpacing()
.map((v) => v * v)
.reduce((a, b) => a + b, 0)
);
mapper.setSampleDistance(sampleDistance);
mapper.setComputeNormalFromOpacity(false);
mapper.setGlobalIlluminationReach(0.0);
mapper.setVolumetricScatteringBlending(0.5);
mapper.setVolumeShadowSamplingDistFactor(5.0);
const volProp = vtkVolumeProperty.newInstance();
volProp.setInterpolationTypeToLinear();
volume
.getProperty()
.setScalarOpacityUnitDistance(
0,
vtkBoundingBox.getDiagonalLength(source.getBounds()) /
Math.max(...source.getDimensions())
);
volProp.setGradientOpacityMinimumValue(0, 0);
const dataArray =
source.getPointData().getScalars() || source.getPointData().getArrays()[0];
const dataRange = dataArray.getRange();
volume
.getProperty()
.setGradientOpacityMaximumValue(0, (dataRange[1] - dataRange[0]) * 0.05);
volProp.setShade(true);
volProp.setUseGradientOpacity(0, false);
volProp.setGradientOpacityMinimumOpacity(0, 0.0);
volProp.setGradientOpacityMaximumOpacity(0, 1.0);
// volProp.setAmbient(0.0);
volProp.setDiffuse(2.0);
volProp.setSpecular(0.0);
volProp.setSpecularPower(0.0);
volProp.setUseLabelOutline(false);
// volProp.setLabelOutlineThickness(2);
volume.setProperty(volProp);
const cam = renderer.getActiveCamera();
cam.setPosition(0, 0, 0);
cam.setFocalPoint(-1, -1, 0);
cam.setViewUp(0, 0, -1);
renderer.addVolume(volume)
const pf = vtkPiecewiseFunction.newInstance();
pf.addPoint(0, 0.0);
pf.addPoint(100, 0.0);
pf.addPoint(3120, 1.0);
volume.getProperty().setScalarOpacity(0, pf);
const ctf = vtkColorTransferFunction.newInstance();
ctf.addRGBPoint(200.0, 1.0, 1.0, 1.0);
ctf.addRGBPoint(2000.0, 1.0, 1.0, 1.0);
volume.getProperty().setRGBTransferFunction(0, ctf);
renderer.resetCamera()
renderer.resetCameraClippingRange()
renderWindow.render()
},
}
}
</script>
<style scoped>
</style>
最终效果:
另外可能存在的问题:这个文件获取不到导致不显示
最后这个问题主要是需要vpn,或者直接把这个文件下下来,网页端不推荐直接使用vtk,可以用cornerstone3D