如何在 Flutter 的原生 C++ 中使用 OpenCV 4(2021 年)(支持 Flutter 2.0)?

fzy*_*cjy 8 c++ android opencv ios flutter

我需要编写一些使用OpenCV 的C++ 代码,而 Flutter 代码将调用这些 C++ 代码。

有关于使用 Flutter 编写 C++ 的教程,但我找不到任何关于使用 OpenCV 的最新且易于部署的解决方案。怎么做?

fzy*_*cjy 14

这是我的解决方案。

特征

  1. 适用于 Android 和 iOS。
  2. 使用静态链接而不是动态链接。(因此代码大小要小得多。)
  3. 最新版本为2021.6.8,使用 OpenCV 4.5.2,并在 Flutter 1.x 和 2.2 上进行测试。(由于这些 API 变化很快,而且很多文章都有些陈旧。)

入门

注意:如果您已经有一个应用程序,则可以跳过本节 :) 本节假定您根本没有代码。

示例代码可以从这里下载。

步骤0:确保你有Flutter环境,并遵循官方的“用Flutter编写C++”教程

注意必须遵循“在 iOS 上,您需要告诉 Xcode 静态链接文件:...”的步骤。否则,在我们的最后一步,iOS 会抱怨找不到符号。

注意:此外,您需要更改此处提到的 iOS的“条形样式” 。否则,您会在 iOS版本构建中看到问题,而在调试构建中一切正常。

第 1 步:使用 OpenCV 编写您喜欢的任何代码。例如,我更改ios/Classes/native_add.cpp为以下愚蠢的代码,它与官方教程中的几乎相同:

#include <stdint.h>
#include <opencv2/core.hpp>

extern "C" __attribute__((visibility("default"))) __attribute__((used))
int32_t native_add(int32_t x, int32_t y) {
    cv::Mat m = cv::Mat::zeros(x, y, CV_8UC3);
    return m.rows + m.cols;
}
Run Code Online (Sandbox Code Playgroud)

安卓

步骤0:从官网下载Android OpenCV sdk 。假设我把它放在我的桌面上。/Users/tom/Others/OpenCVRelease/OpenCV-android-sdk

步骤 1.1:将 更改为本要点android/CMakeLists.txt的内容。注意:首先将 更改为您的文件夹。OPENCV_BASE_DIR

当然,lib/native_with_opencv.dart应该将.so文件名更改为"libnative_with_opencv.so".

备注:如果您需要更多 OpenCV 功能(例如imread),请尝试使用此 gist

步骤 1.2:更改android/build.gradle如下:

android {
    ...
    defaultConfig {
        ...
        // [[[CHANGE 1: Make minSdkVersion bigger]]]
        // see https://github.com/opencv/opencv/issues/14419
        minSdkVersion 21

        // [[[CHANGE 2: Add these flags and filters]]]
        externalNativeBuild {
            cmake {
                cppFlags "-frtti -fexceptions -std=c++11"
                abiFilters 'armeabi-v7a', 'arm64-v8a'
            }
        }
        ...
    }
    ...
}

Run Code Online (Sandbox Code Playgroud)

当然,minSdkVersion您实际项目中的 ( native_with_opencv/example/android/app/build.gradle) 也应该更改为 21。

完毕!编译并享受它(并转到下一部分的 iOS)!如果你看到1 + 2 == 3,那么一切都很好。

奖励:如果您在发布模式下构建查看 apk 大小,您会看到我们的.so文件小于 1MB。因此静态链接和文件大小减小确实有效:)

IOS

第 0 步:在 中ios/native_with_opencv.podspec,添加:

  s.static_framework = true
  s.dependency 'OpenCV', '~> 4.5'
Run Code Online (Sandbox Code Playgroud)

第 1 步pod installnative_with_opencv/example/ios.

第 2 步编译并享受!

备注 0:必须按照tut中“在 iOS 上,您需要告诉 Xcode 静态链接文件:...”的步骤进行操作。否则,在我们的最后一步,iOS 会抱怨找不到符号。

备注 0b:可能需要检查(验证)XCode 中的以下设置(在将某些文件拖入 XCode 时似乎会自动包含但不确定)。否则,你最终IPA文件(可以通过产生这样)会包含你的.cpp 源文件,除了编解码,因此源代码被泄露。

设置:转到“Runner”目标的“构建阶段”。(1) 查看“复制捆绑资源”,并确认您的.cpp文件或文件夹存在。(2) 查看“编译源”,并验证您的.cpp文件那里。(您可能需要先在“编译源”中添加您的文件,然后再在“复制捆绑资源”中将其删除。)

备注 1:如果您正在使用其他.hpp头文件并看到奇怪的错误,例如 OpenCV 应该用 C++ 构建,或者在框架模块中包含非模块化头文件,那么可以试试这个:

创建xxx.modulemap包含以下内容的文件framework module the_name_of_your_module {}。然后更改您的 podspec 以使用此 modulemap s.module_map = 'xxx.modulemap'。然后pod install再次运行以刷新。然后编译运行,应该就OK了。

我对这个问题的猜测是,Cocoapod 生成一个“伞头”(比如 vision_utils-umbrella.h),并且你的头会自动包含在那里。因此,在编译该标头时,事情会被破坏。因此,我上面的方法试图删除这个伞头。

备注 2:当您添加或删除某些 c++ 文件时,您可能需要pod install再次运行(就像在步骤 1 中一样)。否则,您可能会看到诸如“找不到符号”之类的错误(因为 Xcode 不会查看您新添加的 C++ 文件)。

备注 3:如果您看到类似 的问题Failed to lookup symbol (dlsym(RTLD_DEFAULT, your_function): symbol not found),请查看链接。我似乎通过应用该评论中的建议来解决它(但不确定,因为也尝试过其他方法)。如果还没有解决请回复我。


(可选)Android 配置如何工作的说明: (1) 本来我只是链接core,但链接错误有数百个。然后我搜索并修复他们中的每一组。例如,error: undefined reference to 'carotene_o4t::...'意味着我需要与链接libtegra_hal,因此我添加了几行。(2) 奇怪的是,tbb应该放在之后 core,否则,它仍然无法链接。(3)abiFilters需要,因为tegra_hal不支持x86(因此不.a存在文件)。(4)minSdkVersion需要调高,否则fegetenv不会被发现。