Flutter手势识别插件apple_vision_hand的使用
Flutter手势识别插件apple_vision_hand的使用
apple_vision_hand
是一个用于Flutter应用的手势识别插件,它利用了苹果公司的Vision框架来检测手部姿势。以下是如何使用该插件的详细步骤。
插件信息
apple_vision_hand
是一个基于苹果Vision框架的手势识别插件,用于在Flutter应用中实现手部姿势检测。
注意: 该插件并非由苹果公司赞助或维护。作者是一些希望为macOS开发类似Google ML Kit功能的开发者。
要求
MacOS
- 最低osx部署目标版本: 12.0
- Xcode 13 或更新版本
- Swift 5
- ML Kit仅支持64位架构(x86_64 和 arm64)
iOS
- 最低ios部署目标版本: 14.0
- Xcode 13 或更新版本
- Swift 5
- ML Kit仅支持64位架构(x86_64 和 arm64)
开始使用
首先,在你的项目中导入插件:
import 'package:apple_vision_hand/apple_vision_hand.dart';
然后,初始化插件并设置相机:
final GlobalKey cameraKey = GlobalKey(debugLabel: "cameraKey");
late AppleVisionHandController visionController;
InsertCamera camera = InsertCamera();
Size imageSize = const Size(640, 640 * 9 / 16);
String? deviceId;
bool loading = true;
List<HandData>? handData;
late double deviceWidth;
late double deviceHeight;
[@override](/user/override)
void initState() {
camera.setupCameras().then((value) {
setState(() {
loading = false;
});
camera.startLiveFeed((InputImage i) {
if (i.metadata?.size != null) {
imageSize = i.metadata!.size;
}
if (mounted) {
Uint8List? image = i.bytes;
visionController.processImage(image!, imageSize).then((data) {
handData = data;
setState(() {});
});
}
});
});
super.initState();
}
[@override](/user/override)
void dispose() {
camera.dispose();
super.dispose();
}
[@override](/user/override)
Widget build(BuildContext context) {
deviceWidth = MediaQuery.of(context).size.width;
deviceHeight = MediaQuery.of(context).size.height;
return Stack(
children: [
SizedBox(
width: imageSize.width,
height: imageSize.height,
child: loading ? loadingWidget() : CameraSetup(camera: camera, size: imageSize),
),
] + showPoints()
);
}
List<Widget> showPoints() {
if (handData == null || handData!.isEmpty) return [];
List<Widget> widgets = [];
Map<FingerJoint, Color> colors = {
FingerJoint.thumbCMC: Colors.amber,
FingerJoint.thumbIP: Colors.amber,
FingerJoint.thumbMP: Colors.amber,
FingerJoint.thumbTip: Colors.amber,
FingerJoint.indexDIP: Colors.green,
FingerJoint.indexMCP: Colors.green,
FingerJoint.indexPIP: Colors.green,
FingerJoint.indexTip: Colors.green,
FingerJoint.middleDIP: Colors.purple,
FingerJoint.middleMCP: Colors.purple,
FingerJoint.middlePIP: Colors.purple,
FingerJoint.middleTip: Colors.purple,
FingerJoint.ringDIP: Colors.pink,
FingerJoint.ringMCP: Colors.pink,
FingerJoint.ringPIP: Colors.pink,
FingerJoint.ringTip: Colors.pink,
FingerJoint.littleDIP: Colors.cyanAccent,
FingerJoint.littleMCP: Colors.cyanAccent,
FingerJoint.littlePIP: Colors.cyanAccent,
FingerJoint.littleTip: Colors.cyanAccent
};
for (int j = 0; j < handData!.length; j++) {
for (int i = 0; i < handData![j].poses.length; i++) {
if (handData![j].poses[i].confidence > 0.5) {
widgets.add(
Positioned(
top: handData![j].poses[i].location.y,
left: handData![j].poses[i].location.x,
child: Container(
width: 10,
height: 10,
decoration: BoxDecoration(
color: colors[handData![j].poses[i].joint],
borderRadius: BorderRadius.circular(5)
),
)
)
);
}
}
}
return widgets;
}
Widget loadingWidget() {
return Container(
width: deviceWidth,
height: deviceHeight,
color: Theme.of(context).canvasColor,
alignment: Alignment.center,
child: const CircularProgressIndicator(color: Colors.blue)
);
}
示例代码
以下是完整的示例代码,演示如何使用apple_vision_hand
插件进行手势识别。
import 'package:apple_vision_hand/apple_vision_hand.dart';
import 'package:flutter/material.dart';
import '../camera/camera_insert.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'camera/input_image.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const VisionHand(),
);
}
}
class VisionHand extends StatefulWidget {
const VisionHand({
Key? key,
this.onScanned
}) : super(key: key);
final Function(dynamic data)? onScanned;
[@override](/user/override)
_VisionHand createState() => _VisionHand();
}
class _VisionHand extends State<VisionHand> {
final GlobalKey cameraKey = GlobalKey(debugLabel: "cameraKey");
AppleVisionHandController visionController = AppleVisionHandController();
InsertCamera camera = InsertCamera();
Size imageSize = const Size(640, 640 * 9 / 16);
String? deviceId;
bool loading = true;
List<HandData>? handData;
late double deviceWidth;
late double deviceHeight;
[@override](/user/override)
void initState() {
camera.setupCameras().then((value) {
setState(() {
loading = false;
});
camera.startLiveFeed((InputImage i) {
if (i.metadata?.size != null) {
imageSize = i.metadata!.size;
}
if (mounted) {
Uint8List? image = i.bytes;
visionController.processImage(image!, imageSize).then((data) {
handData = data;
setState(() {});
});
}
});
});
super.initState();
}
[@override](/user/override)
void dispose() {
camera.dispose();
super.dispose();
}
[@override](/user/override)
Widget build(BuildContext context) {
deviceWidth = MediaQuery.of(context).size.width;
deviceHeight = MediaQuery.of(context).size.height;
return Stack(
children: [
SizedBox(
width: imageSize.width,
height: imageSize.height,
child: loading ? loadingWidget() : CameraSetup(camera: camera, size: imageSize),
),
] + showPoints()
);
}
List<Widget> showPoints() {
if (handData == null || handData!.isEmpty) return [];
List<Widget> widgets = [];
Map<FingerJoint, Color> colors = {
FingerJoint.thumbCMC: Colors.amber,
FingerJoint.thumbIP: Colors.amber,
FingerJoint.thumbMP: Colors.amber,
FingerJoint.thumbTip: Colors.amber,
FingerJoint.indexDIP: Colors.green,
FingerJoint.indexMCP: Colors.green,
FingerJoint.indexPIP: Colors.green,
FingerJoint.indexTip: Colors.green,
FingerJoint.middleDIP: Colors.purple,
FingerJoint.middleMCP: Colors.purple,
FingerJoint.middlePIP: Colors.purple,
FingerJoint.middleTip: Colors.purple,
FingerJoint.ringDIP: Colors.pink,
FingerJoint.ringMCP: Colors.pink,
FingerJoint.ringPIP: Colors.pink,
FingerJoint.ringTip: Colors.pink,
FingerJoint.littleDIP: Colors.cyanAccent,
FingerJoint.littleMCP: Colors.cyanAccent,
FingerJoint.littlePIP: Colors.cyanAccent,
FingerJoint.littleTip: Colors.cyanAccent
};
for (int j = 0; j < handData!.length; j++) {
for (int i = 0; i < handData![j].poses.length; i++) {
if (handData![j].poses[i].confidence > 0.5) {
widgets.add(
Positioned(
top: handData![j].poses[i].location.y,
left: handData![j].poses[i].location.x,
child: Container(
width: 10,
height: 10,
decoration: BoxDecoration(
color: colors[handData![j].poses[i].joint],
borderRadius: BorderRadius.circular(5)
),
)
)
);
}
}
}
return widgets;
}
Widget loadingWidget() {
return Container(
width: deviceWidth,
height: deviceHeight,
color: Theme.of(context).canvasColor,
alignment: Alignment.center,
child: const CircularProgressIndicator(color: Colors.blue)
);
}
}
更多关于Flutter手势识别插件apple_vision_hand的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter手势识别插件apple_vision_hand的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,关于使用Flutter手势识别插件apple_vision_hand
,这里是一个简单的代码案例,展示如何在Flutter应用中集成和使用这个插件来识别手势。
首先,你需要确保你的Flutter环境已经设置好,并且你的pubspec.yaml
文件中已经添加了apple_vision_hand
依赖。请注意,这个插件目前只支持iOS平台。
dependencies:
flutter:
sdk: flutter
apple_vision_hand: ^最新版本号 # 请替换为实际的最新版本号
然后,运行flutter pub get
来安装依赖。
接下来是一个简单的Flutter应用示例,展示如何使用apple_vision_hand
插件:
import 'package:flutter/material.dart';
import 'package:apple_vision_hand/apple_vision_hand.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Hand Gesture Recognition',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HandGestureRecognitionPage(),
);
}
}
class HandGestureRecognitionPage extends StatefulWidget {
@override
_HandGestureRecognitionPageState createState() => _HandGestureRecognitionPageState();
}
class _HandGestureRecognitionPageState extends State<HandGestureRecognitionPage> {
late AppleVisionHandController _controller;
late CameraImage? _currentImage;
@override
void initState() {
super.initState();
_controller = AppleVisionHandController();
// 监听手势识别结果
_controller.handLandmarksStream.listen((handLandmarks) {
// 在这里处理识别到的手势,例如更新UI显示手势关键点
print('Hand landmarks: $handLandmarks');
});
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Hand Gesture Recognition'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Capture your hand gesture to see the recognition result.',
),
SizedBox(height: 20),
// 这里你可以添加一个相机预览组件,用于捕获实时图像
// 由于篇幅限制,这里简单用一个容器代替
Container(
height: 300,
width: 300,
color: Colors.grey[200],
child: _currentImage == null
? Center(child: Text('No image captured yet'))
: CustomPaint(
painter: HandGesturePainter(_controller.latestHandLandmarks),
),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
// 这里模拟捕获一张图像(在实际应用中,应从相机获取图像)
// 由于apple_vision_hand插件目前不支持直接从相机获取图像进行处理,
// 因此这里仅展示如何处理假设已经捕获的图像数据。
// 你需要实现自己的图像捕获逻辑,并将CameraImage传递给_processImage方法。
// _currentImage = await _captureImageFromCamera();
// _processImage(_currentImage!);
},
tooltip: 'Capture Image',
child: Icon(Icons.camera_alt),
),
);
}
// 假设的图像捕获方法(实际需自行实现)
// Future<CameraImage?> _captureImageFromCamera() async {
// // 实现图像捕获逻辑
// return null;
// }
// 图像处理方法(假设已经捕获到图像)
// void _processImage(CameraImage image) async {
// try {
// // 将CameraImage转换为CVPixelBufferRef,然后传递给apple_vision_hand进行处理
// // 注意:这里需要实现CameraImage到CVPixelBufferRef的转换逻辑,
// // 由于apple_vision_hand插件未提供直接转换的方法,因此这里仅作为示例说明。
// // CVPixelBufferRef pixelBuffer = ...; // 转换得到的CVPixelBufferRef
// // _controller.processImage(pixelBuffer);
// } catch (e) {
// print('Error processing image: $e');
// }
// }
}
// 自定义Painter用于在图像上绘制手势关键点
class HandGesturePainter extends CustomPainter {
final List<List<Offset>>? handLandmarks;
HandGesturePainter(this.handLandmarks);
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = Colors.red
..style = PaintingStyle.fill
..strokeWidth = 2.0;
if (handLandmarks != null) {
for (var landmark in handLandmarks!) {
for (var point in landmark) {
canvas.drawCircle(point, 5.0, paint);
}
}
}
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return oldDelegate != this;
}
}
注意:
- 由于
apple_vision_hand
插件目前不支持直接从Flutter的camera
插件获取的图像进行处理,上面的代码示例中图像捕获和处理部分被注释掉了。你需要实现自己的图像捕获逻辑,并将CameraImage
转换为CVPixelBufferRef
,然后传递给apple_vision_hand
进行处理。 HandGesturePainter
类是一个简单的自定义Painter,用于在捕获的图像上绘制手势关键点。你需要根据实际的handLandmarks
数据结构进行调整。- 由于
apple_vision_hand
插件的API和使用方法可能会随着版本更新而变化,请参考插件的官方文档和示例代码以获取最新和最准确的信息。
希望这个示例能帮助你开始在Flutter应用中使用apple_vision_hand
插件进行手势识别。