import 'dart:io'; import 'dart:typed_data'; import 'dart:ui'; import 'package:flutter/material.dart'; import 'dart:async'; import 'package:flutter_vision/flutter_vision.dart'; import 'package:image_picker/image_picker.dart'; enum Options { none, imagev8 } void main() async { WidgetsFlutterBinding.ensureInitialized(); runApp(const MaterialApp( home: MyApp(), debugShowCheckedModeBanner: false, )); } class MyApp extends StatefulWidget { const MyApp({Key? key}) : super(key: key); @override State createState() => _MyAppState(); } class _MyAppState extends State { late FlutterVision vision; Options option = Options.none; @override void initState() { super.initState(); vision = FlutterVision(); } @override void dispose() async { super.dispose(); await vision.closeYoloModel(); } @override Widget build(BuildContext context) { return Scaffold( body: task(option), ); } Widget task(Options option) { return YoloImageV8(vision: vision); } } class YoloImageV8 extends StatefulWidget { final FlutterVision vision; const YoloImageV8({Key? key, required this.vision}) : super(key: key); @override State createState() => _YoloImageV8State(); } class _YoloImageV8State extends State { late List> yoloResults; File? imageFile; int imageHeight = 1; int imageWidth = 1; bool isLoaded = false; @override void initState() { super.initState(); loadYoloModel().then((value) { setState(() { yoloResults = []; isLoaded = true; }); }); } @override void dispose() async { super.dispose(); } @override Widget build(BuildContext context) { final Size size = MediaQuery.of(context).size; if (!isLoaded) { return const Scaffold( body: Center( child: Text("Model not loaded, waiting for it"), ), ); } return Scaffold( appBar: AppBar( title: const Text("Yolo V8"), ), body: Column( children: [ Expanded(child: imageFile != null ? Image.file(imageFile!) : const SizedBox()), Stack( fit: StackFit.expand, children: [ Align( alignment: Alignment.bottomCenter, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ TextButton( onPressed: pickImage, child: const Text("ambil gmbr serah"), ), // ElevatedButton( // onPressed: yoloOnImage, // child: const Text("Ya test"), // ) ], ), ), ], ), ...displayBoxesAroundRecognizedObjects(size), ], ), ); } Future loadYoloModel() async { await widget.vision.loadYoloModel( labels: 'assets/labels.txt', modelPath: 'assets/yolov8m_float16.tflite', modelVersion: "yolov8", quantization: false, numThreads: 2, useGpu: true, ); setState(() { isLoaded = true; }); } Future pickImage() async { final ImagePicker picker = ImagePicker(); final XFile? photo = await picker.pickImage(source: ImageSource.gallery); if (photo != null) { setState(() { imageFile = File(photo.path); yoloOnImage(); }); } } yoloOnImage() async { yoloResults.clear(); Uint8List byte = await imageFile!.readAsBytes(); final image = await decodeImageFromList(byte); imageHeight = image.height; imageWidth = image.width; final result = await widget.vision.yoloOnImage( bytesList: byte, imageHeight: image.height, imageWidth: image.width, iouThreshold: 0.8, confThreshold: 0.2, classThreshold: 0.3, ); if (result.isNotEmpty) { setState(() { yoloResults = result; }); } } List displayBoxesAroundRecognizedObjects(Size screen) { if (yoloResults.isEmpty) return []; double factorX = screen.width / (imageWidth); double imgRatio = imageWidth / imageHeight; double newWidth = imageWidth * factorX; double newHeight = newWidth / imgRatio; double factorY = newHeight / (imageHeight); double pady = (screen.height - newHeight) / 2; Color colorPick = const Color.fromARGB(255, 50, 233, 30); return yoloResults.map((result) { return Positioned( left: result["box"][0] * factorX, top: result["box"][1] * factorY + pady, width: (result["box"][2] - result["box"][0]) * factorX, height: (result["box"][3] - result["box"][1]) * factorY, child: Container( decoration: BoxDecoration( borderRadius: const BorderRadius.all(Radius.circular(10.0)), border: Border.all(color: Colors.pink, width: 2.0), ), child: Text( "${result['tag']} ${(result['box'][4] * 100).toStringAsFixed(0)}%", style: TextStyle( background: Paint()..color = colorPick, color: Colors.white, fontSize: 12.0, ), ), ), ); }).toList(); } }