我有一个大小为(X,Y,Z)的3D矩阵,它存储在数据结构中作为 Z 矩阵,每个 X x Y < / em>大小。我想重新切片这些矩阵以获得 X 切片,每个 Y x Z 的大小。换句话说,我想重新组合在YZ平面中存储为XY切片的3D矩阵。用例是将轴向CT图像重新定位为矢状图像。我在浏览器环境中工作。
这是我想要实现的一个例子:
我在Python中实现了天真(迭代)解决方案,每个切片需要O(Y * Z)。我甚至不打算写出相应的JavaScript实现,因为这种方法太慢了几个数量级。
import glob
import numpy as np
import matplotlib.pyplot as plt
from scipy.misc import imread
height, width, depth = 512, 512, 100
volume = np.zeros((height, width, depth))
s = 0
for filename in glob.iglob('./*.jpg'):
volume[:,:,s] = imread(filename)[...,0]/255.0
s += 1
reslice = np.zeros((depth, height, width))
for s in xrange(0, width):
current = np.zeros((depth, height))
for i in xrange(0, height):
for j in xrange(0, depth):
current[j,i] = volume[i,s,j]
reslice[:,:,s] = current
此算法似乎适合并行化。例如,在CUDA中,可以将3D数据加载到全局存储器中,每个像素创建一个线程,然后针对新方向的每个切片进行迭代,并且在每次迭代时请求正确的像素触发以填充当前切片。这将是一个非常简单的内核,每个切片大约为O(1)。但是,我无法在浏览器中访问CUDA。
从CUDA到WebCL的映射相对简单,但由于不存在供应商支持ATM,因此WebCL是不可能的。因此,我认为WebGL是理想的解决方案。
我不太确定如何在&#34; WebGL&#34;范式,但我确信它可以完成,我怀疑它也是相当微不足道的。然而,我无法找到从哪里开始,而使用OpenGL进行通用计算的资源非常稀少。我将如何使用OpenGL加速浏览器中3D矩阵的重新拼接?
答案 0 :(得分:3)
您没有必要使用webGL足够快。
如果使用3D阵列,JavaScript可能太慢,但使用 flat 数组,重新制作的时间实际上与创建时间相似阵列!
另一个技巧是使用 类型数组 来减少内存使用并提高性能(Uint8Array)。
我创建了一个小类来处理这样的平面数组并对其进行切片。
我认为你想要的最相关的事实是在(x,y)轴或(y,z)轴上获得 视图 。
由于数组创建速度很慢,因此您希望在固定缓冲区内构建视图。由于您还需要切片视图,因此您还必须为切片视图创建缓冲区和方法。 它的速度很快:为512X512x100示例创建一个视图, 小于5毫秒! (所以事实上,你以后要做的putImageData会花费更多的时间!)
小提琴在这里:http://jsfiddle.net/n38mwh95/1/
这是处理数据的类,您必须更改构造函数,以便接受真实的原始数据:
function Array3D(xSize, ySize, zSize) {
this.xSize = xSize;
this.ySize = ySize;
this.zSize = zSize;
var xyMultiplier = xSize * ySize;
this.array = new Uint8Array(xSize * ySize * zSize);
this.view = new Uint8Array(xSize * ySize);
this.slicedView = new Uint8Array(ySize * zSize);
this.valueAt = function (x, y, z) {
return this.array[x + xSize * (y + z * ySize)];
};
this.setValueAt = function (x, y, z, val) {
return this.array[x + xSize * (y + z * ySize)] = val;
};
this.buildView = function (z) {
var src = this.array;
var view = this.view;
for (var x = 0; x < xSize; x++) {
for (var y = 0; y < ySize; y++) {
view[x + xSize * y] = src[x + xSize * (y + z * ySize)];
}
}
return view;
};
this.buildSlicedView = function (x) {
var src = this.array;
var sView = this.slicedView;
for (var y = 0; y < ySize; y++) {
for (var z = 0; z < zSize; z++) {
sView[y + ySize * z] = src[x + xSize * (y + z * ySize)];
}
}
return sView;
};
}
使用中:
var xSize = 512;
var ySize = 512;
var zSize = 100;
var t1, t2;
t1 = performance.now();
var testArray = new Array3D(xSize, ySize, zSize);
t2 = performance.now();
console.log('created in :' + (t2 - t1));
t1 = performance.now();
var resliced = testArray.buildView(10);
t2 = performance.now();
console.log('building view in :' + (t2 - t1));
var x = 80;
t1 = performance.now();
var resliced = testArray.buildSlicedView(x);
t2 = performance.now();
console.log('building sliced view in :' + (t2 - t1));
结果:
created in :33.92199998779688 (index):73
building view in :2.7559999871300533 (index):79
building sliced view in :5.726000003051013
在代码的最后,我还添加了一些代码来渲染视图。
不要忘记缓存画布imageData:只创建一次然后重新使用它以获得最佳性能。
您可以轻松实现实时渲染。