替代已停用的tflite_flutter_helper实现Flutter中TFLite模型功能
替代tflite_flutter_helper实现姿态估计图像预处理
依赖替换
放弃已停止维护的tflite_flutter_helper,改用官方维护的tflite_flutter基础包,搭配dart原生图像处理库image实现所有预处理功能。在pubspec.yaml中添加依赖:
dependencies: flutter: sdk: flutter tflite_flutter: ^0.10.1 # 使用最新稳定版 image: ^4.0.17 camera: ^0.10.5+5 # 若使用摄像头输入需添加
核心功能实现
1. 实现ResizeWithCropOrPad操作
模拟原包的裁剪/填充逻辑,将图像调整为指定正方形尺寸:
import 'package:image/image.dart' as img; img.Image resizeWithCropOrPad(img.Image image, int targetSize) { final int width = image.width; final int height = image.height; if (width == targetSize && height == targetSize) return image; // 计算裁剪区域(中心裁剪) int cropX = 0, cropY = 0; int cropWidth = width, cropHeight = height; if (width > targetSize) { cropX = (width - targetSize) ~/ 2; cropWidth = targetSize; } if (height > targetSize) { cropY = (height - targetSize) ~/ 2; cropHeight = targetSize; } // 执行裁剪 final cropped = img.copyCrop(image, cropX, cropY, cropWidth, cropHeight); // 若裁剪后尺寸不足,填充至目标大小(黑色背景) if (cropped.width < targetSize || cropped.height < targetSize) { final padded = img.Image(targetSize, targetSize); final offsetX = (targetSize - cropped.width) ~/ 2; final offsetY = (targetSize - cropped.height) ~/ 2; img.copyInto(padded, cropped, dstX: offsetX, dstY: offsetY); return padded; } return cropped; }
2. 实现双线性插值Resize
将图像缩放到模型要求的192×192尺寸:
img.Image resizeToModelSize(img.Image image) { return img.copyResize( image, width: 192, height: 192, interpolation: img.Interpolation.bilinear, ); }
3. 图像转TFLite输入张量
将处理后的图像转换为模型所需的float32格式张量(需根据模型要求调整归一化规则):
import 'package:tflite_flutter/tflite_flutter.dart'; TensorBuffer convertImageToTensor(img.Image image) { // 模型输入形状:[1, 192, 192, 3](NHWC格式) final inputShape = [1, image.height, image.width, 3]; final buffer = TensorBuffer.createFixedSize(inputShape, TfLiteType.float32); final floatList = Float32List(inputShape[0] * inputShape[1] * inputShape[2] * inputShape[3]); int index = 0; // 遍历像素,转换为归一化的float值(此处为0-1范围,若模型要求-1到1则改为 (value/127.5)-1.0) for (int y = 0; y < image.height; y++) { for (int x = 0; x < image.width; x++) { final pixel = image.getPixel(x, y); floatList[index++] = img.getRed(pixel) / 255.0; floatList[index++] = img.getGreen(pixel) / 255.0; floatList[index++] = img.getBlue(pixel) / 255.0; } } buffer.setFloatList(floatList); return buffer; }
4. 创建输出TensorBuffer
替代原包的TensorBufferFloat,使用tflite_flutter原生API创建:
final outputLocations = TensorBuffer.createFixedSize([1, 1, 17, 3], TfLiteType.float32);
完整使用流程
从摄像头输入到模型推理的完整流程示例:
// 1. 将摄像头输出的CameraImage转换为image库的Image对象 img.Image convertCameraImageToImage(CameraImage cameraImage) { final int width = cameraImage.width; final int height = cameraImage.height; final image = img.Image(width, height); final uvRowStride = cameraImage.planes[1].bytesPerRow; final uvPixelStride = cameraImage.planes[1].bytesPerPixel!; for (int w = 0; w < width; w++) { for (int h = 0; h < height; h++) { final uvIndex = uvPixelStride * (w ~/ 2) + uvRowStride * (h ~/ 2); final y = cameraImage.planes[0].bytes[h * width + w]; final u = cameraImage.planes[1].bytes[uvIndex]; final v = cameraImage.planes[2].bytes[uvIndex]; // YUV转RGB int r = (y + 1.370705 * (v - 128)).round().clamp(0, 255); int g = (y - 0.698001 * (v - 128) - 0.337633 * (u - 128)).round().clamp(0, 255); int b = (y + 1.732446 * (u - 128)).round().clamp(0, 255); image.setPixelRgba(w, h, r, g, b, 255); } } return image; } // 2. 完整预处理+推理流程 void runPoseEstimation(CameraImage cameraImage, Interpreter interpreter) { // 转换摄像头图像格式 final rawImage = convertCameraImageToImage(cameraImage); // 执行预处理 final padSize = ...; // 原代码中使用的padSize值 final croppedPadded = resizeWithCropOrPad(rawImage, padSize); final resizedImage = resizeToModelSize(croppedPadded); // 转换为模型输入张量 final inputTensor = convertImageToTensor(resizedImage); // 运行模型推理 interpreter.run(inputTensor.buffer, outputLocations.buffer); // 处理输出结果 final keypoints = outputLocations.getFloatList(); // 此处根据模型输出格式解析姿态关键点坐标... }
注意事项
- 归一化规则:需匹配模型训练时的预处理规则,部分模型要求像素值范围为-1到1,此时需将代码中的
value/255.0改为(value/127.5)-1.0。 - 输入格式:若模型使用NCHW格式([1,3,192,192]),需调整张量的通道顺序,先遍历RGB通道,再遍历高度和宽度。
- 版本兼容:确保使用最新版的
tflite_flutter和image库,避免API差异问题。
内容的提问来源于stack exchange,提问作者FlutterNoob
相关产品推荐
相关产品推荐

