async estimateFaces()

in blazeface/src/face.ts [347:436]


  async estimateFaces(
      input: tf.Tensor3D|ImageData|HTMLVideoElement|HTMLImageElement|
      HTMLCanvasElement,
      returnTensors = false, flipHorizontal = false,
      annotateBoxes = true): Promise<NormalizedFace[]> {
    const [, width] = getInputTensorDimensions(input);
    const image = tf.tidy(() => {
      if (!(input instanceof tf.Tensor)) {
        input = tf.browser.fromPixels(input);
      }
      return tf.expandDims(tf.cast((input as tf.Tensor), 'float32'), 0);
    });
    const {boxes, scaleFactor} = await this.getBoundingBoxes(
        image as tf.Tensor4D, returnTensors, annotateBoxes);
    image.dispose();

    if (returnTensors) {
      return boxes.map((face: BlazeFacePrediction|Box) => {
        const scaledBox =
            scaleBoxFromPrediction(face, scaleFactor as tf.Tensor1D);
        let normalizedFace: NormalizedFace = {
          topLeft: tf.slice(scaledBox, [0], [2]) as tf.Tensor1D,
          bottomRight: tf.slice(scaledBox, [2], [2]) as tf.Tensor1D
        };

        if (annotateBoxes) {
          const {landmarks, probability, anchor} = face as {
            landmarks: tf.Tensor2D,
            probability: tf.Tensor1D,
            anchor: tf.Tensor2D | [number, number]
          };

          const normalizedLandmarks: tf.Tensor2D =
              tf.mul(tf.add(landmarks, anchor), scaleFactor);
          normalizedFace.landmarks = normalizedLandmarks;
          normalizedFace.probability = probability;
        }

        if (flipHorizontal) {
          normalizedFace = flipFaceHorizontal(normalizedFace, width);
        }
        return normalizedFace;
      });
    }

    return Promise.all(boxes.map(async (face: BlazeFacePrediction) => {
      const scaledBox =
          scaleBoxFromPrediction(face, scaleFactor as [number, number]);
      let normalizedFace: NormalizedFace;
      if (!annotateBoxes) {
        const boxData = await scaledBox.array();
        normalizedFace = {
          topLeft: (boxData as number[]).slice(0, 2) as [number, number],
          bottomRight: (boxData as number[]).slice(2) as [number, number]
        };
      } else {
        const [landmarkData, boxData, probabilityData] =
            await Promise.all([face.landmarks, scaledBox, face.probability].map(
                async d => d.array()));

        const anchor = face.anchor as [number, number];
        const [scaleFactorX, scaleFactorY] = scaleFactor as [number, number];
        const scaledLandmarks =
            (landmarkData as Array<[number, number]>)
                .map(landmark => ([
                       (landmark[0] + anchor[0]) * scaleFactorX,
                       (landmark[1] + anchor[1]) * scaleFactorY
                     ]));

        normalizedFace = {
          topLeft: (boxData as number[]).slice(0, 2) as [number, number],
          bottomRight: (boxData as number[]).slice(2) as [number, number],
          landmarks: scaledLandmarks,
          probability: probabilityData as number
        };

        disposeBox(face.box);
        face.landmarks.dispose();
        face.probability.dispose();
      }

      scaledBox.dispose();

      if (flipHorizontal) {
        normalizedFace = flipFaceHorizontal(normalizedFace, width);
      }

      return normalizedFace;
    }));
  }