convertImageToTensor function

ImageTensor convertImageToTensor(
  1. Mat src, {
  2. required int outW,
  3. required int outH,
  4. Float32List? buffer,
})

Converts a cv.Mat image to a normalized tensor with letterboxing.

This function performs aspect-preserving resize with black padding and normalizes pixel values to the [-1.0, 1.0] range expected by MediaPipe TensorFlow Lite models.

The src cv.Mat will be resized to fit within outW×outH dimensions while preserving its aspect ratio. Black padding is added to fill the remaining space.

Returns an ImageTensor containing:

  • Normalized float32 tensor in NHWC format
  • Padding information needed to reverse the letterbox transformation

Note: The input cv.Mat is NOT disposed by this function.

Implementation

ImageTensor convertImageToTensor(
  cv.Mat src, {
  required int outW,
  required int outH,
  Float32List? buffer,
}) {
  final int inW = src.cols;
  final int inH = src.rows;

  final LetterboxParams lbp = computeLetterboxParams(
    srcWidth: inW,
    srcHeight: inH,
    targetWidth: outW,
    targetHeight: outH,
  );

  // Skip the resize when the source already matches the target geometry
  // (crops warped directly to model input size hit this every call). A
  // non-continuous source still goes through cv.resize so the conversion
  // below always reads tightly packed rows, as it did before this fast path.
  final bool needsResize =
      inW != lbp.newWidth || inH != lbp.newHeight || !src.isContinuous;
  final cv.Mat resized = needsResize
      ? cv.resize(src, (
          lbp.newWidth,
          lbp.newHeight,
        ), interpolation: cv.INTER_LINEAR)
      : src;

  final bool needsPad =
      lbp.padTop != 0 ||
      lbp.padBottom != 0 ||
      lbp.padLeft != 0 ||
      lbp.padRight != 0;
  final cv.Mat padded = needsPad
      ? cv.copyMakeBorder(
          resized,
          lbp.padTop,
          lbp.padBottom,
          lbp.padLeft,
          lbp.padRight,
          cv.BORDER_CONSTANT,
          value: cv.Scalar.black,
        )
      : resized;
  if (needsResize && needsPad) resized.dispose();

  final Float32List tensor = bgrMatToSignedFloat32(
    padded,
    totalPixels: outW * outH,
    buffer: buffer,
  );
  if (needsResize || needsPad) padded.dispose();

  final double padTopNorm = lbp.padTop / outH;
  final double padBottomNorm = lbp.padBottom / outH;
  final double padLeftNorm = lbp.padLeft / outW;
  final double padRightNorm = lbp.padRight / outW;

  return ImageTensor(
    tensor,
    [padTopNorm, padBottomNorm, padLeftNorm, padRightNorm],
    outW,
    outH,
  );
}