Flutter目标检测应用报错:Interpreter busy问题求助
Flutter目标检测应用运行时错误及文本显示问题解决
问题描述
运行Flutter目标检测应用时触发以下运行时错误:
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(Failed to run model, Interpreter busy, java.lang.RuntimeException: Interpreter busy)
同时检测出的目标文本无法正常显示,原代码如下:
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:camera/camera.dart'; import 'package:flutter_tflite/flutter_tflite.dart'; //import 'package:tflite/tflite.dart'; String result = ""; class CameraScreen extends StatefulWidget { final CameraDescription camera; CameraScreen(this.camera); @override _CameraScreenState createState() => _CameraScreenState(); } class _CameraScreenState extends State<CameraScreen> { loadModel() async { await Tflite.loadModel( model: "assets/mobilenet_v1_1.0_224.tflite", labels: "assets/mobilenet_v1_1.0_224.txt"); } late CameraController _controller; late CameraImage imgCam; late Future<void> _initializeControllerFuture; @override void initState() { super.initState(); _controller = CameraController(widget.camera, ResolutionPreset.medium); _initializeControllerFuture = _controller.initialize().then((value) => { setState((() { _controller.startImageStream((imageFromStream) => { imgCam = imageFromStream, runModel(); }); })) }); loadModel(); } runModel() async { if (imgCam != null) { var recognition = await Tflite.runModelOnFrame( bytesList: imgCam.planes.map((plane) { return plane.bytes; }).toList(), imageHeight: imgCam.height, imageWidth: imgCam.width, imageMean: 127.5, imageStd: 127.5, rotation: 90, numResults: 1, threshold: 0.1, asynch: true, ); result = "yes"; recognition?.forEach((response) { result += response["label"] + " " + (response["confidence"] as double).toStringAsFixed(2) + "\n\n"; print(result); print("\n\n\n\n\n\n\n\n\n"); }); setState(() { result; }); } } @override void dispose() async { _controller.dispose(); await Tflite.close(); super.dispose(); } @override Widget build(BuildContext context) { final size = MediaQuery.of(context).size; final deviceRatio = size.width / size.height; return Scaffold( body: FutureBuilder<void>( future: _initializeControllerFuture, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { // If the Future is complete, display the preview return AspectRatio( aspectRatio: deviceRatio, child: CameraPreview( child: Center( child: Text(result), ), _controller), ); } else { // Otherwise, display a loading indicator return Center(child: CircularProgressIndicator()); } })); } }
问题分析及修复方案
1. Interpreter busy 异常原因及修复
相机流每秒推送大量帧,原代码每收到一帧就调用runModel(),导致TFLite解释器被并发请求占满,抛出Interpreter busy异常。
修复方式:添加任务锁标志位,确保同一时间只有一个模型推理任务在执行。
2. 检测文本无法显示原因及修复
setState(() { result; });写法错误,未触发状态更新;- 全局变量
result在多线程环境下易出现状态混乱; - 文本直接叠加在相机预览上,无背景遮挡导致可读性差甚至被覆盖。
修复方式:
- 将
result改为State类的成员变量; - 修正
setState写法,确保UI更新; - 使用
Stack布局让文本显示在预览上方,添加半透明背景提升可读性。
修改后的完整代码
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:camera/camera.dart'; import 'package:flutter_tflite/flutter_tflite.dart'; class CameraScreen extends StatefulWidget { final CameraDescription camera; CameraScreen(this.camera); @override _CameraScreenState createState() => _CameraScreenState(); } class _CameraScreenState extends State<CameraScreen> { String _result = "未检测到目标"; bool _isProcessing = false; // 任务锁标志位 late CameraController _controller; late Future<void> _initializeControllerFuture; loadModel() async { await Tflite.loadModel( model: "assets/mobilenet_v1_1.0_224.tflite", labels: "assets/mobilenet_v1_1.0_224.txt", ); } @override void initState() { super.initState(); _controller = CameraController(widget.camera, ResolutionPreset.medium); _initializeControllerFuture = _controller.initialize().then((_) { _controller.startImageStream((imageFromStream) { if (!_isProcessing) runModel(imageFromStream); }); }); loadModel(); } runModel(CameraImage imgCam) async { _isProcessing = true; try { var recognition = await Tflite.runModelOnFrame( bytesList: imgCam.planes.map((plane) => plane.bytes).toList(), imageHeight: imgCam.height, imageWidth: imgCam.width, imageMean: 127.5, imageStd: 127.5, rotation: 90, numResults: 1, threshold: 0.1, asynch: true, ); String newResult = ""; recognition?.forEach((response) { newResult += "${response["label"]} ${(response["confidence"] as double).toStringAsFixed(2)}\n"; }); setState(() { _result = newResult.isNotEmpty ? newResult : "未检测到目标"; }); } catch (e) { print("模型推理出错: $e"); } finally { _isProcessing = false; // 无论成功失败都释放锁 } } @override void dispose() async { _controller.dispose(); await Tflite.close(); super.dispose(); } @override Widget build(BuildContext context) { final size = MediaQuery.of(context).size; final deviceRatio = size.width / size.height; return Scaffold( body: FutureBuilder<void>( future: _initializeControllerFuture, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { return AspectRatio( aspectRatio: deviceRatio, child: Stack( children: [ CameraPreview(_controller), Center( child: Container( padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8), color: Colors.black54, child: Text( _result, style: TextStyle(color: Colors.white, fontSize: 18), textAlign: TextAlign.center, ), ), ), ], ), ); } else { return Center(child: CircularProgressIndicator()); } }, ), ); } }
关键修改点说明
- 新增
_isProcessing标志位,避免并发调用模型导致解释器繁忙; - 将全局
result改为State成员变量_result,避免状态混乱; - 修正
setState写法,确保正确触发UI更新; - 使用
Stack布局让文本显示在相机预览上方,添加半透明背景提升可读性; - 在
runModel中添加try-catch捕获异常,确保标志位能被重置; - 移除冗余的
imgCam成员变量,直接使用流传递的帧数据。
内容的提问来源于stack exchange,提问作者20C079 Shakeel Akthar
相关产品推荐
相关产品推荐

