如何用Three.js DataArrayTexture渲染DICOM或单位置NRRD图像?
实现Three.js Texture2DArray风格的DICOM/NRRD体数据渲染
方案2:基于NRRDLoader的直接实现(推荐)
Three.js的NrrdLoader加载3D体数据后,可直接提取原始像素数组和维度信息,用来创建DataArrayTexture,完全匹配你想要的texture2darray示例效果:
加载NRRD并提取体数据
使用NrrdLoader加载后,回调返回的volume对象包含体数据的核心信息:import * as THREE from 'three'; import { NrrdLoader } from 'three/addons/loaders/NrrdLoader.js'; const loader = new NrrdLoader(); loader.load('your-volume.nrrd', (volume) => { // 提取体数据的尺寸和原始像素数组 const { width, height, depth, data } = volume; // 创建DataArrayTexture const textureArray = new THREE.DataArrayTexture( data, // 合并后的体数据数组 width, // 单切片宽度 height, // 单切片高度 depth // Z轴切片数量 ); // 配置纹理参数,匹配数据格式 textureArray.format = THREE.RedFormat; // 单通道体数据用RedFormat,多通道按需调整 textureArray.type = THREE.UnsignedByteType; // 匹配NRRD的数据类型(如Uint16则用UnsignedShortType) textureArray.minFilter = THREE.LinearFilter; textureArray.magFilter = THREE.LinearFilter; textureArray.wrapR = THREE.ClampToEdgeWrapping; // Z轴边界不重复 textureArray.needsUpdate = true; // 后续即可像texture2darray示例一样使用该纹理 // 比如创建平面材质,在Shader中采样指定Z切片 });Shader中采样Texture2DArray
参考示例的Shader逻辑,传入切片索引即可渲染对应Z层:uniform sampler2DArray uTextureArray; uniform float uSliceIndex; uniform vec2 uResolution; void main() { vec2 uv = gl_FragCoord.xy / uResolution; gl_FragColor = texture(uTextureArray, vec3(uv, uSliceIndex)); }
方案1:前端直接合并DICOM切片(无需预生成数组文件)
如果你不想转NRRD,可以直接在前端解析DICOM切片并合并,跳过OpenGL处理步骤:
解析DICOM切片
使用dicom-parser库解析每个DICOM文件,提取像素数据和Z轴位置信息:import dicomParser from 'dicom-parser'; // 假设已获取所有DICOM文件的File对象数组 const dicomFiles = [...]; const slices = []; for (const file of dicomFiles) { const arrayBuffer = await file.arrayBuffer(); const dataSet = dicomParser.parseDicom(arrayBuffer); // 提取像素数据(注意DICOM可能有压缩格式,需额外处理) const pixelData = dataSet.byteArray.slice( dataSet.elements.x7fe00010.dataOffset, dataSet.elements.x7fe00010.dataOffset + dataSet.elements.x7fe00010.length ); // 提取Z轴位置(用InstanceNumber或ImagePositionPatient的Z值排序) const zPosition = dataSet.elements.x00200013 ? dataSet.elements.x00200013.value[0] : 0; slices.push({ pixelData, width: dataSet.elements.x00280010.value[0], height: dataSet.elements.x00280011.value[0], zPosition }); }排序并合并切片
按Z轴位置排序后,将所有切片的像素数组合并为一个大数组:// 按Z轴位置排序切片 slices.sort((a, b) => a.zPosition - b.zPosition); const width = slices[0].width; const height = slices[0].height; const depth = slices.length; // 创建合并后的体数据数组 const mergedData = new Uint8Array(width * height * depth); slices.forEach((slice, index) => { mergedData.set(slice.pixelData, index * width * height); }); // 用合并后的数组创建DataArrayTexture,步骤同方案2 const textureArray = new THREE.DataArrayTexture(mergedData, width, height, depth); // ... 配置纹理参数 ...
注意事项
- 确保DICOM/NRRD的所有切片尺寸一致,否则无法创建
DataArrayTexture - DICOM像素数据可能存在位深、压缩、窗宽窗位等问题,需根据实际情况做预处理
- WebGL 2.0支持
Texture2DArray,确保你的环境启用了WebGL 2.0
内容的提问来源于stack exchange,提问作者linkun
相关产品推荐
相关产品推荐

