Flutter动物姿态识别插件apple_vision_animal_pose的使用

Flutter动物姿态识别插件apple_vision_animal_pose的使用

apple_vision_animal_pose

Apple Vision Animal Pose Detection 是一个 Flutter 插件,使 Flutter 应用程序能够使用 Apple Vision Animal Pose Detection

  • 该插件并非由 Apple 赞助或维护。作者是一些希望为 macOS 创建类似 Google ML Kit 的开发者。

要求

MacOS

  • 最低 osx 部署目标:14.0
  • Xcode 15 或更新版本
  • Swift 5
  • ML Kit 仅支持 64 位架构(x86_64 和 arm64)

iOS

  • 最低 ios 部署目标:17.0
  • Xcode 15 或更新版本
  • Swift 5
  • ML Kit 仅支持 64 位架构(x86_64 和 arm64)

开始使用

首先,你需要导入 'package:apple_vision/apple_vision.dart'

final GlobalKey cameraKey = GlobalKey(debugLabel: "cameraKey");
late AppleVisionAnimalPoseController visionController = AppleVisionAnimalPoseController();
InsertCamera camera = InsertCamera();
Size imageSize = const Size(640,640*9/16);
String? deviceId;
bool loading = true;

List<AnimalPoseData>? poseData;
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!, i.metadata!.size).then((data){
          poseData = 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?Container():CameraSetup(camera: camera, size: imageSize)
    ),
    ]+showPoints()
  );
}

