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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值