人工智能 (AI) 和机器学习 (ML) 正在改变我们与技术互动的方式。将 AI/ML 能力集成到移动和桌面应用程序中,可以提供更智能、更个性化的用户体验。Flutter 作为跨平台框架,能够很好地与 AI/ML 模型集成,无论是通过云服务还是在设备端运行。
1. AI/ML 在移动应用中的应用场景
2. Flutter 集成 AI/ML 的方式
云端 AI/ML 服务:
设备端 AI/ML (On-device ML):
3. TensorFlow Lite 在 Flutter 中的应用
TensorFlow Lite 是在设备端运行 ML 模型的首选方案。其基本流程如下:
.tflite 文件作为 assets 资源添加到 pubspec.yaml 中。tflite_flutter 或 tflite_flutter_helper 等社区插件。Tensor)。将 AI/ML 能力集成到 Flutter 应用中,可以极大地提升用户体验和应用价值。以下案例将演示如何使用 tflite_flutter 插件在 Flutter 应用中进行简单的图像分类。
案例:使用 TensorFlow Lite 进行图像分类
我们将构建一个简单的应用,允许用户从相册选择图片,然后使用预训练的 TensorFlow Lite 模型对图片进行分类。
前提条件:
.txt),包含模型能够识别的类别名称。image_picker 插件用于选择图片。步骤 1: 创建项目并添加依赖
flutter create image_classifier
cd image_classifier
在 pubspec.yaml 中添加 tflite_flutter 和 image_picker 依赖:
dependencies:
flutter:
sdk: flutter
tflite_flutter: ^0.10.0 # 最新版本可能不同
image_picker: ^1.0.4 # 最新版本可能不同
运行 flutter pub get。
步骤 2: 添加模型和标签文件
在项目根目录下创建 assets/ml/ 目录,并将你的 .tflite 模型文件(例如 mobilenet_v2_1.0_224.tflite)和标签文件(例如 labels.txt)放入其中。
修改 pubspec.yaml,声明这些 assets:
flutter:
uses-material-design: true
assets:
- assets/ml/mobilenet_v2_1.0_224.tflite
- assets/ml/labels.txt
步骤 3: 构建 UI 和逻辑 (lib/main.dart)
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'dart:io';
import 'package:tflite_flutter/tflite_flutter.dart';
import 'package:tflite_flutter/tflite_flutter_helper.dart'; // 用于图像预处理
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '图像分类器',
theme: ThemeData(
primarySwatch: Colors.teal,
),
home: const ImageClassifierScreen(),
);
}
}
class ImageClassifierScreen extends StatefulWidget {
const ImageClassifierScreen({super.key});
@override
State<ImageClassifierScreen> createState() => _ImageClassifierScreenState();
}
class _ImageClassifierScreenState extends State<ImageClassifierScreen> {
Interpreter? _interpreter;
List<String>? _labels;
File? _image;
String _result = '请选择一张图片进行分类';
bool _isLoading = false;
final ImagePicker _picker = ImagePicker();
@override
void initState() {
super.initState();
_loadModel();
}
@override
void dispose() {
_interpreter?.close();
super.dispose();
}
Future<void> _loadModel() async {
setState(() {
_isLoading = true;
});
try {
_interpreter = await Interpreter.fromAsset(
'assets/ml/mobilenet_v2_1.0_224.tflite',
options: InterpreterOptions()..threads = 4, // 可以配置线程数
);
_labels = await FileUtil.loadLabels('assets/ml/labels.txt');
_result = '模型加载成功,请选择图片。';
} catch (e) {
_result = '模型加载失败: $e';
print('Failed to load model: $e');
} finally {
setState(() {
_isLoading = false;
});
}
}
Future<void> _pickImage() async {
final XFile? pickedFile = await _picker.pickImage(source: ImageSource.gallery);
if (pickedFile != null) {
setState(() {
_image = File(pickedFile.path);
_result = '正在分类...';
_isLoading = true;
});
await _classifyImage(_image!);
}
}
Future<void> _classifyImage(File image) async {
if (_interpreter == null || _labels == null) {
setState(() {
_result = '模型未加载或标签缺失。';
_isLoading = false;
});
return;
}
try {
// 图像预处理
// 根据你的模型输入要求调整参数
// MobileNetV2 通常需要 224x224 像素的 RGB 图像,像素值归一化到 [-1, 1] 或 [0, 1]
ImageProcessor imageProcessor = ImageProcessorBuilder()
.add(ResizeOp(224, 224, ResizeMethod.BILINEAR))
.add(NormalizeOp(127.5, 127.5)) // 归一化到 [-1, 1]
.build();
TensorImage tensorImage = TensorImage.fromFile(image);
tensorImage = imageProcessor.process(tensorImage);
// 获取输入输出张量信息
Tensor inputTensor = _interpreter!.getInputTensor(0);
Tensor outputTensor = _interpreter!.getOutputTensor(0);
// 运行模型
_interpreter!.run(tensorImage.buffer, outputTensor.buffer);
// 解析输出结果
// 假设输出是 Float32List,表示每个类别的概率
List<double> probabilities = outputTensor.buffer.asFloat32List();
// 找到概率最高的类别
int maxProbIndex = 0;
for (int i = 0; i < probabilities.length; i++) {
if (probabilities[i] > probabilities[maxProbIndex]) {
maxProbIndex = i;
}
}
String predictedLabel = _labels![maxProbIndex];
double confidence = probabilities[maxProbIndex] * 100;
setState(() {
_result = '分类结果: $predictedLabel (${confidence.toStringAsFixed(2)}%)';
});
} catch (e) {
setState(() {
_result = '分类失败: $e';
print('Failed to classify image: $e');
});
} finally {
setState(() {
_isLoading = false;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('图像分类器'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_image == null
? const Text('没有选择图片')
: Image.file(
_image!,
height: 250,
width: 250,
fit: BoxFit.contain,
),
const SizedBox(height: 20),
Text(
_result,
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 20),
_isLoading
? const CircularProgressIndicator()
: ElevatedButton(
onPressed: _pickImage,
child: const Text('从相册选择图片'),
),
],
),
),
);
}
}
案例分析:
tflite_flutter 插件:这是在 Flutter 中加载和运行 TensorFlow Lite 模型的核心插件。Interpreter.fromAsset():用于从 Flutter assets 中加载 .tflite 模型文件。确保模型文件已在 pubspec.yaml 中声明。FileUtil.loadLabels():tflite_flutter_helper 提供的辅助函数,用于加载标签文件。ImageProcessorBuilder 用于构建图像处理管道。模型通常对输入图像的尺寸和像素值范围有严格要求。ResizeOp:将图像调整到模型所需的尺寸(例如 224x224)。NormalizeOp:将像素值归一化到模型所需的范围(例如 [-1, 1] 或 [0, 1])。TensorImage.fromFile():将 File 对象转换为 TensorImage,这是 tflite_flutter 处理图像的内部表示。_interpreter!.run(tensorImage.buffer, outputTensor.buffer):执行模型推理。tensorImage.buffer 是输入数据,outputTensor.buffer 是模型输出结果的缓冲区。_isLoading 状态显示加载指示器,并通过 _result 文本显示分类结果和错误信息。如何运行和测试:
assets/ml/ 目录下。flutter run。这个案例展示了如何在 Flutter 应用中集成设备端机器学习能力。通过 TensorFlow Lite,你可以构建智能应用,在用户设备上直接进行图像识别、文本处理等任务,提供快速、私密且无需网络连接的 AI 体验。