Flutter图像处理插件opencv_dart的使用

发布于 1周前 作者 yuanlaile 来自 Flutter

Flutter图像处理插件opencv_dart的使用

opencv_dart简介

opencv_dart是用于Flutter的OpenCV库,它包含了所有的OpenCV模块。如果你不需要videoiohighgui模块,可以考虑使用opencv_core

注意事项

从版本v1.3.0开始,动态库将在本地构建,并在构建期间由Flutter调用。请注意:OpenCV SDK(约100M)将通过CMake的FetchContent下载,你可以设置DARTCV_CACHE_DIR环境变量来缓存它以避免重复下载。例如:export DARTCV_CACHE_DIR=$HOME/.cache/dartcv

  • Q&A: #212 或者打开新问题。
  • 如果你正在使用支持原生资源的Flutter特性,请考虑使用v2.x版本,详见native-assets分支,但此分支不会更新直到Native Assets稳定。

支持的平台

平台 是否支持 测试状态 架构
Android x86_64, arm64-v8a, armeabi-v7a
iOS arm64, x64(Simulator)
Linux x64, arm64
Windows x64, arm64
macOS x64, arm64

支持的模块

具体支持的模块列表请参阅这里

包大小

示例代码

下面是一个完整的示例demo,展示了如何使用opencv_dart进行图像处理:

// ignore_for_file: avoid_print

import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:opencv_dart/opencv.dart' as cv;

void main() {
  runApp(const MyApp());
}

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  List<Uint8List> images = [];

  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('OpenCV Dart Example'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            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}");
                    // 重计算任务
                    final (gray, blur) = await heavyTaskAsync(mat, count: 1);
                    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();
                  // 重计算任务
                  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()),
                      ),
                    ),
                  ],
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

说明

  • heavyTaskAsync:该函数执行了颜色转换和高斯模糊操作,并返回灰度图和模糊后的图像。
  • Pick Image按钮:允许用户从图库中选择图片,并对其进行颜色转换和高斯模糊处理,最后显示原始图像、灰度图像和模糊图像。
  • Process按钮:加载内置的lenna.png图像并对其进行相同的处理。

更多示例可以参考官方示例awesome-opencv_dart

许可证

opencv_dart遵循Apache-2.0 License

希望这些信息对你有帮助!如果你有任何问题或需要进一步的帮助,请随时提问。


更多关于Flutter图像处理插件opencv_dart的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter图像处理插件opencv_dart的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter中,使用opencv_dart插件进行图像处理是一个强大的方法,因为OpenCV是一个广泛使用的计算机视觉库。虽然opencv_dart主要是为Dart环境设计的,但你可以通过一些桥接技术在Flutter项目中使用它。下面是一个基本的示例,展示如何在Flutter中使用opencv_dart进行图像处理。

首先,你需要在你的pubspec.yaml文件中添加对opencv_dart的依赖。然而,需要注意的是,opencv_dart可能不是直接在Flutter插件库中可用的,因此你可能需要手动集成OpenCV的Dart绑定或者使用其他Flutter兼容的OpenCV封装。这里假设你已经有了相应的绑定或封装。

dependencies:
  flutter:
    sdk: flutter
  opencv_dart: ^版本号  # 请注意,这里的版本号需要替换为实际可用的版本号

由于opencv_dart可能不是官方支持的Flutter插件,接下来的步骤可能涉及一些原生代码集成或者使用现有的Flutter兼容库(如flutter_opencv,如果存在的话)。以下是一个假设性的示例,展示如何在Flutter中调用OpenCV的功能。

假设性示例:在Flutter中使用OpenCV进行灰度转换

  1. 确保OpenCV Dart绑定已正确集成

    这一步可能涉及下载OpenCV的Dart绑定库,并将其包含在你的Flutter项目中。由于这不是一个标准的Flutter插件,你可能需要手动处理一些原生代码和构建配置。

  2. 创建一个Dart文件来处理OpenCV操作

    import 'package:opencv_dart/opencv_dart.dart';
    
    class ImageProcessor {
      Mat convertToGrayscale(Uint8List imageBytes, int width, int height) {
        // 创建一个Mat对象从图像字节数据
        Mat src = Mat.fromBytes(width, height, Mat.CV_8UC4, imageBytes);
        // 转换到灰度图像
        Mat dst = Mat();
        cv.cvtColor(src, dst, cv.COLOR_BGR2GRAY);
        return dst;
      }
    }
    
  3. 在Flutter Widget中使用这个处理器

    import 'package:flutter/material.dart';
    import 'dart:typed_data';
    import 'image_processor.dart'; // 假设你的ImageProcessor类在这里
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(
              title: Text('OpenCV in Flutter'),
            ),
            body: Center(
              child: ImageFromOpenCV(),
            ),
          ),
        );
      }
    }
    
    class ImageFromOpenCV extends StatefulWidget {
      @override
      _ImageFromOpenCVState createState() => _ImageFromOpenCVState();
    }
    
    class _ImageFromOpenCVState extends State<ImageFromOpenCV> {
      Uint8List? grayscaleImageBytes;
    
      @override
      void initState() {
        super.initState();
        loadAndProcessImage();
      }
    
      void loadAndProcessImage() async {
        // 这里你应该加载你的图像数据,例如从资产文件夹或网络
        // 这里为了简化,我们假设已经有了一个图像字节数组
        Uint8List imageBytes = ...; // 你的图像字节数据
        int width = ...; // 图像宽度
        int height = ...; // 图像高度
    
        ImageProcessor processor = ImageProcessor();
        Mat grayscaleMat = processor.convertToGrayscale(imageBytes, width, height);
    
        // 将Mat对象转换回字节数据(这里需要一些额外的处理,因为Mat对象不是直接可序列化的)
        // 注意:这里的转换代码可能需要根据你使用的OpenCV Dart绑定的具体实现来调整
        Uint8ListBuffer buffer = Uint8ListBuffer();
        grayscaleMat.writeTo(buffer);
        grayscaleImageBytes = buffer.asUint8List();
    
        // 更新UI
        setState(() {});
      }
    
      @override
      Widget build(BuildContext context) {
        return grayscaleImageBytes != null
            ? Image.memory(grayscaleImageBytes!)
            : CircularProgressIndicator();
      }
    }
    

注意:上面的代码示例包含了一些假设和简化的部分,特别是关于如何加载图像数据和如何将Mat对象转换回字节数据的部分。在实际应用中,你可能需要使用更复杂的逻辑来处理这些任务,特别是如果你正在处理从相机或网络加载的图像。

此外,由于opencv_dart可能不是直接在Flutter生态系统中广泛使用的库,因此你可能需要查找或创建与Flutter兼容的OpenCV绑定。如果这样的绑定不存在,你可能需要考虑使用平台通道(Platform Channels)来在Flutter和原生代码之间通信,从而在原生侧使用OpenCV。

回到顶部