ultralytics / yolo-flutter-app

A Flutter plugin for Ultralytics YOLO computer vision models
https://ultralytics.com
GNU Affero General Public License v3.0
100 stars 40 forks source link

Drawing the bounding boxes on detection #46

Open hafidhhusna opened 3 months ago

hafidhhusna commented 3 months ago

i have the problem on the bounding boxes not drawn when i tried to run the inference on my flutter app code

import 'package:flutter/material.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:ultralytics_yolo/predict/detect/detect.dart'; import 'package:ultralytics_yolo/ultralytics_yolo.dart'; import 'package:ultralytics_yolo/yolo_model.dart';

class ScanController extends StatefulWidget { const ScanController({super.key});

@override State createState() => _ScanControllerState(); }

class _ScanControllerState extends State { final controller = UltralyticsYoloCameraController(); bool _cameraPermissionGranted = false; ObjectDetector? predictor;

@override void initState() { super.initState(); _checkCameraPermission(); }

Future _checkCameraPermission() async { try { final cameraStatus = await Permission.camera.status; print('Initial Camera status: $cameraStatus');

  if (!cameraStatus.isGranted) {
    print('Requesting camera permission...');
    final statuses = await [Permission.camera].request();
    print('Permission statuses after request: $statuses');

    setState(() {
      _cameraPermissionGranted = statuses[Permission.camera] == PermissionStatus.granted;
    });
  } else {
    setState(() {
      _cameraPermissionGranted = true;
    });
  }
} catch (e) {
  print('Error checking/requesting camera permission: $e');
  setState(() {
    _cameraPermissionGranted = false;
  });
}

print('Final Camera Permission granted: $_cameraPermissionGranted');

}

@override Widget build(BuildContext context) { return Scaffold( body: !_cameraPermissionGranted ? Center(child: Text('Camera permission not granted')) : FutureBuilder( future: _initObjectDetector(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return Center(child: CircularProgressIndicator()); } else if (snapshot.hasError) { print('Error initializing detector: ${snapshot.error}'); return Center(child: Text('Error initializing detector: ${snapshot.error}')); }

            predictor = snapshot.data;

            if (predictor == null) {
              print('Predictor initialization failed');
              return Center(child: Text('Predictor initialization failed'));
            }

            return Stack(
              children: [
                UltralyticsYoloCameraPreview(
                  predictor: predictor!,
                  controller: controller,
                  onCameraCreated: () async {
                    try {
                      print('Attempting to load model...');
                      await predictor!.loadModel(useGpu: false);
                      print('Model loaded successfully');
                    } catch (e) {
                      print('Error loading model: $e');
                    }
                  },
                ),
                StreamBuilder<double?>(
                  stream: predictor!.inferenceTime,
                  builder: (context, snapshot) {
                    final inferenceTime = snapshot.data;

                    print('Inference Time StreamBuilder updated: ${inferenceTime?.toStringAsFixed(2) ?? 'N/A'} ms');

                    return StreamBuilder<double?>(
                      stream: predictor!.fpsRate,
                      builder: (context, snapshot) {
                        final fpsRate = snapshot.data;

                        print('FPS Rate StreamBuilder updated: ${fpsRate?.toStringAsFixed(2) ?? 'N/A'}');

                        return Times(
                          inferenceTime: inferenceTime,
                          fpsRate: fpsRate,
                        );
                      },
                    );
                  },
                ),
              ],
            );
          },
        ),
);

}

Future _initObjectDetector() async { final model = LocalYoloModel( id: '', modelPath: 'assets/model/BILI.tflite', task: Task.classify, format: Format.tflite, metadataPath: 'assets/metadata/metadata.yaml', );

try {
  final detector = ObjectDetector(model: model);
  print('ObjectDetector initialized successfully');
  return detector;
} catch (e) {
  print('Error initializing ObjectDetector: $e');
  rethrow;
}

} }

class Times extends StatelessWidget { final double? inferenceTime; final double? fpsRate;

const Times({ Key? key, required this.inferenceTime, required this.fpsRate, }) : super(key: key);

@override Widget build(BuildContext context) { return Positioned( bottom: 10, left: 10, child: Column( children: [ Text('Inference Time: ${inferenceTime?.toStringAsFixed(2) ?? 'N/A'} ms'), Text('FPS Rate: ${fpsRate?.toStringAsFixed(2) ?? 'N/A'}'), ], ), ); } }

XeroDays commented 3 months ago

Try this code, i am using another class which has the model, you just need to put the model here and load the model.


import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:intelpro/controller/loadercontroller.dart';
import 'package:intelpro/screens/screenpreview.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:ultralytics_yolo/ultralytics_yolo.dart';

class LiveView extends StatefulWidget {
  const LiveView({super.key});

  @override
  State<LiveView> createState() => _LiveViewState();
}

