cornerstonejs / dicomParser

JavaScript parser for DICOM Part 10 data
MIT License
712 stars 228 forks source link

How dicom-parser.js works with vtk.js to achieve dicom file display #256

Closed SuperLuckyKris closed 1 year ago

SuperLuckyKris commented 1 year ago

I'm not sure if I'm writing this correctly, so please enlighten me

The code is as follows render3DModel (dicomData) { // 使用dicom-parser解析DICOM文件 const byteArray = new Uint8Array(dicomData) const dataSet = DICOMParser.parseDicom(byteArray)

  console.log("dataSet",dataSet.byteArray)
  // 获取图像数据的字节数组
  const pixelDataByteArray = dataSet.byteArray

  // 获取图像尺寸和像素间隔,如果不存在则设置默认值
  const rows = dataSet.uint16('x00280010') || 1 // 图像行数,默认为1
  const columns = dataSet.uint16('x00280011') || 1 // 图像列数,默认为1
  const slices = dataSet.uint16('x00540081') || 1 // 图像层数,默认为1
  const pixelSpacingX = dataSet.floatString('x00280030', 0) || 1 // X轴像素间隔,默认为1
  const pixelSpacingY = dataSet.floatString('x00280030', 1) || 1 // Y轴像素间隔,默认为1
  const sliceSpacing = dataSet.floatString('x00180088') || 0 // 图像切片间隔,默认为0

  // 1.typedArray传递给vtk的dataArray
  // 将图像数据的字节数组转换为JavaScript数组
  const dicomDataArray = Array.from(pixelDataByteArray)
  // 创建vtkDataArray,并将DICOM像素数据填充到数组中
  const dataArray = vtkDataArray.newInstance({
    numberOfComponents: 1, // 单通道灰度图像
    values: dicomDataArray,
    name: 'DICOM_PixelData',
  })
  // 2.生成vtkImageData
  // 创建vtkImageData,并设置图像尺寸和像素间隔
  const imageData = vtkImageData.newInstance()
  imageData.setDimensions(rows, columns, slices)
  imageData.setSpacing(pixelSpacingX, pixelSpacingY, sliceSpacing)
  // 将vtkDataArray设置为vtkImageData的Scalars
  imageData.getPointData().setScalars(dataArray)

  // 3生成vtkVolumeMapper
  // 创建vtkVolumeMapper
  const volumeMapper = vtkVolumeMapper.newInstance()
  volumeMapper.setInputData(imageData)
  // 4生成vtkVolume
  const volume = vtkVolume.newInstance()
  volume.setMapper(volumeMapper)
  // 5把volume添加到由vtk的renderwindow获取的renderer里面
  // 使用vtk.js创建vtkFullScreenRenderWindow
  const container = document.getElementById('vtk-container')
  const fullScreenRenderer = vtkFullScreenRenderWindow.newInstance({
    container: container,
    background: [0, 0, 0],
  })

  try {
    // 将vtkVolume添加到渲染器并渲染
    fullScreenRenderer.getRenderer().addVolume(volume)
    fullScreenRenderer.getRenderWindow().render()
  } catch (error) {
    console.error('渲染3D图像时出现错误:', error)
  } finally {
    console.log('结束')
  }
},
aodong8808 commented 1 year ago

https://github.com/QSolutionsLLC/cornerstone-vtk-mpr/blob/master/README.md 你可以参考一下这个

yagni commented 1 year ago

It depends on what you're trying to do. For example: which modalities are you wanting to display: Dose, CT, PET, etc.? (0054,0081) only exists for Nuclear Medicine and PET. Dose files contain the entire dose volume as a single block; image series (CT, PET, MR, etc.) have each slice as a separate file. Are you wanting to display a volume as a whole, or just a single 2D image at a time?

From the dicomParser side, you're going to want to just pass in the pixel data, not the whole byte array. See the "Usage" section in README for an example of getting the pixel data bytes (the pixelData variable there is what you'd pass to vtk).

