Flutter图像处理插件opencv_4的使用

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

Flutter图像处理插件opencv_4的使用

opencv_4 是一个用于Flutter应用的插件,它集成了OpenCV 4.3.0版本的功能,支持Android和iOS平台。本文将介绍如何安装和使用该插件,并提供一些示例代码。

目录

关于此版本

兼容性

  • 集成OpenCV 4.3.0版本
  • 支持Android和iOS平台
  • 可与流行的Flutter包如 image_picker 配合使用,以从图库或相机中获取图像进行处理

图像处理

  • 所有处理都通过图像字符串路径进行
  • 图像可以来自Flutter项目的assets文件夹、URL或者使用 image_picker 获取的相机和图库中的图片

安装

1. 依赖它

在你的 pubspec.yaml 文件中添加以下内容:

dependencies:
  opencv_4: ^1.0.0

2. 安装它

你可以通过命令行安装包:

$ flutter pub get

3. 导入它

现在你可以在Dart代码中导入并使用:

import 'package:opencv_4/opencv_4.dart';

如何使用

前提条件

  1. Android: 需要在项目中的 android/app/build.gradle 文件中设置最低版本为21:

    defaultConfig {
        ...
        minSdkVersion 21
        ...
    }
    
  2. 如果要处理来自assets文件夹的图像,不需要额外配置。

  3. 如果要处理来自URL的图像,也不需要额外配置。

  4. 如果要使用 image_picker 处理来自相机和图库的图像,请按照其文档进行权限配置。

  5. Nullsafety: 如果你要测试示例代码,请确保在 pubspec.yaml 中设置了以下环境变量:

    environment:
      sdk: ">=2.12.0 <3.0.0"
    

  • Cv2: 包含OpenCV模块实现的类
  • CVPathFrom: 允许配置要处理的图像路径
    • URL: 配置OpenCV用于Web图像
    • GALLERY_CAMERA: 配置OpenCV用于从 image_picker 包获取的图像
    • ASSETS: 配置OpenCV用于flutter项目中配置的assets图像

模块:图像过滤

Bilateral Filter (双边滤波)

必须在异步函数中调用:

Uint8List _byte = await Cv2.bilateralFilter(
  pathFrom: CVPathFrom.ASSETS,
  pathString: 'assets/Test.JPG',
  diameter: 20,
  sigmaColor: 75,
  sigmaSpace: 75,
  borderType: Cv2.BORDER_DEFAULT,
);

setState(() {
  _byte;
});

显示结果在一个Image widget中:

Image.memory(
  _byte!,
  width: 300,
  height: 300,
  fit: BoxFit.fill,
)

如果你要处理网络上的图像,只需将 pathFrom 设置为 CVPathFrom.URL 并替换 pathString 为URL即可。

Dilate (膨胀)

Uint8List _byte = await Cv2.dilate(
  pathFrom: CVPathFrom.ASSETS,
  pathString: 'assets/Test.JPG',
  kernelSize: [3, 3],
);

setState(() {
  _byte;
});

Filter2D (二维卷积)

Uint8List _byte = await Cv2.filter2D(
  pathFrom: CVPathFrom.URL,
  pathString: 'https://example.com/image.jpg',
  outputDepth: -1,
  kernelSize: [2, 2],
);

setState(() {
  _byte;
});

Median Blur (中值模糊)

Uint8List _byte = await Cv2.medianBlur(
  pathFrom: CVPathFrom.URL,
  pathString: 'https://example.com/image.jpg',
  kernelSize: 19,
);

setState(() {
  _byte;
});

MorphologyEx (形态学操作)

Uint8List _byte = await Cv2.morphologyEx(
  pathFrom: CVPathFrom.URL,
  pathString: 'https://example.com/image.jpg',
  operation: Cv2.MORPH_TOPHAT,
  kernelSize: [5, 5],
);

setState(() {
  _byte;
});

PyrMeanShiftFiltering (金字塔均值偏移滤波)

Uint8List _byte = await Cv2.pyrMeanShiftFiltering(
  pathFrom: CVPathFrom.ASSETS,
  pathString: 'assets/Test.JPG',
  spatialWindowRadius: 20,
  colorWindowRadius: 20,
);

setState(() {
  _byte;
});

Scharr (Scharr算子)

Uint8List _byte = await Cv2.scharr(
  pathFrom: CVPathFrom.ASSETS,
  pathString: 'assets/Test.JPG',
  depth: Cv2.CV_SCHARR,
  dx: 0,
  dy: 1,
);

setState(() {
  _byte;
});

示例Demo

下面是一个完整的Flutter应用程序示例,展示了如何使用 opencv_4 插件来处理图像:

