vtk.js

vtk.js


绘制2D云图

<h3>1. 从数据中提取和处理</h3> <pre><code>let renderData = getCludeData(data, config.dataSource); const [minL, maxL] = d3.extent(renderData); let colorInterpolator = interpolateColor(config.color, minL, maxL);</code></pre> <ul> <li>getCludeData(data, config.dataSource):这个函数根据数据源配置从原始数据中提取要渲染的部分。这里 data 是原始数据,config.dataSource 是指定数据来源的配置。</li> <li>d3.extent(renderData):使用 D3.js 库的 extent 方法计算 renderData 的最小值和最大值。这个范围用于颜色映射。</li> <li>interpolateColor(config.color, minL, maxL):创建一个颜色插值器,使用 config.color 中的颜色来映射 minL 到 maxL 范围内的数据值。这个插值器将数据值转换为相应的颜色。</li> </ul> <h3>2. 创建图像数据并设置颜色</h3> <pre><code>const ImgData = new ImageData(data.x_grid, data.y_grid); for (let i = 0, j = 0; i &amp;lt; renderData.length; i++, j += 4) { const value = renderData[i]; if (isNaN(value)) { ImgData.data[j] = 0; // R channel ImgData.data[j + 1] = 0; // G channel ImgData.data[j + 2] = 0; // B channel ImgData.data[j + 3] = 0; // A channel } else { const color = d3.rgb(colorInterpolator(value)); ImgData.data[j] = color.r; // R channel ImgData.data[j + 1] = color.g; // G channel ImgData.data[j + 2] = color.b; // B channel ImgData.data[j + 3] = config.colorOpacity / 100 * 255; // A channel } }</code></pre> <ul> <li>new ImageData(data.x_grid, data.y_grid):创建一个新的 ImageData 对象,用于存储图像的像素数据。data.x_grid 和 data.y_grid 是图像的宽度和高度。</li> <li>循环遍历 renderData 并将其值转换为图像的颜色数据:</li> <li>isNaN(value):检查数据值是否为 NaN(表示无效数据),如果是,则将对应的像素设置为完全透明。</li> <li>d3.rgb(colorInterpolator(value)):将数据值转换为颜色。</li> <li>设置 ImgData.data[j]、ImgData.data[j + 1]、ImgData.data[j + 2] 和 ImgData.data[j + 3] 分别对应红色、绿色、蓝色和透明度通道。 <h3>3. 配置 Canvas</h3></li> </ul> <pre><code>const canvas = document.createElement('canvas'); const context = canvas.getContext('2d', { willReadFrequently: true }); const canvasElm = options.canvas; const canvasElmWidth = canvasElm.width; const canvasElmHeight = canvasElm.height; const scaleZoom = Math.floor(d3.min([canvasElmWidth / data.x_grid, canvasElmHeight / data.y_grid])) / 2; canvas.width = data.x_grid * scaleZoom; canvas.height = data.y_grid * scaleZoom;</code></pre> <ul> <li>创建一个新的 canvas 元素,并获取其 2D 上下文 context。</li> <li>从 options.canvas 获取已有 Canvas 元素的宽度和高度。</li> <li>计算缩放比例 scaleZoom,以确保图像适合在 Canvas 上显示。如果图像的尺寸大于 Canvas 的尺寸,则缩放图像。</li> <li>根据计算的缩放比例设置 Canvas 的宽度和高度。</li> </ul> <h3>4. 图像插值和处理</h3> <pre><code>let res = null; if (config.interpolationMethod === '1') { const newImageData1 = ImageInterpolation.bicubicInterpolation(ImgData, canvas.width, canvas.height); res = await createImageBitmap(newImageData1, 0, 0, canvas.width, canvas.height); } else { res = await createImageBitmap(ImgData, 0, 0, data.x_grid, data.y_grid); }</code></pre> <ul> <li>根据 config.interpolationMethod 选择插值方法:</li> <li>如果方法是 '1',则使用 bicubicInterpolation 函数进行三次插值,以平滑图像数据。</li> <li>否则,直接创建 ImageBitmap 对象。</li> <li>createImageBitmap:将图像数据转换为 ImageBitmap 对象,用于高效显示图像。 <h3>5. 渲染图像到 Canvas</h3></li> </ul> <pre><code>context.drawImage(res, 0, 0, canvas.width, canvas.height); const newImageData = context.getImageData(0, 0, canvas.width, canvas.height);</code></pre> <ul> <li>使用 context.drawImage 将处理后的图像绘制到 Canvas 上。</li> <li>context.getImageData 获取绘制后的图像数据,用于进一步处理或显示。</li> </ul> <h3>6. VTK 渲染设置</h3> <pre><code>const renderer = vtkRenderer.newInstance(); renderer.setBackground(0, 0, 0, 0); const vtkTexture = window.vtk.Rendering.Core.vtkTexture.newInstance(); vtkTexture.setInterpolate(true); vtkTexture.setJsImageData(newImageData); const planeSource = window.vtk.Filters.Sources.vtkPlaneSource.newInstance(); planeSource.setCenter(0, 0, 0); planeSource.setNormal(0, 0, 1); const mapper = window.vtk.Rendering.Core.vtkMapper.newInstance(); mapper.setInputConnection(planeSource.getOutputPort()); const actor = window.vtk.Rendering.Core.vtkActor.newInstance(); actor.setMapper(mapper); actor.addTexture(vtkTexture); renderer.addActor(actor); renderer.setLayer(2);</code></pre> <ul> <li>创建 VTK 渲染器实例 vtkRenderer 并设置背景色为透明(0, 0, 0, 0)。</li> <li>创建 VTK 纹理 vtkTexture 并将 Canvas 上的图像数据加载到纹理中。启用插值以提高纹理质量。</li> <li>创建 VTK 平面源 vtkPlaneSource 并设置平面的中心和法线方向。</li> <li>创建 VTK 映射器 vtkMapper,将平面源连接到映射器。</li> <li>创建 VTK 演员 vtkActor,将映射器和纹理应用到演员上。</li> <li>将演员添加到渲染器中,并设置渲染层为 2。</li> </ul> <h3>总结</h3> <p>这段代码的目的是将图像数据处理成适合 3D 渲染的纹理,并在 VTK 渲染器中显示。它涉及从数据中提取图像数据、创建图像数据、配置 Canvas、处理图像数据、渲染图像并将其应用到 VTK 渲染器中。这些步骤确保图像能够以高质量的纹理显示在 3D 环境中。</p> <p>完整代码</p> <pre><code class="language-javascript">/** * * @param {*} ImgData * @param {*} bounds * @param {*} center * @returns */ async addImgClude(data, bounds, options = {}, slice = 1) { let renderData = getCludeData(data, config.dataSource); const [minL, maxL] = d3.extent(renderData); let colorInterpolator = interpolateColor(config.color, minL, maxL); const ImgData = new ImageData(data.x_grid, data.y_grid); for (let i = 0, j = 0; i &amp;lt; renderData.length; i++, j += 4) { const value = renderData[i]; // 拿到模长 // nan数据不显示 if (isNaN(value)) { ImgData.data[j] = 0; // R channel ImgData.data[j + 1] = 0; // G channel ImgData.data[j + 2] = 0; // B channel ImgData.data[j + 3] = 0; // A 通道 } else { const color = d3.rgb(colorInterpolator(value)); ImgData.data[j] = color.r; // R channel ImgData.data[j + 1] = color.g; // G channel ImgData.data[j + 2] = color.b; // B channel ImgData.data[j + 3] = config.colorOpacity / 100 * 255; // A 通道 } } const canvas = document.createElement('canvas'); const context = canvas.getContext('2d', { willReadFrequently: true }); const canvasElm = options.canvas; const canvasElmWidth = canvasElm.width; const canvasElmHeight = canvasElm.height; // 获取一个最接近原图的缩放比例 const scaleZoom = Math.floor(d3.min([canvasElmWidth / data.x_grid, canvasElmHeight / data.y_grid])) / 2; canvas.width = data.x_grid * scaleZoom; canvas.height = data.y_grid * scaleZoom; let res = null; // 三次插值算法 if (config.interpolationMethod === '1') { const newImageData1 = ImageInterpolation.bicubicInterpolation(ImgData, canvas.width, canvas.height); res = await createImageBitmap(newImageData1, 0, 0, canvas.width, canvas.height); } else { res = await createImageBitmap(ImgData, 0, 0, data.x_grid, data.y_grid); } context.drawImage(res, 0, 0, canvas.width, canvas.height); const newImageData = context.getImageData(0, 0, canvas.width, canvas.height); const renderer = vtkRenderer.newInstance(); // 将渲染器的背景色设置为透明 renderer.setBackground(0, 0, 0, 0); // RGBA 中的 A 通道设置为 0 表示完全透明 // vtk 纹理 const vtkTexture = window.vtk.Rendering.Core.vtkTexture.newInstance(); // 创建平面源 const planeSource = window.vtk.Filters.Sources.vtkPlaneSource.newInstance(); planeSource.setCenter(0, 0, 0); // 平面的中心点 planeSource.setNormal(0, 0, 1); // 平面的法线方向 // 方法用于设置纹理插值。当插值设置为 true 时,它会对纹理进行插值,以确保在图像放大或缩小时保持图像的平滑性。 vtkTexture.setInterpolate(true); // 直接加载canvas的imgdata数据 vtkTexture.setJsImageData(newImageData); // 创建映射器 const mapper = window.vtk.Rendering.Core.vtkMapper.newInstance(); mapper.setInputConnection(planeSource.getOutputPort()); // 创建一个actor const actor = window.vtk.Rendering.Core.vtkActor.newInstance(); actor.setMapper(mapper); actor.addTexture(vtkTexture); renderer.addActor(actor); renderer.setLayer(2); }</code></pre>

页面列表

ITEM_HTML