This VTK example might be helpful as well.

SuperLuckyKris commented 1 year ago

thank you for your reply I modified the code, the pixel data of the dicom file should be passed this time, but nothing is displayed after running, is it my mistake?

I just got rid of medical imaging, and I am still not familiar with it, please guide me

test () { axios.get('src/views/modules/generator/demo.dcm', { responseType: 'arraybuffer' }).then(response => { this.render3DModel(response.data) }).catch(error => { console.error(error)

}) },

render3DModel (dicomData) {

const byteArray = new Uint8Array(dicomData) const dataSet = DICOMParser.parseDicom(byteArray)

const pixelDataElement = dataSet.elements.x7fe00010 const pixelData = new Int16Array(dataSet.byteArray.buffer, pixelDataElement.dataOffset, pixelDataElement.length / 2)

const rows = dataSet.uint16('x00280010') || 1 const columns = dataSet.uint16('x00280011') || 1 const slices = dataSet.uint16('x00540081') || 1

const pixelSpacingX = dataSet.floatString('x00280030', 0) || 1 const pixelSpacingY = dataSet.floatString('x00280030', 1) || 1 const sliceSpacing = dataSet.floatString('x00180088') || 0

console.log("Rows:", rows); console.log("Columns:", columns); console.log("Slices:", slices); console.log("Pixel Spacing X:", pixelSpacingX); console.log("Pixel Spacing Y:", pixelSpacingY); console.log("Slice Spacing:", sliceSpacing);

const dataArray = vtkDataArray.newInstance({ numberOfComponents: 1, values: Array.from(pixelData), dataType: 'Int16Array', name: 'scalars' })

const imageData = vtkImageData.newInstance() imageData.setDimensions(rows, columns, slices) imageData.setSpacing(pixelSpacingX, pixelSpacingY, sliceSpacing)

imageData.getPointData().setScalars(dataArray)

const volumeMapper = vtkVolumeMapper.newInstance() volumeMapper.setInputData(imageData)

const volume = vtkVolume.newInstance() volume.setMapper(volumeMapper)

const container = document.getElementById('vtk-container') const fullScreenRenderer = vtkFullScreenRenderWindow.newInstance({ container: container, background: [1, 1, 1] })

try {

fullScreenRenderer.getRenderer().addVolume(volume)
fullScreenRenderer.getRenderer().resetCamera()
fullScreenRenderer.getRenderer().resetCameraClippingRange()
fullScreenRenderer.getRenderWindow().render()

} catch (error) { console.error('erro:', error) } finally { console.log('end') } },

------------------ 原始邮件 ------------------ 发件人: "cornerstonejs/dicomParser" @.>; 发送时间: 2023年7月26日(星期三) 晚上10:15 @.>; @.**@.>; 主题: Re: [cornerstonejs/dicomParser] How dicom-parser.js works with vtk.js to achieve dicom file display (Issue #256)

It depends on what you're trying to do. For example: which modalities are you wanting to display: Dose, CT, PET, etc.? (0054,0081) only exists for Nuclear Medicine and PET. Dose files contain the entire dose volume as a single block; image series (CT, PET, MR, etc.) have each slice as a separate file. Are you wanting to display a volume as a whole, or just a single 2D image at a time?

From the dicomParser side, you're going to want to just pass in the pixel data, not the whole byte array. See the "Usage" section in README for an example of getting the pixel data bytes (the pixelData variable there is what you'd pass to vtk).

This VTK example might be helpful as well.

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you authored the thread.Message ID: @.***>

yagni commented 1 year ago

@1413194910 You probably want to default slice spacing to > 0. Other than that, your DICOM code looks reasonable. For the VTK side, you'll need to ask elsewhere, though. Try dannyrb's repo that @aodong8808 linked above (this file looks like a good place to start) or the vtk.js repo. If you have DICOM-specific questions, feel free to reopen and ask here.