ultralytics / yolo-flutter-app

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

Unhandled Exception: type '_Map<Object?, Object?>' is not a subtype of type 'Map<String, dynamic>?' in type cast #45

Open m-naeem66622 opened 1 month ago

m-naeem66622 commented 1 month ago

Problem Description

I had used the example which is prefectly with my model. Now I have tried to feed a single image using camera to take a picture or image picker to get the image from the gallery. but somehow it's not working throwing an error. the issue is coming from here https://github.com/ultralytics/yolo-flutter-app/blob/6ef5571270c5d5229ca20c9c4502010863bb7898/lib/ultralytics_yolo_platform_channel.dart#L152

Performing hot restart...                                               
Restarted application in 2,217ms.
I/flutter (14663): File copied to: /data/user/0/com.ultralytics.ultralytics_yolo_example/files/assets/yolov8m_int8.tflite
I/flutter (14663): File copied to: /data/user/0/com.ultralytics.ultralytics_yolo_example/files/assets/metadata.yaml
I/System.out(14663): INPUT_SIZE:320
I/tflite  (14663): Replacing 318 out of 318 node(s) with delegate (TfLiteGpuDelegateV2) node, yielding 1 partitions for the whole graph.
I/tflite  (14663): Created 1 GPU delegate kernels.
I/flutter (14663): File exists
E/flutter (14663): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: type '_Map<Object?, Object?>' is not a subtype of type 'Map<String, dynamic>?' in type cast
E/flutter (14663): #0      PlatformChannelUltralyticsYolo.detectImage.<anonymous closure> (package:ultralytics_yolo/ultralytics_yolo_platform_channel.dart:152:19)
E/flutter (14663): #1      _Array.forEach (dart:core-patch/array.dart:40:8)
E/flutter (14663): #2      PlatformChannelUltralyticsYolo.detectImage (package:ultralytics_yolo/ultralytics_yolo_platform_channel.dart:151:13)
E/flutter (14663): <asynchronous suspension>
E/flutter (14663): #3      _ImageDetectionScreenState._captureAndDetectImage (package:ultralytics_yolo_example/main.dart:120:31)
E/flutter (14663): <asynchronous suspension>
E/flutter (14663): 

Reproducible Code

import 'package:flutter/material.dart';
import 'dart:io' as io;
import 'package:image_picker/image_picker.dart';
import 'package:ultralytics_yolo/ultralytics_yolo.dart';
import 'package:ultralytics_yolo/yolo_model.dart';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:flutter/services.dart';
import 'dart:io';
import 'package:permission_handler/permission_handler.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: ImageDetectionScreen(),
    );
  }
}

class ImageDetectionScreen extends StatefulWidget {
  @override
  _ImageDetectionScreenState createState() => _ImageDetectionScreenState();
}

class _ImageDetectionScreenState extends State<ImageDetectionScreen> {
  late ObjectDetector detector;
  List<DetectedObject?>? _detectedObjects;
  final ImagePicker _picker = ImagePicker();
  String? _imagePath;

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

  Future<void> _initializeDetector() async {
    final modelPath = await _copy('assets/yolov8m_int8.tflite');
    final metadataPath = await _copy('assets/metadata.yaml');
    final model = LocalYoloModel(
        id: 'custom_model',
        modelPath: modelPath,
        task: Task.detect,
        format: Format.tflite,
        metadataPath: metadataPath);

    detector = ObjectDetector(model: model);
    await detector.loadModel();
  }

  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;
      }
    }
  }

  Future<String> _copy(String assetPath) async {
    try {
      final directory = await getApplicationSupportDirectory();
      final path = join(directory.path, assetPath);
      await io.Directory(dirname(path)).create(recursive: true);
      final file = io.File(path);
      if (!await file.exists()) {
        final byteData = await rootBundle.load(assetPath);
        await file.writeAsBytes(byteData.buffer
            .asUint8List(byteData.offsetInBytes, byteData.lengthInBytes));
      }
      print('File copied to: $path');
      return file.path;
    } catch (e) {
      print('Error copying file: $e');
      rethrow;
    }
  }

  Future<void> _captureAndDetectImage(ImageSource source) async {
    bool permissionsGranted = await _checkPermissions();
    if (!permissionsGranted) {
      ScaffoldMessenger.of(this.context).showSnackBar(
        SnackBar(content: Text('Permissions not granted')),
      );
      return;
    }

    final pickedFile = await _picker.pickImage(source: source);
    if (pickedFile != null) {
      setState(() {
        _imagePath = pickedFile.path;
      });

      // check if the file exists or not
      if (!await File(pickedFile.path).exists()) {
        print('File does not exist');
        return;
      } else {
        print('File exists');
      }

      final detectedObjects = await detector.detect(imagePath: pickedFile.path);

      print('Raw detection output: $detectedObjects');

      if (detectedObjects == null || detectedObjects.isEmpty) {
        print('No objects detected or empty response');
        setState(() {
          _detectedObjects = [];
        });
        return;
      }

      setState(() {
        _detectedObjects = detectedObjects;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('YOLO Image Detection'),
      ),
      body: Column(
        children: [
          if (_imagePath != null) Image.file(File(_imagePath!)),
          if (_detectedObjects != null)
            Expanded(
              child: ListView.builder(
                itemCount: _detectedObjects!.length,
                itemBuilder: (context, index) {
                  final detectedObject = _detectedObjects![index];
                  if (detectedObject == null) return Container();
                  return ListTile(
                    title: Text('Label: ${detectedObject.label}'),
                    subtitle: Text(
                        'Confidence: ${(detectedObject.confidence * 100).toStringAsFixed(2)}%'),
                  );
                },
              ),
            ),
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              ElevatedButton(
                onPressed: () => _captureAndDetectImage(ImageSource.camera),
                child: Text('Capture Image'),
              ),
              SizedBox(width: 20),
              ElevatedButton(
                onPressed: () => _captureAndDetectImage(ImageSource.gallery),
                child: Text('Import Image'),
              ),
            ],
          ),
        ],
      ),
    );
  }
}
muhammad-qasim-cowlar commented 1 month ago

Have you tried using String instead of String? here: String? _imagePath;

XeroDays commented 1 month ago

I am also facing same issue

this is my code just like you mentioned @pderrenger i tried same


void scan() async {
    final objectDetector = ObjectDetector(
      model: LoaderController.model!,
    );
    await objectDetector.loadModel(useGpu: true);
    final detectedObjects = await objectDetector.detect(imagePath: imagePath);
    if (detectedObjects is Map<Object?, Object?>) { 
      print('Detected objects: $detectedObjects');
    } else {
      print('Type mismatch: ${detectedObjects.runtimeType}');
    }
  }
}
image

@m-naeem66622 did you found any solutions?

XeroDays commented 1 month ago

i fixed this issue, @pderrenger . can i create PR to this repo?

XeroDays commented 1 month ago

47 Pull Requests has fixed this bug.