cameraFrameToBgrMat function
Decodes a CameraFrame into a 3-channel BGR cv.Mat.
The layout and safe operation order come from flutter_litert
(CameraFrame.decodePlan); this only maps that backend-neutral plan onto
OpenCV primitives. Equivalent to the previous inline conversion: for
4-channel frames it resizes/rotates before dropping alpha; for packed YUV it
colour-converts first (the packed layout can't be resized).
Implementation
cv.Mat cameraFrameToBgrMat(CameraFrame frame, {int? maxDim}) {
final CameraFrameDecodePlan plan = frame.decodePlan();
final cv.Mat source = matFromPackedLayout(
plan.sourceLayout,
frame.bytes,
plan.sourceLayout.channels == 4 ? cv.MatType.CV_8UC4 : cv.MatType.CV_8UC1,
);
cv.Mat maybeResize(cv.Mat m) {
if (maxDim == null || (m.cols <= maxDim && m.rows <= maxDim)) return m;
final double scale = maxDim / (m.cols > m.rows ? m.cols : m.rows);
final cv.Mat resized = cv.resize(m, (
(m.cols * scale).toInt(),
(m.rows * scale).toInt(),
), interpolation: cv.INTER_LINEAR);
m.dispose();
return resized;
}
int? rotateFlag() {
return switch (plan.rotation) {
CameraFrameRotation.cw90 => cv.ROTATE_90_CLOCKWISE,
CameraFrameRotation.cw180 => cv.ROTATE_180,
CameraFrameRotation.cw270 => cv.ROTATE_90_COUNTERCLOCKWISE,
null => null,
};
}
cv.Mat maybeRotate(cv.Mat m) {
final int? flag = rotateFlag();
if (flag == null) return m;
final cv.Mat rotated = cv.rotate(m, flag);
m.dispose();
return rotated;
}
final int cvtCode = switch (plan.conversion) {
CameraFrameConversion.bgra2bgr => cv.COLOR_BGRA2BGR,
CameraFrameConversion.rgba2bgr => cv.COLOR_RGBA2BGR,
CameraFrameConversion.yuv2bgrNv12 => cv.COLOR_YUV2BGR_NV12,
CameraFrameConversion.yuv2bgrNv21 => cv.COLOR_YUV2BGR_NV21,
CameraFrameConversion.yuv2bgrI420 => cv.COLOR_YUV2BGR_I420,
};
switch (plan.order) {
case CameraFrameDecodeOrder.resizeRotateThenColorConvert:
cv.Mat current = plan.hasStridePadding
? source.region(cv.Rect(0, 0, plan.visibleWidth, plan.visibleHeight))
: source;
if (maxDim != null && (current.cols > maxDim || current.rows > maxDim)) {
final double scale =
maxDim /
(current.cols > current.rows ? current.cols : current.rows);
final cv.Mat resized = cv.resize(current, (
(current.cols * scale).toInt(),
(current.rows * scale).toInt(),
), interpolation: cv.INTER_LINEAR);
if (!identical(current, source)) current.dispose();
current = resized;
}
final int? flag = rotateFlag();
if (flag != null) {
final cv.Mat rotated = cv.rotate(current, flag);
if (!identical(current, source)) current.dispose();
current = rotated;
}
final cv.Mat bgr = cv.cvtColor(current, cvtCode);
if (!identical(current, source)) current.dispose();
source.dispose();
return bgr;
case CameraFrameDecodeOrder.colorConvertThenResizeRotate:
cv.Mat current = cv.cvtColor(source, cvtCode);
source.dispose();
current = maybeResize(current);
current = maybeRotate(current);
return current;
}
}