All files / nifti-volume-loader/src/helpers makeVolumeMetadata.ts

0% Statements 0/15
0% Branches 0/2
0% Functions 0/1
0% Lines 0/15

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87                                                                                                                                                                             
import type { Types } from '@cornerstonejs/core';
import { utilities } from '@cornerstonejs/core';
import { vec3 } from 'gl-matrix';
 
const { windowLevel } = utilities;
 
// everything here is LPS
export default function makeVolumeMetadata(
  niftiHeader,
  orientation,
  pixelRepresentation
): {
  volumeMetadata: Types.Metadata;
  dimensions: Types.Point3;
  direction: Types.Mat3;
} {
  const { numBitsPerVoxel, littleEndian, pixDims, dims } = niftiHeader;
  const min = Infinity;
  const max = -Infinity;
  const frameLength = dims[1] * dims[2];
  const middleFrameIndex = Math.floor(dims[3] / 2);
  const offset = frameLength * middleFrameIndex;
  // for (
  //   let voxelIndex = offset;
  //   voxelIndex < offset + frameLength;
  //   voxelIndex++
  // ) {
  //   const voxelValue = scalarData[voxelIndex];
  //   if (voxelValue > max) {
  //     max = voxelValue;
  //   }
  //   if (voxelValue < min) {
  //     min = voxelValue;
  //   }
  // }
  // const { windowWidth, windowCenter } = windowLevel.toWindowLevel(min, max);
  const { windowWidth, windowCenter } = { windowWidth: 400, windowCenter: 40 };
 
  const rowCosines = vec3.create();
  const columnCosines = vec3.create();
  const scanAxisNormal = vec3.create();
  vec3.set(rowCosines, orientation[0], orientation[1], orientation[2]);
  vec3.set(columnCosines, orientation[3], orientation[4], orientation[5]);
  vec3.set(scanAxisNormal, orientation[6], orientation[7], orientation[8]);
  return {
    volumeMetadata: {
      BitsAllocated: numBitsPerVoxel,
      BitsStored: numBitsPerVoxel,
      SamplesPerPixel: 1,
      HighBit: littleEndian ? numBitsPerVoxel - 1 : 1,
      PhotometricInterpretation: 'MONOCHROME2',
      PixelRepresentation: pixelRepresentation,
      ImageOrientationPatient: [
        rowCosines[0],
        rowCosines[1],
        rowCosines[2],
        columnCosines[0],
        columnCosines[1],
        columnCosines[2],
      ],
      PixelSpacing: [pixDims[1], pixDims[2]],
      Columns: dims[1],
      Rows: dims[2],
      // This is a reshaped object and not a dicom tag:
      voiLut: [{ windowCenter, windowWidth }],
      // Todo: we should grab this from somewhere but it doesn't really
      // prevent us from rendering the volume so we'll just hardcode it for now.
      FrameOfReferenceUID: '1.2.3',
      Modality: 'MR',
      VOILUTFunction: 'LINEAR',
    },
    // Spacing goes [1] then [0], as [1] is column spacing (x) and [0] is row spacing (y)
    dimensions: [dims[1], dims[2], dims[3]],
    direction: new Float32Array([
      rowCosines[0],
      rowCosines[1],
      rowCosines[2],
      columnCosines[0],
      columnCosines[1],
      columnCosines[2],
      scanAxisNormal[0],
      scanAxisNormal[1],
      scanAxisNormal[2],
    ]) as Types.Mat3,
  };
}