You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

替代已停用的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 14:14:58