import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:opencv_4/factory/pathfrom.dart';
import 'package:opencv_4/opencv_4.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'OpenCV Example'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, this.title}) : super(key: key);

  final String? title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  Uint8List? _byte;
  bool _visible = false;
  final picker = ImagePicker();

  Future<void> _getOpenCVVersion() async {
    String? versionOpenCV = await Cv2.version();
    setState(() {
      print('OpenCV Version: $versionOpenCV');
    });
  }

  void testThreshold({
    required String pathString,
    required CVPathFrom pathFrom,
    required double thresholdValue,
    required double maxThresholdValue,
    required int thresholdType,
  }) async {
    try {
      _byte = await Cv2.threshold(
        pathFrom: pathFrom,
        pathString: pathString,
        maxThresholdValue: maxThresholdValue,
        thresholdType: thresholdType,
        thresholdValue: thresholdValue,
      );

      setState(() {
        _byte;
        _visible = false;
      });
    } on PlatformException catch (e) {
      print(e.message);
    }
  }

  void _testFromAssets() async {
    testThreshold(
      pathFrom: CVPathFrom.ASSETS,
      pathString: 'assets/Test.JPG',
      thresholdValue: 150,
      maxThresholdValue: 200,
      thresholdType: Cv2.THRESH_BINARY,
    );
    setState(() {
      _visible = true;
    });
  }

  void _testFromUrl() async {
    testThreshold(
      pathFrom: CVPathFrom.URL,
      pathString: 'https://example.com/image.jpg',
      thresholdValue: 150,
      maxThresholdValue: 200,
      thresholdType: Cv2.THRESH_BINARY,
    );
    setState(() {
      _visible = true;
    });
  }

  void _testFromCamera() async {
    final pickedFile = await picker.getImage(source: ImageSource.camera);
    if (pickedFile != null) {
      testThreshold(
        pathFrom: CVPathFrom.GALLERY_CAMERA,
        pathString: pickedFile.path,
        thresholdValue: 150,
        maxThresholdValue: 200,
        thresholdType: Cv2.THRESH_BINARY,
      );
      setState(() {
        _visible = true;
      });
    }
  }

  void _testFromGallery() async {
    final pickedFile = await picker.getImage(source: ImageSource.gallery);
    if (pickedFile != null) {
      testThreshold(
        pathFrom: CVPathFrom.GALLERY_CAMERA,
        pathString: pickedFile.path,
        thresholdValue: 150,
        maxThresholdValue: 200,
        thresholdType: Cv2.THRESH_BINARY,
      );
      setState(() {
        _visible = true;
      });
    }
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title!),
      ),
      body: SingleChildScrollView(
        child: Container(
          child: Column(
            children: [
              Container(
                margin: EdgeInsets.only(top: 20),
                child: Center(
                  child: Column(
                    children: <Widget>[
                      Text(
                        'OpenCV Example',
                        style: TextStyle(fontSize: 23),
                      ),
                      Container(
                        margin: EdgeInsets.only(top: 5),
                        child: _byte != null
                            ? Image.memory(
                                _byte!,
                                width: 300,
                                height: 300,
                                fit: BoxFit.fill,
                              )
                            : Container(
                                width: 300,
                                height: 300,
                                child: Icon(
                                  Icons.camera_alt,
                                  color: Colors.grey[800],
                                ),
                              ),
                      ),
                      Visibility(
                        maintainAnimation: true,
                        maintainState: true,
                        visible: _visible,
                        child: Container(child: CircularProgressIndicator()),
                      ),
                      SizedBox(
                        width: MediaQuery.of(context).size.width - 40,
                        child: TextButton(
                          child: Text('Test Assets'),
                          onPressed: _testFromAssets,
                          style: TextButton.styleFrom(
                            primary: Colors.white,
                            backgroundColor: Colors.teal,
                            onSurface: Colors.grey,
                          ),
                        ),
                      ),
                      SizedBox(
                        width: MediaQuery.of(context).size.width - 40,
                        child: TextButton(
                          child: Text('Test URL'),
                          onPressed: _testFromUrl,
                          style: TextButton.styleFrom(
                            primary: Colors.white,
                            backgroundColor: Colors.teal,
                            onSurface: Colors.grey,
                          ),
                        ),
                      ),
                      SizedBox(
                        width: MediaQuery.of(context).size.width - 40,
                        child: TextButton(
                          child: Text('Test Gallery'),
                          onPressed: _testFromGallery,
                          style: TextButton.styleFrom(
                            primary: Colors.white,
                            backgroundColor: Colors.teal,
                            onSurface: Colors.grey,
                          ),
                        ),
                      ),
                      SizedBox(
                        width: MediaQuery.of(context).size.width - 40,
                        child: TextButton(
                          child: Text('Test Camera'),
                          onPressed: _testFromCamera,
                          style: TextButton.styleFrom(
                            primary: Colors.white,
                            backgroundColor: Colors.teal,
                            onSurface: Colors.grey,
                          ),
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

以上就是使用 opencv_4 插件的基本步骤和示例代码。希望对你有所帮助!


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

1 回复

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


当然,下面是一个关于如何在Flutter项目中使用opencv_4插件进行基本图像处理的示例代码。请注意,opencv_4插件可能并不是官方或广泛认可的插件名称,因此这里假设你指的是一个允许Flutter使用OpenCV 4.x功能的插件。在Flutter社区中,通常通过调用原生代码(如C++或Java/Kotlin)来实现OpenCV的功能。

由于Flutter本身不直接支持C++库,我们通常需要通过平台通道(Platform Channels)与原生代码进行交互。以下示例将展示如何在Flutter中设置一个基本的平台通道,并在原生代码中调用OpenCV的功能。

1. 设置Flutter项目

首先,创建一个新的Flutter项目(如果还没有的话):

flutter create flutter_opencv_example
cd flutter_opencv_example

2. 添加平台通道

lib目录下创建或修改main.dart文件,添加一个平台通道来与原生代码通信:

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

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

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  static const platform = const MethodChannel('com.example.flutter_opencv_example/opencv');

  Future<void> _processImage(File imageFile) async {
    try {
      final result = await platform.invokeMethod('processImage', imageFile.path);
      print('Processed image result: $result');
    } on PlatformException catch (e) {
      print("Failed to process image: '${e.message}'.");
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter OpenCV Example'),
        ),
        body: Center(
          child: ElevatedButton(
            onPressed: () async {
              // Here you would typically pick an image from the gallery or take a photo with the camera
              // For simplicity, we assume you already have a File object called `imageFile`
              // File imageFile = ...;
              // _processImage(imageFile);
            },
            child: Text('Process Image'),
          ),
        ),
      ),
    );
  }
}

3. 在Android端实现OpenCV功能

android/app/src/main/java/com/example/flutter_opencv_example/目录下创建或修改MainActivity.kt(如果是Kotlin项目)或MainActivity.java(如果是Java项目),并添加平台通道的实现。这里以Kotlin为例:

package com.example.flutter_opencv_example

import android.content.Intent
import android.graphics.Bitmap
import android.net.Uri
import androidx.annotation.NonNull
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import org.opencv.android.OpenCVLoader
import org.opencv.android.Utils
import org.opencv.core.Mat
import org.opencv.imgproc.Imgproc

class MainActivity: FlutterActivity() {
    private val CHANNEL = "com.example.flutter_opencv_example/opencv"

    override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
            if (call.method == "processImage") {
                val imagePath = call.argument<String>("imagePath") ?: return@setMethodCallHandler result.error("INVALID_ARGUMENT", "imagePath is missing", null)
                processImage(imagePath, result)
            } else {
                result.notImplemented()
            }
        }
    }

    private fun processImage(imagePath: String, result: MethodChannel.Result) {
        if (!OpenCVLoader.initDebug()) {
            result.error("OPENCV_LOAD_FAILED", "OpenCV library loading failed", null)
            return
        }

        val bitmap = // Load bitmap from imagePath (you can use standard Android code for this)

        val mat = Mat()
        Utils.bitmapToMat(bitmap, mat)
        Imgproc.cvtColor(mat, mat, Imgproc.COLOR_BGR2GRAY) // Example: convert to grayscale

        val processedBitmap = Bitmap.createBitmap(mat.cols(), mat.rows(), Bitmap.Config.ARGB_8888)
        Utils.matToBitmap(mat, processedBitmap)

        // Save or return the processed bitmap as needed
        // For simplicity, we'll just return a success message here
        result.success("Image processed successfully")
    }
}

注意:上面的代码中省略了从文件路径加载Bitmap的部分,因为这部分代码依赖于Android的标准图像处理库,并且相对简单。你可以使用BitmapFactory.decodeFile(imagePath)来加载图像。

4. 在iOS端实现OpenCV功能(可选)

由于iOS平台的复杂性,这里不详细展开。但基本思路是类似的:你需要创建一个SwiftObjective-C的桥接文件,使用OpenCV的iOS库来处理图像,并通过Flutter的MethodChannel与Dart代码通信。

5. 添加OpenCV依赖

确保在Android和iOS项目中正确配置了OpenCV库。对于Android,你可能需要将OpenCV的SDK添加到项目中,并在build.gradle文件中进行配置。对于iOS,你需要将OpenCV的framework添加到Xcode项目中。

6. 运行应用

现在,你应该能够在Flutter应用中调用OpenCV的功能来处理图像了。请注意,这只是一个基本示例,实际应用中可能需要进行更多的错误处理和优化。

由于篇幅限制和平台差异,这里提供的代码可能需要根据实际情况进行调整和完善。希望这个示例能帮助你入门在Flutter中使用OpenCV进行图像处理。

回到顶部