Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
m-naeem66622 opened this issue Jul 25, 2024 · 24 comments · Fixed by #47
Labels
fixed Bug has been resolved

Comments

@m-naeem66622
Copy link

m-naeem66622 commented Jul 25, 2024

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

json = json as Map<String, dynamic>?;

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
Copy link

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

@pderrenger
Copy link
Member

@muhammad-qasim-cowlar thank you for reaching out! It looks like the issue might be related to type casting within the detectImage method. Specifically, the error message indicates a type mismatch between _Map<Object?, Object?> and Map<String, dynamic>?.

To address your suggestion, changing String? _imagePath to String _imagePath might not directly resolve the type casting issue, but it's worth ensuring that _imagePath is properly initialized and not null when used.

Here are a few steps to help troubleshoot and potentially resolve the issue:

  1. Update Packages: Ensure you are using the latest versions of all relevant packages. Sometimes, bugs are fixed in newer releases.

  2. Type Casting: The error suggests a type casting issue. You might want to explicitly cast the map to Map<String, dynamic> where the error occurs. For example:

    final detectedObjects = await detector.detect(imagePath: pickedFile.path) as Map<String, dynamic>;
  3. Null Safety: Ensure that all variables are properly initialized and checked for null values before use. For example:

    if (_imagePath != null) {
        // Use _imagePath
    }
  4. Debugging: Add some debug prints to check the types of the variables at runtime:

    print(detectedObjects.runtimeType);

Here’s a small code snippet to illustrate the type casting:

final detectedObjects = await detector.detect(imagePath: pickedFile.path);
if (detectedObjects is Map<String, dynamic>) {
    // Proceed with detectedObjects
} else {
    print('Type mismatch: ${detectedObjects.runtimeType}');
}

Please try these steps and let us know if the issue persists. If it does, providing additional details about the exact versions of the packages you are using and any other relevant context would be helpful.

Thank you for your patience and for being a part of the YOLO community! 😊

@XeroDays
Copy link
Contributor

XeroDays commented Aug 7, 2024

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
Copy link
Contributor

XeroDays commented Aug 7, 2024

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

@XeroDays
Copy link
Contributor

XeroDays commented Aug 7, 2024

#47 Pull Requests has fixed this bug.

@pderrenger
Copy link
Member

Thank you for your proactive approach and for resolving the issue! 🎉

We appreciate your willingness to contribute to the Ultralytics repository. Please feel free to create a Pull Request (PR) with your fix. Make sure to include a clear description of the issue and how your changes address it. This will help the maintainers review and merge your PR efficiently.

Before submitting, kindly ensure that the issue is reproducible in the latest versions of the packages and that your fix is compatible with them. This helps maintain consistency and reliability across the project.

Looking forward to your contribution! If you have any questions or need further assistance, feel free to ask here.

Thank you for being an active member of the YOLO community! 😊

glenn-jocher added a commit that referenced this issue Aug 14, 2024
…ed (#47)

Co-authored-by: UltralyticsAssistant <[email protected]>
Co-authored-by: Glenn Jocher <[email protected]>
@glenn-jocher glenn-jocher added the fixed Bug has been resolved label Aug 14, 2024
@ice6
Copy link

ice6 commented Sep 26, 2024

encountered same problem.

so the bug was fixed. a fixed version like 0.0.4 release is good for users :)

@XeroDays
Copy link
Contributor

@ice6 Bug is fixed but they didnt released it to prod.
@pderrenger @glenn-jocher Can you guys help on this pne?

@glenn-jocher
Copy link
Member

Please update to the latest version of the package to see if the fix is included. If the issue persists, let us know.

@ice6
Copy link

ice6 commented Sep 27, 2024

even the bug was fixed.

I think it is not a good idea to return List<DetectedObject?>? type to end user, List<DetectedObject>? is better.

now, I have to do the something like this in my app:

    for (var f in files) {
      var imagePath = f.xFile.path;
      var detectedObjects = await predictor!.detect(imagePath: imagePath);
      f.detectedObjects = detectedObjects?.where((obj) => obj != null).map((obj) => obj!).toList() ?? <DetectedObject>[];
    }

a null DetectedObject is non-sense for end users ;)

@glenn-jocher
Copy link
Member

Thank you for your feedback. We appreciate your suggestion regarding the return type. We'll consider this for future improvements to enhance usability. If you have any more insights, feel free to share!

@ohTIO
Copy link

ohTIO commented Oct 3, 2024

how do i use an image picker instead of camera preview.

@pderrenger
Copy link
Member

You can use the image_picker package to select images from the gallery. Here's a quick example:

final pickedFile = await ImagePicker().pickImage(source: ImageSource.gallery);
if (pickedFile != null) {
  final imagePath = pickedFile.path;
  // Use imagePath with your detector
}

Ensure you have the necessary permissions set up in your app.

@HansLuft778
Copy link

I am still encountering the issue. When will the fix go live?

@pderrenger
Copy link
Member

@HansLuft778 please ensure you're using the latest version of the package, as updates may include the fix. If the issue persists, let us know.

@XeroDays
Copy link
Contributor

XeroDays commented Oct 5, 2024

@HansLuft778 The issue is merged with base branch, but still new release is not on the air.

@mnawazshah
Copy link

Having same issue ....
It is working fine if we use UltralyticsCameraPreview but if we want to detect on image then getting this error.
If this issue was fixed then it is not in production yet

@pderrenger
Copy link
Member

Please ensure you're using the latest package version, as updates may include the fix. If the issue persists, let us know.

@XeroDays
Copy link
Contributor

@pderrenger is a bot.

@pderrenger
Copy link
Member

@XeroDays i'm here to assist with any questions or issues you have regarding Ultralytics. How can I help you today?

@mnawazshah
Copy link

@XeroDays yes 😂

@LeeClayberg
Copy link

@glenn-jocher Can these changes be pushed to pub.dev?

@tinjet11
Copy link

tinjet11 commented Nov 19, 2024

Encounter the same issue, temporary solve it by changing the code in local, but hope there is a new releases in pubdev to fix it asap @pderrenger

@pderrenger
Copy link
Member

Thanks for your patience. Please keep an eye on the repository for any updates regarding new releases. If the issue persists in the latest version, feel free to report it again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
fixed Bug has been resolved
Projects
None yet
Development

Successfully merging a pull request may close this issue.