bgrMatToSignedFloat32 function
Converts a continuous BGR CV_8UC3 cv.Mat to a [-1, 1]-normalized
RGB float tensor using OpenCV SIMD kernels (BGR→RGB swap + scaled float
conversion) and a single memcpy into buffer.
Falls back to the scalar Dart loop (bgrBytesToSignedFloat32) for
non-CV_8UC3 or non-continuous inputs.
Implementation
@visibleForTesting
Float32List bgrMatToSignedFloat32(
cv.Mat mat, {
required int totalPixels,
Float32List? buffer,
}) {
// BGRA (4ch) and grayscale (1ch) inputs must be color-converted to 3-channel
// BGR first: both the SIMD path below and the byte fallback assume 3
// bytes/pixel, so a non-BGR stride overruns the buffer (BGRA) or under-reads
// it (grayscale) and corrupts the tensor.
cv.Mat? owned;
cv.Mat src = mat;
if (mat.type == cv.MatType.CV_8UC4) {
src = owned = cv.cvtColor(mat, cv.COLOR_BGRA2BGR);
} else if (mat.type == cv.MatType.CV_8UC1) {
src = owned = cv.cvtColor(mat, cv.COLOR_GRAY2BGR);
}
try {
if (src.type != cv.MatType.CV_8UC3 || !src.isContinuous) {
return bgrBytesToSignedFloat32(
bytes: src.data,
totalPixels: totalPixels,
buffer: buffer,
);
}
final cv.Mat rgb = cv.cvtColor(src, cv.COLOR_BGR2RGB);
final cv.Mat f32 = rgb.convertTo(
cv.MatType.CV_32FC3,
alpha: 1.0 / 127.5,
beta: -1.0,
);
rgb.dispose();
final Uint8List raw = f32.data;
final Float32List view = Float32List.view(
raw.buffer,
raw.offsetInBytes,
totalPixels * 3,
);
final Float32List tensor = buffer ?? Float32List(totalPixels * 3);
tensor.setAll(0, view);
f32.dispose();
return tensor;
} finally {
owned?.dispose();
}
}