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



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

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

这是我的解决方案。

功能

  1. 适用于Android和iOS
  2. 使用静态链接而不是动态链接。(因此,代码大小要小得多。)
  3. 最新版本2022.08.08使用OpenCV 4.6.0,并在Flutter 1.x、2.x和3.0上进行了测试。(因为这些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;
}

Android

步骤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),请尝试使用此要点。

步骤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'
}
}
...
}
...
}

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

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

额外的好处:如果你在发布模式下构建并查看apk大小,你会发现我们的.so文件小于1MB。因此,静态链接和文件大小缩减确实有效:)

iOS

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

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

步骤1:在native_with_opencv/example/ios下运行pod install

第2步编译并享受吧

备注0:必须遵循";在iOS上,您需要告诉Xcode静态链接文件:"在芭蕾舞团。否则,在我们的最后一步,iOS将抱怨找不到符号。

备注0b:可能需要检查(验证)XCode中的以下设置(当将某些文件拖动到XCode中时,该设置似乎会自动包含,但不确定)。否则,您的最终IPA文件(可以由此生成)将包含您的.cpp源文件以及编译的代码,因此源代码被泄露。

设置:转到";构建阶段";";Runner";目标(1) 看看";复制捆绑资源";,并验证您的.cpp文件或文件夹是否而不是。(2) 看看";编译源";,并验证您的.cpp文件是否存在。(您可能需要先在"编译源"中添加文件,然后再在"复制捆绑资源"中删除它。)

备注1:如果您正在使用其他.hpp标头,并看到奇怪的错误,例如OpenCV应该使用C++构建,或者在框架模块中包含非模块化标头,则可以尝试以下操作:

创建包含以下framework module the_name_of_your_module {}xxx.modulemap文件。然后更改您的podspec以使用此模块映射s.module_map = 'xxx.modulemap'。然后再次运行pod install进行刷新。然后编译并运行,它应该是好的。

我对这个问题的猜测是,Cocoapod生成一个";伞头";(比如vision_utils-umbram.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) 由于tegra_hal不支持x86(因此不存在.a文件),因此需要abiFilters。(4)minSdkVersion需要升高,否则将找不到fegetenv

相关内容

最新更新