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

Posted

技术标签:

【中文标题】如何在 Flutter 的原生 C++ 中使用 OpenCV 4(2021 年)(支持 Flutter 2.0)? [关闭]【英文标题】:How to use OpenCV 4 in native C++ of Flutter (in 2022) (support Flutter 2.0)? [closed] 【发布时间】:2020-11-17 11:38:58 【问题描述】:

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

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

【问题讨论】:

【参考方案1】:

这是我的解决方案。

特点

    适用于 androidios。 使用静态链接而不是动态链接。 (因此代码大小要小得多。) 在 2021.12.26 更新,使用 OpenCV 4.5.5 并在 Flutter 1.x 和 2.8 上测试。 (因为这些 API 变化很快,而且很多文章都有点老了。)

开始

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

示例代码可以从here下载。

第 0 步:确保您拥有Flutter environment,并遵循official "writing C++ with Flutter" tutorial。

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

注意:另外,您需要更改“条形样式”,如 iOS 中提到的 here。否则,您将在 iOS release 构建中看到 problems,而在调试构建中一切正常。

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

#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;

安卓

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

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

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

备注:如果您需要更多OpenCV功能(如imread),请尝试使用this 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'
            
        
        ...
    
    ...


当然,你实际项目中的minSdkVersionnative_with_opencv/example/android/app/build.gradle)也应该改为21。

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

奖励:如果您使用build in release mode 和look at the apk size,您将看到我们的.so 文件小于1MB。因此静态链接和文件大小减少确实有效:)

iOS

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

  s.static_framework = true
  s.dependency 'OpenCV', '~> 4.5'

第一步:在native_with_opencv/example/ios下运行pod install

第 2 步编译并享受!

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

备注 0b: 可能需要检查(验证)XCode 中的以下设置(在将某些文件拖入 XCode 时似乎会自动包含但不确定)。否则,您的最终 IPA 文件(可以由 this 生成)除了已编译的代码之外,还将包含您的 .cpp 源文件,从而导致源代码泄露。

设置:转到“Runner”目标的“Build Phase”。 (1) 查看“复制捆绑资源”,并确认您的.cpp 文件或文件夹在那里。 (2) 查看“编译源”,并验证您的.cpp 文件那里。 (您可能需要先在“Compile Sources”中添加您的文件,然后在“Copy Bundle Resources”中删除它。)

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

创建包含以下framework module the_name_of_your_module xxx.modulemap 文件。然后 change 你的 podspec 使用这个模块映射 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) 之类的问题,请查看this 链接。我似乎通过应用该评论中的建议来解决它(但不确定,因为也尝试了其他方式)。如果还没有解决,请回复我。


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

【讨论】:

很棒的教程,谢谢!不过,我有一个问题:只要我坚持你的例子,使用cv::Mat m = cv::Mat::zeros(x, y, CV_8UC3),一切正常。但是,如果我想改用imread(),则会收到error: undefined reference to 'Imf_opencv:: .... 之类的错误。我已经将imgcodecsimgproc 添加到target_link_libraries @Schnodderbalken 我已经用我最新的 CMakeLists.txt 编辑了我的答案(请参阅“如果您需要更多 OpenCV 功能...”)。 只是一个注释,如果使用imgproc,你想在core之前放置MakeLists.txt for android。所以顺序是imgproc 然后core 然后tbb @ykonda 谢谢。我已经更新了要点:gist.github.com/fzyzcjy/621fb575e7ca57beed6a55576418efd8 @AlexisToby 我没有尝试过。它应该类似于您如何将任何 windows/linux/macos 库集成到颤振

以上是关于如何在 Flutter 的原生 C++ 中使用 OpenCV 4(2021 年)(支持 Flutter 2.0)? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

如何在flutter中嵌入原生android apis?

如何在 Flutter 应用程序中显示原生 Android 视图?

如何在 Flutter 中获取原生启动画面?

Flutter Web: 如何在页面中使用web原生组件及交互

Flutter Web: 如何在页面中使用web原生组件及交互

教你如何使用Flutter和原生App混合开发