export function createSsdAnchors()

in face-landmarks-detection/src/shared/calculators/create_ssd_anchors.ts [23:117]


export function createSsdAnchors(config: AnchorConfig): Rect[] {
  // Set defaults.
  if (config.reduceBoxesInLowestLayer == null) {
    config.reduceBoxesInLowestLayer = false;
  }
  if (config.interpolatedScaleAspectRatio == null) {
    config.interpolatedScaleAspectRatio = 1.0;
  }
  if (config.fixedAnchorSize == null) {
    config.fixedAnchorSize = false;
  }

  const anchors: Rect[] = [];
  let layerId = 0;
  while (layerId < config.numLayers) {
    const anchorHeight = [];
    const anchorWidth = [];
    const aspectRatios = [];
    const scales = [];

    // For same strides, we merge the anchors in the same order.
    let lastSameStrideLayer = layerId;
    while (lastSameStrideLayer < config.strides.length &&
           config.strides[lastSameStrideLayer] === config.strides[layerId]) {
      const scale = calculateScale(
          config.minScale, config.maxScale, lastSameStrideLayer,
          config.strides.length);
      if (lastSameStrideLayer === 0 && config.reduceBoxesInLowestLayer) {
        // For first layer, it can be specified to use predefined anchors.
        aspectRatios.push(1);
        aspectRatios.push(2);
        aspectRatios.push(0.5);
        scales.push(0.1);
        scales.push(scale);
        scales.push(scale);
      } else {
        for (let aspectRatioId = 0; aspectRatioId < config.aspectRatios.length;
             ++aspectRatioId) {
          aspectRatios.push(config.aspectRatios[aspectRatioId]);
          scales.push(scale);
        }
        if (config.interpolatedScaleAspectRatio > 0.0) {
          const scaleNext = lastSameStrideLayer === config.strides.length - 1 ?
              1.0 :
              calculateScale(
                  config.minScale, config.maxScale, lastSameStrideLayer + 1,
                  config.strides.length);
          scales.push(Math.sqrt(scale * scaleNext));
          aspectRatios.push(config.interpolatedScaleAspectRatio);
        }
      }
      lastSameStrideLayer++;
    }

    for (let i = 0; i < aspectRatios.length; ++i) {
      const ratioSqrts = Math.sqrt(aspectRatios[i]);
      anchorHeight.push(scales[i] / ratioSqrts);
      anchorWidth.push(scales[i] * ratioSqrts);
    }

    let featureMapHeight = 0;
    let featureMapWidth = 0;
    if (config.featureMapHeight.length > 0) {
      featureMapHeight = config.featureMapHeight[layerId];
      featureMapWidth = config.featureMapWidth[layerId];
    } else {
      const stride = config.strides[layerId];
      featureMapHeight = Math.ceil(config.inputSizeHeight / stride);
      featureMapWidth = Math.ceil(config.inputSizeWidth / stride);
    }

    for (let y = 0; y < featureMapHeight; ++y) {
      for (let x = 0; x < featureMapWidth; ++x) {
        for (let anchorId = 0; anchorId < anchorHeight.length; ++anchorId) {
          const xCenter = (x + config.anchorOffsetX) / featureMapWidth;
          const yCenter = (y + config.anchorOffsetY) / featureMapHeight;

          const newAnchor: Rect = {xCenter, yCenter, width: 0, height: 0};

          if (config.fixedAnchorSize) {
            newAnchor.width = 1.0;
            newAnchor.height = 1.0;
          } else {
            newAnchor.width = anchorWidth[anchorId];
            newAnchor.height = anchorHeight[anchorId];
          }
          anchors.push(newAnchor);
        }
      }
    }
    layerId = lastSameStrideLayer;
  }

  return anchors;
}