List<Widget> showPoints(){
  if(poseData == null || poseData!.isEmpty) return[];
  Map<AnimalJoint,Color> colors = {
    AnimalJoint.rightBackElbow: Colors.orange,
    AnimalJoint.rightBackKnee: Colors.orange,
    AnimalJoint.rightBackPaw: Colors.orange,

    AnimalJoint.rightFrontKnee: Colors.purple,
    AnimalJoint.rightFrontPaw: Colors.purple,

    AnimalJoint.nose: Colors.pink,
    AnimalJoint.neck: Colors.pink,

    AnimalJoint.leftFrontPaw: Colors.indigo,
    AnimalJoint.leftFrontKnee: Colors.indigo,

    AnimalJoint.leftBackElbow: Colors.grey,
    AnimalJoint.leftBackKnee: Colors.grey,
    AnimalJoint.leftBackPaw: Colors.grey,

    AnimalJoint.tailTop: Colors.yellow,
    AnimalJoint.tailMiddle: Colors.yellow,
    AnimalJoint.tailBottom: Colors.yellow,

    AnimalJoint.leftEye: Colors.cyanAccent,
    AnimalJoint.leftEarTop: Colors.cyanAccent,
    AnimalJoint.leftEarBottom: Colors.cyanAccent,
    AnimalJoint.rightEarTop: Colors.blue,
    AnimalJoint.rightEarBottom: Colors.blue,
    AnimalJoint.rightEye: Colors.blue,
  };
  List<Widget> widgets = [];
  for(int j = 0; j < poseData!.length;j++){
    for(int i = 0; i < poseData![j].poses.length; i++){
      if(poseData![j].poses[i].confidence > 0.5){
        widgets.add(
          Positioned(
            top: imageSize.height-poseData![j].poses[i].location.y,
            left: poseData![j].poses[i].location.x,
            child: Container(
              width: 10,
              height: 10,
              decoration: BoxDecoration(
                color: colors[poseData![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)
  );
}

示例

你可以在这里找到此 API 的示例:main.dart

import 'package:apple_vision_animal_pose/apple_vision_animal_pose.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 VisionAnimalPose(),
    );
  }
}

class VisionAnimalPose extends StatefulWidget {
  const VisionAnimalPose({
    Key? key,
    this.onScanned
  }):super(key: key);

  final Function(dynamic data)? onScanned; 

  [@override](/user/override)
  _VisionAnimalPose createState() => _VisionAnimalPose();
}

class _VisionAnimalPose extends State<VisionAnimalPose>{
  final GlobalKey cameraKey = GlobalKey(debugLabel: "cameraKey");
  late AppleVisionAnimalPoseController visionController = AppleVisionAnimalPoseController();
  InsertCamera camera = InsertCamera();
  Size imageSize = const Size(640,640*9/16);
  String? deviceId;
  bool loading = true;

  List<AnimalPoseData>? poseData;
  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!, i.metadata!.size).then((data){
            poseData = 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?Container():CameraSetup(camera: camera, size: imageSize)
      ),
      ]+showPoints()
    );
  }

  List<Widget> showPoints(){
    if(poseData == null || poseData!.isEmpty) return[];
    Map<AnimalJoint,Color> colors = {
      AnimalJoint.rightBackElbow: Colors.orange,
      AnimalJoint.rightBackKnee: Colors.orange,
      AnimalJoint.rightBackPaw: Colors.orange,

      AnimalJoint.rightFrontKnee: Colors.purple,
      AnimalJoint.rightFrontPaw: Colors.purple,

      AnimalJoint.nose: Colors.pink,
      AnimalJoint.neck: Colors.pink,

      AnimalJoint.leftFrontPaw: Colors.indigo,
      AnimalJoint.leftFrontKnee: Colors.indigo,

      AnimalJoint.leftBackElbow: Colors.grey,
      AnimalJoint.leftBackKnee: Colors.grey,
      AnimalJoint.leftBackPaw: Colors.grey,

      AnimalJoint.tailTop: Colors.yellow,
      AnimalJoint.tailMiddle: Colors.yellow,
      AnimalJoint.tailBottom: Colors.yellow,

      AnimalJoint.leftEye: Colors.cyanAccent,
      AnimalJoint.leftEarTop: Colors.cyanAccent,
      AnimalJoint.leftEarBottom: Colors.cyanAccent,
      AnimalJoint.rightEarTop: Colors.blue,
      AnimalJoint.rightEarBottom: Colors.blue,
      AnimalJoint.rightEye: Colors.blue,
    };
    List<Widget> widgets = [];
    for(int j = 0; j < poseData!.length;j++){
      for(int i = 0; i < poseData![j].poses.length; i++){
        if(poseData![j].poses[i].confidence > 0.5){
          widgets.add(
            Positioned(
              top: imageSize.height-poseData![j].poses[i].location.y,
              left: poseData![j].poses[i].location.x,
              child: Container(
                width: 10,
                height: 10,
                decoration: BoxDecoration(
                  color: colors[poseData![j].poses[i].joint],
                  borderRadius: BorderRadius.circular(5)
                ),
              )
            )
          );
        }
      }
    }
    return widgets;
  }
}

更多关于Flutter动物姿态识别插件apple_vision_animal_pose的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter动物姿态识别插件apple_vision_animal_pose的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


apple_vision_animal_pose 是一个用于在 Flutter 应用中实现动物姿态识别的插件。它基于 Apple 的 Vision 框架,提供了在 iOS 设备上检测动物姿态的能力。以下是如何在 Flutter 项目中使用 apple_vision_animal_pose 插件的基本步骤。

1. 添加依赖

首先,你需要在 pubspec.yaml 文件中添加 apple_vision_animal_pose 插件的依赖。

dependencies:
  flutter:
    sdk: flutter
  apple_vision_animal_pose: ^0.1.0  # 请使用最新版本

然后,运行 flutter pub get 来获取依赖。

2. 导入插件

在你的 Dart 文件中导入 apple_vision_animal_pose 插件。

import 'package:apple_vision_animal_pose/apple_vision_animal_pose.dart';

3. 初始化插件

在使用插件之前,你需要初始化它。

final animalPose = AppleVisionAnimalPose();

4. 检测动物姿态

你可以使用 detectAnimalPose 方法来检测图像中的动物姿态。这个方法需要一个 UIImage 对象作为输入,并返回一个包含检测结果的 AnimalPose 对象。

Future<void> detectAnimalPose(UIImage image) async {
  try {
    final result = await animalPose.detectAnimalPose(image);
    if (result != null) {
      // 处理检测结果
      print('Detected animal pose: $result');
    } else {
      print('No animal pose detected.');
    }
  } catch (e) {
    print('Error detecting animal pose: $e');
  }
}

5. 处理检测结果

AnimalPose 对象通常包含检测到的关键点的位置信息。你可以根据这些信息来绘制动物的姿态或进行其他处理。

void processAnimalPose(AnimalPose pose) {
  for (var keypoint in pose.keypoints) {
    print('Keypoint: ${keypoint.type}, Position: ${keypoint.position}');
  }
}

6. 示例:从相机或图库中获取图像并检测姿态

以下是一个完整的示例,展示如何从相机或图库中获取图像,并使用 apple_vision_animal_pose 插件检测动物姿态。

import 'package:flutter/material.dart';
import 'package:apple_vision_animal_pose/apple_vision_animal_pose.dart';
import 'package:image_picker/image_picker.dart';
import 'dart:io';

class AnimalPoseDetectionPage extends StatefulWidget {
  [@override](/user/override)
  _AnimalPoseDetectionPageState createState() => _AnimalPoseDetectionPageState();
}

class _AnimalPoseDetectionPageState extends State<AnimalPoseDetectionPage> {
  final animalPose = AppleVisionAnimalPose();
  File? _image;

  Future<void> _pickImage(ImageSource source) async {
    final pickedFile = await ImagePicker().getImage(source: source);
    if (pickedFile != null) {
      setState(() {
        _image = File(pickedFile.path);
      });
      await _detectAnimalPose(_image!);
    }
  }

  Future<void> _detectAnimalPose(File image) async {
    final uiImage = UIImage.fromFile(image.path);
    try {
      final result = await animalPose.detectAnimalPose(uiImage);
      if (result != null) {
        processAnimalPose(result);
      } else {
        print('No animal pose detected.');
      }
    } catch (e) {
      print('Error detecting animal pose: $e');
    }
  }

  void processAnimalPose(AnimalPose pose) {
    for (var keypoint in pose.keypoints) {
      print('Keypoint: ${keypoint.type}, Position: ${keypoint.position}');
    }
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Animal Pose Detection'),
      ),
      body: Center(
        child: _image == null
            ? Text('No image selected.')
            : Image.file(_image!),
      ),
      floatingActionButton: Column(
        mainAxisAlignment: MainAxisAlignment.end,
        children: [
          FloatingActionButton(
            onPressed: () => _pickImage(ImageSource.camera),
            child: Icon(Icons.camera_alt),
          ),
          SizedBox(height: 10),
          FloatingActionButton(
            onPressed: () => _pickImage(ImageSource.gallery),
            child: Icon(Icons.photo_library),
          ),
        ],
      ),
    );
  }
}

void main() {
  runApp(MaterialApp(
    home: AnimalPoseDetectionPage(),
  ));
}
回到顶部