Closed farzam-khodajoo closed 1 year ago
Hi,
maybe you can try this library: https://github.com/scijs/ndarray, which operates like NumPy. Since the image data is stored in a TypedArray
, you can easily reshape the data using ndarray
and call array.pick()
to select the columns you want.
This is a brief sample:
let header = nifti.readHeader(binaryData) // binaryData is an arrayBuffer you download or read locally
let dims = header.dims
let stride = [1, dims[1], dims[1] * dims[2]]
let array = ndarray(imageData, [dims[1], dims[2], dims[3]], stride).step(1, 1, -1) // imageData is a TypedArray, see the docs
const getImage = (dim, slice) => {
let image
if (dim === 1) {
image = array.pick(slice, null, null)
} else if (dim === 2) {
image = array.pick(null, slice, null)
} else if (dim === 3) {
image = array.pick(null, null, header.dims[3] - slice - 1)
}
return image
}
Thus, you can get images from coronal view as getImage(2, SLICE)
.
Hope this will help!
If you want to display axial, coronal and sagittal views from a 3D volume it is easiest to use WebGL2. This version introduced 3D textures, which are like 3D bitmaps (e.g. 2D bitmaps are pixel based, 3D are voxel based). This means that you do not have to send data between the CPU and GPU for each slice and every frame, rather the entire 3D array is in the GPU memory and the shader samples the desired plane.
You can see this in NiiVue where the shader uniform axCorSag selects between axial, coronal and sagittal slices. Since Texture dimensions are always sampled from 0..1, you would choose an axial slice would be [0,0,z],[1,0,z],[1,1,z],[0,1,z], a coronal slice would be [0,y,0],[1,y,0],[1,y,1],[0,y,1] and the sagittal slice would be [x,0,0],[x,1,0],[x,1,1],[x,0,1] assuming your voxels are in RAS orientation (NiiVue includes code that will swizzle voxel order to RAS).
Hi @Hermanboi97 , the ndarray
takes a TypedArray
as the first parameter. The imageData
in my code is identical to the typedData
in the example. Then, use the function image.get(i, j)
to get the image value at (i, j)
.
The render process is like:
let ctx = canvas.getContext('2d')
let canvasImageData = ctx.createImageData(cols, rows)
// draw pixels
for (let row = 0; row < rows; row++) {
let rowOffset = row * cols;
for (let col = 0; col < cols; col++) {
let value = image.get(col, row)
/*
Assumes data is 8-bit, otherwise you would need to first convert
to 0-255 range based on datatype range, data range (iterate through
data to find), or display range (cal_min/max).
Other things to take into consideration:
- data scale: scl_slope and scl_inter, apply to raw value before
applying display range
- orientation: displays in raw orientation, see nifti orientation
info for how to orient data
- assumes voxel shape (pixDims) is isometric, if not, you'll need
to apply transform to the canvas
- byte order: see littleEndian flag
*/
canvasImageData.data[(rowOffset + col) * 4] = value & 0xFF;
canvasImageData.data[(rowOffset + col) * 4 + 1] = value & 0xFF;
canvasImageData.data[(rowOffset + col) * 4 + 2] = value & 0xFF;
canvasImageData.data[(rowOffset + col) * 4 + 3] = 0xFF;
}
}
ctx.putImageData(canvasImageData, 0, 0);
Closing this issue based on solution from @znshje
Hi, thanks for this handy library this is not really an issue, but I have struggle getting coronal view instead of axial for brain images. I have brain MRI images in axial view with dimention of
(240, 240, 155)
and this example successfuly draws images on screenbut now I'm looking for coronal view like this image which happens when treat columns as slices and slices as column :
(rows, column, slices)
to(rows, slices, column)
I would appreciate your guidance.