rainyl / opencv_dart

OpenCV bindings for Dart language and Flutter. Support Asynchronous Now!
https://pub.dev/packages/opencv_dart
Apache License 2.0
133 stars 18 forks source link

cv.imdecode giveing null data , #258

Closed KartikGavhale closed 1 month ago

KartikGavhale commented 1 month ago

Describe the bug im trying to pick image from mobile galary , i used imdecodeasync to decode a 16MP resolution image , when i checked the returmed mat.data , its giveing me null

To Reproduce 1.using image picker to pick image from galary .

  1. select a image of 16MP resolution
  2. convert it to mat
rainyl commented 1 month ago

@KartikGavhale Thanks for your report.

Could you please attach an example image so I can test it?

KartikGavhale commented 1 month ago

Hi @rainyl , i tried using two following code

  final data = File(imagepath).readAsBytesSync();
Uint8List  bytes = data.buffer.asUint8List();
colorimg = cv.imdecode(bytes,cv.IMREAD_ANYCOLOR);

and colorimg=cv.imread(imagepath);

both returned the empty data in mat without error I have to for the image picker to get 50% image quality then only its giveing me the data.

attaching referance image which i used 20240928_172002 (1)

rainyl commented 1 month ago

@KartikGavhale Thanks for your response, but I cant reproduce it with the following steps:

```dart // ignore_for_file: avoid_print import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:opencv_dart/opencv_dart.dart' as cv; import 'package:image_picker/image_picker.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatefulWidget { const MyApp({super.key}); @override State createState() => _MyAppState(); } class _MyAppState extends State { var images = []; @override void initState() { super.initState(); } @override void dispose() { super.dispose(); } Future<(cv.Mat, cv.Mat)> heavyTaskAsync(cv.Mat im, {int count=1000}) async { late cv.Mat gray, blur; for (var i = 0; i < count; i++) { gray = await cv.cvtColorAsync(im, cv.COLOR_BGR2GRAY); blur = await cv.gaussianBlurAsync(im, (7, 7), 2, sigmaY: 2); } return (gray, blur); } @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar( title: const Text('Native Packages'), ), body: Container( alignment: Alignment.center, child: Column( children: [ ElevatedButton( onPressed: () async { final picker = ImagePicker(); final img = await picker.pickImage(source: ImageSource.gallery); if (img != null) { final path = img.path; final mat = cv.imread(path); print("cv.imread: width: ${mat.cols}, height: ${mat.rows}, path: $path"); debugPrint("mat.data.length: ${mat.data.length}"); // heavy computation final (gray, blur) = await heavyTaskAsync(mat, count: 100); setState(() { images = [ cv.imencode(".png", mat).$2, cv.imencode(".png", gray).$2, cv.imencode(".png", blur).$2, ]; }); } }, child: const Text("Pick Image"), ), ElevatedButton( onPressed: () async { final data = await DefaultAssetBundle.of(context).load("images/lenna.png"); final bytes = data.buffer.asUint8List(); // heavy computation // final (gray, blur) = await heavyTask(bytes); // setState(() { // images = [bytes, gray, blur]; // }); final (gray, blur) = await heavyTaskAsync(cv.imdecode(bytes, cv.IMREAD_COLOR)); setState(() { images = [bytes, cv.imencode(".png", gray).$2, cv.imencode(".png", blur).$2]; }); }, child: const Text("Process"), ), Expanded( flex: 2, child: Row( children: [ Expanded( child: ListView.builder( itemCount: images.length, itemBuilder: (ctx, idx) => Card( child: Image.memory(images[idx]), ), ), ), Expanded( child: SingleChildScrollView( child: Text(cv.getBuildInformation()), ), ), ], ), ), ], ), ), ), ); } } ```

I also tested it on android and it worked fine.

image

image

KartikGavhale commented 1 month ago

@rainyl can you confirm if you had picked image from gallery? Please test this with some good quality picture captured by camera and choose it from gallery. I tried multiple time .

rainyl commented 1 month ago

@KartikGavhale Yes, it works in my test, even with large images (3472*4624)

However, in these cases, large images may not be freed timely due to the inherent problem of dart:ffi, so you must manage the memories carefully, or the app may reach the maximum memory limitation and be killed by OS (you can inspect this via DevTools).

Related issues about dart objects and native objects:

e.g., in the above example, change the function heavyTaskAsync to:

Future<(cv.Mat, cv.Mat)> heavyTaskAsync(cv.Mat im, {int count = 1000}) async {
    late cv.Mat gray, blur;
    for (var i = 0; i < count; i++) {
      gray = await cv.cvtColorAsync(im, cv.COLOR_BGR2GRAY);
      blur = await cv.gaussianBlurAsync(im, (7, 7), 2, sigmaY: 2);
      if (i != count - 1) {
        gray.dispose(); // manually dispose
        blur.dispose(); // manually dispose
      }
    }
    return (gray, blur);
  }

image

opencv_dart_issue258

Full code ```dart // ignore_for_file: avoid_print import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:opencv_dart/opencv_dart.dart' as cv; import 'package:image_picker/image_picker.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatefulWidget { const MyApp({super.key}); @override State createState() => _MyAppState(); } class _MyAppState extends State { var images = []; @override void initState() { super.initState(); } @override void dispose() { super.dispose(); } Future<(cv.Mat, cv.Mat)> heavyTaskAsync(cv.Mat im, {int count = 1000}) async { late cv.Mat gray, blur; for (var i = 0; i < count; i++) { gray = await cv.cvtColorAsync(im, cv.COLOR_BGR2GRAY); blur = await cv.gaussianBlurAsync(im, (7, 7), 2, sigmaY: 2); if (i != count - 1) { gray.dispose(); blur.dispose(); } } return (gray, blur); } @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar( title: const Text('Native Packages'), ), body: Container( alignment: Alignment.center, child: Column( children: [ ElevatedButton( onPressed: () async { final picker = ImagePicker(); final img = await picker.pickImage(source: ImageSource.gallery); if (img != null) { final path = img.path; final mat = cv.imread(path); print("cv.imread: width: ${mat.cols}, height: ${mat.rows}, path: $path"); debugPrint("mat.data.length: ${mat.data.length}"); // heavy computation final (gray, blur) = await heavyTaskAsync(mat, count: 100); // final gray = await cv.cvtColorAsync(mat, cv.COLOR_BGR2GRAY); setState(() { images = [ cv.imencode(".png", mat).$2, cv.imencode(".png", gray).$2, cv.imencode(".png", blur).$2, ]; }); } }, child: const Text("Pick Image"), ), Expanded( flex: 2, child: Row( children: [ Expanded( child: ListView.builder( itemCount: images.length, itemBuilder: (ctx, idx) => Card( child: Image.memory(images[idx]), ), ), ), Expanded( child: SingleChildScrollView( child: Text(cv.getBuildInformation()), ), ), ], ), ), ], ), ), ), ); } } ```
KartikGavhale commented 1 month ago

@rainyl , ok will try to get if i found any certain error. Thanks for the continues support buddy.