class _LiveViewState extends State<LiveView> {
  final controller = UltralyticsYoloCameraController();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: FutureBuilder<bool>(
          future: _checkPermissions(),
          builder: (context, snapshot) {
            final allPermissionsGranted = snapshot.data ?? false;
            return !allPermissionsGranted
                ? Container()
                : FutureBuilder<ObjectDetector>(
                    future: _initObjectDetectorWithLocalModel(),
                    builder: (context, snapshot) {
                      final predictor = snapshot.data;
                      return predictor == null
                          ? Container()
                          : Stack(
                              children: [
                                UltralyticsYoloCameraPreview(
                                    controller: controller,
                                    predictor: predictor,
                                    onCameraCreated: () {
                                      predictor.loadModel(useGpu: true);
                                    }),
                                StreamBuilder(
                                    stream: predictor.detectionResultStream,
                                    builder: (context, snapshot) {
                                      final detectionResult = snapshot.data;

                                      return detectionResult == null
                                          ? Container()
                                          : Stack(
                                              children: detectionResult
                                                  .map((detectedObject) {
                                              final boundingBox =
                                                  detectedObject!.boundingBox;
                                              return Positioned(
                                                left: boundingBox.left,
                                                top: boundingBox.top,
                                                width: boundingBox.width,
                                                height: boundingBox.height,
                                                child: Container(
                                                  decoration: BoxDecoration(
                                                    color: Colors.green
                                                        .withOpacity(0.5),
                                                    border: Border.all(
                                                      color: Colors.green,
                                                      width: 2,
                                                    ),
                                                    borderRadius:
                                                        BorderRadius.circular(
                                                            5),
                                                  ),
                                                  child: //add label and confidence label
                                                      SingleChildScrollView(
                                                    child: Column(
                                                      children: [
                                                        Text(
                                                          detectedObject.label,
                                                          style:
                                                              const TextStyle(
                                                                  color: Colors
                                                                      .black,
                                                                  fontSize: 16),
                                                        ),
                                                        Text(
                                                          (detectedObject
                                                                      .confidence *
                                                                  100)
                                                              .toInt()
                                                              .toString(),
                                                          style:
                                                              const TextStyle(
                                                                  color: Colors
                                                                      .black,
                                                                  fontSize: 16),
                                                        ),
                                                      ],
                                                    ),
                                                  ),
                                                ),
                                              );
                                            }).toList());
                                    }),
                                StreamBuilder<double?>(
                                  stream: predictor.inferenceTime,
                                  builder: (context, snapshot) {
                                    final inferenceTime = snapshot.data;

                                    return StreamBuilder<double?>(
                                      stream: predictor.fpsRate,
                                      builder: (context, snapshot) {
                                        final fpsRate = snapshot.data;

                                        return Times(
                                          inferenceTime: inferenceTime,
                                          fpsRate: fpsRate,
                                        );
                                      },
                                    );
                                  },
                                ),
                              ],
                            );
                    },
                  );
          },
        ),
        floatingActionButton: FloatingActionButton(
          child: const Icon(Icons.abc),
          onPressed: () {
            controller.dispose();
            controller.closeCamera();
            controller.pauseLivePrediction();
            controller.toggleLensDirection();

            Navigator.pushReplacement(
              context,
              MaterialPageRoute(builder: (context) => const ScreenPreview()),
            );
          },
        ),
      ),
    );
  }

  Future<ObjectDetector> _initObjectDetectorWithLocalModel() async {
    return ObjectDetector(model: LoaderController.model!);
  }

  Future<bool> _checkPermissions() async {
    List<Permission> permissions = [];

    var cameraStatus = await Permission.camera.status;
    if (!cameraStatus.isGranted) permissions.add(Permission.camera);

    var storageStatus = await Permission.storage.status;
    if (!storageStatus.isGranted) permissions.add(Permission.storage);

    if (permissions.isEmpty) {
      return true;
    } else {
      try {
        Map<Permission, PermissionStatus> statuses =
            await permissions.request();
        return statuses[Permission.camera] == PermissionStatus.granted &&
            statuses[Permission.storage] == PermissionStatus.granted;
      } on Exception catch (_) {
        return false;
      }
    }
  }
}

class Times extends StatelessWidget {
  const Times({
    super.key,
    required this.inferenceTime,
    required this.fpsRate,
  });

  final double? inferenceTime;
  final double? fpsRate;

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Align(
        alignment: Alignment.bottomCenter,
        child: Container(
            margin: const EdgeInsets.all(20),
            padding: const EdgeInsets.all(20),
            decoration: const BoxDecoration(
              borderRadius: BorderRadius.all(Radius.circular(10)),
              color: Colors.black54,
            ),
            child: Text(
              '${(inferenceTime ?? 0).toStringAsFixed(1)} ms  -  ${(fpsRate ?? 0).toStringAsFixed(1)} FPS',
              style: const TextStyle(color: Colors.white70),
            )),
      ),
    );
  }
}
hafidhhusna commented 3 months ago

can you provide me with the loadercontroller and screenpreview code?

glenn-jocher commented 3 months ago

Hello!

Thank you for reaching out. It looks like you're making great progress with your Flutter app using Ultralytics YOLO. Unfortunately, I can't provide specific code for LoaderController and ScreenPreview as these are custom classes specific to your project. However, I can guide you on how to structure these components.

LoaderController

The LoaderController class should handle the loading of your YOLO model. Here's a basic example:

import 'package:ultralytics_yolo/ultralytics_yolo.dart';

class LoaderController {
  static YoloModel? model;

  static Future<void> loadModel() async {
    model = LocalYoloModel(
      id: 'your_model_id',
      modelPath: 'assets/model/BILI.tflite',
      task: Task.detect,
      format: Format.tflite,
      metadataPath: 'assets/metadata/metadata.yaml',
    );
    await model!.load();
  }
}

ScreenPreview

The ScreenPreview class can be a simple screen that displays the camera preview along with the detected objects. Here's a basic example:

import 'package:flutter/material.dart';

class ScreenPreview extends StatelessWidget {
  const ScreenPreview({Key? key}) : super(key: key);

  @hafidhhusna
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Screen Preview'),
      ),
      body: Center(
        child: Text('This is the screen preview.'),
      ),
    );
  }
}

Integration

Make sure to initialize the LoaderController before using it in your LiveView class:

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await LoaderController.loadModel();
  runApp(const LiveView());
}

If you encounter any issues, please ensure you are using the latest versions of the Ultralytics packages. If the problem persists, feel free to share more details, and we can troubleshoot further together.

Happy coding! 😊