static contrastEnchanceUnsharpMask()

in src/engine/loaders/voltools.js [411:519]


  static contrastEnchanceUnsharpMask(pixelsSrc, xDim, yDim, zDim, pixelsDst, radSmooth, sigmaSmooth, multiplier, needConsoleLog = false) {
    // check input arguments
    if (typeof xDim !== 'number' || typeof yDim !== 'number' || typeof zDim !== 'number') {
      return VolumeTools.VOLTOOLS_ERROR_BAD_NUMBER;
    }
    if (typeof pixelsSrc !== 'object') {
      return VolumeTools.VOLTOOLS_ERROR_BAD_ARRAY;
    }
    if (typeof pixelsDst !== 'object') {
      return VolumeTools.VOLTOOLS_ERROR_BAD_ARRAY;
    }
    if (multiplier < 1.0) {
      return VolumeTools.VOLTOOLS_ERROR_BAD_MULTIPLIER;
    }
    const MAX_POSSIBLE_MULTIPLIER = 256.0;
    if (multiplier >= MAX_POSSIBLE_MULTIPLIER) {
      return VolumeTools.VOLTOOLS_ERROR_BAD_MULTIPLIER;
    }
    if (xDim <= 1 || yDim <= 1 || zDim <= 1) {
      return VolumeTools.VOLTOOLS_ERROR_BAD_DIMENSION;
    }
    const MAX_POSSIBLE_DIM = 4096;
    if (xDim >= MAX_POSSIBLE_DIM || yDim >= MAX_POSSIBLE_DIM || zDim >= MAX_POSSIBLE_DIM) {
      return VolumeTools.VOLTOOLS_ERROR_BAD_DIMENSION;
    }
    const TWO = 2;
    const side = TWO * radSmooth + 1;
    const side3 = side * side * side;
    const xyDim = xDim * yDim;

    // allocate gauss convolution 3d matrix
    const gaussWeights = new Float32Array(side3);

    // flll gauss convolution matrix
    const koefSpatial = 1.0 / (TWO * sigmaSmooth * sigmaSmooth);
    let weightSum = 0.0;
    let off = 0;
    for (let z = 0; z < side; z++) {
      const dz = z - radSmooth;
      for (let y = 0; y < side; y++) {
        const dy = y - radSmooth;
        for (let x = 0; x < side; x++) {
          const dx = x - radSmooth;
          const dist2 = 1.0 * dx * dx + dy * dy + dz * dz;
          const w = 1.0 / Math.exp(dist2 * koefSpatial);
          gaussWeights[off] = w;
          weightSum += gaussWeights[off];
          off++;
        } // for (x)
      } // for (y)
    } // for (z)
    // Normalize gauss matrix
    const scale = 1.0 / weightSum;
    for (let x = 0; x < side3; x++) {
      gaussWeights[x] *= scale;
    }
    // Process image
    for (let zc = 0; zc < zDim; zc++) {
      for (let yc = 0; yc < yDim; yc++) {
        for (let xc = 0; xc < xDim; xc++) {
          let valSmoothed = 0.0;
          let offConv = 0;
          for (let dz = -radSmooth; dz <= +radSmooth; dz++) {
            let z = zc + dz;
            z = z < 0 ? 0 : z >= zDim ? zDim - 1 : z;
            const zOff = z * xyDim;
            for (let dy = -radSmooth; dy <= +radSmooth; dy++) {
              let y = yc + dy;
              y = y < 0 ? 0 : y >= yDim ? yDim - 1 : y;
              const yOff = y * xDim;
              for (let dx = -radSmooth; dx <= +radSmooth; dx++) {
                let x = xc + dx;
                x = x < 0 ? 0 : x >= xDim ? xDim - 1 : x;

                const w = gaussWeights[offConv];
                offConv++;
                const offImage = x + yOff + zOff;
                const val = pixelsSrc[offImage];
                valSmoothed += w * val;
              } // for (dx)
            } // for (dy)
          } // for (dz)

          // now valSmoothed is smoothed pixel intensity at (xc, yc)
          off = xc + yc * xDim + zc * xyDim;
          let val = pixelsSrc[off];
          const valDif = val - valSmoothed;
          const MIN_DIF_UNSHARP_VAL = 2.0;
          const valAdd = valDif > MIN_DIF_UNSHARP_VAL || valDif < -MIN_DIF_UNSHARP_VAL ? valDif * multiplier : 0.0;
          let valSharpened = val + valAdd;
          valSharpened = valSharpened < 0.0 ? 0.0 : valSharpened;
          val = Math.floor(valSharpened);
          const MAX_COLOR = 255;
          val = val > MAX_COLOR ? MAX_COLOR : val;
          pixelsDst[off] = val;
          if (needConsoleLog) {
            const MASK_MANY = 16383;
            if ((off & MASK_MANY) === 0) {
              const HUNDR = 100.0;
              const ratioPrc = (off * HUNDR) / (xDim * yDim * zDim);
              console.log(`contrastEnchanceUnsharpMask: ${ratioPrc} %`);
            }
          } // if ned console
        } // for (xc)
      } // for (yc)
    } // for (zc)

    return VolumeTools.VOLTOOLS_ERROR_OK;
  }