问题描述
我需要编写一些使用 OpenCV 的C ++代码,Flutter代码将调用这些C ++代码./p>
关于使用Flutter编写C ++的教程找不到有关使用OpenCV的任何最新且易于部署的解决方案.该怎么做?
这是我的解决方案.
功能
- 适用于Android和iOS.
- 使用静态链接而不是动态链接.(因此,代码大小要小得多.)
- 使用OpenCV 4.5.1(第一个版本为2020.7.28)在 2021.3.7 上进行了最新更新,并在Flutter 1.x和2.0上进行了测试.(由于这些API的变化很快,而且许多文章都有些陈旧.)
入门
注意:如果您已经有一个应用程序,则可以跳过本节:)本节假定您根本没有任何代码.
可以从此处下载示例代码.
第0步:确保您具有 Flutter环境,并遵循官方使用Flutter编写C ++"教程.
注意:必须遵循 步骤,在iOS上,您需要告诉Xcode静态链接文件:...".否则,iOS会在最后一步抱怨找不到该符号.
注意:此外,您还需要更改条形样式"如此处所述.否则,您会在iOS 版本中看到问题构建,而在调试构建中,一切正常.
第1步:使用OpenCV编写所需的任何代码.例如,我将 ios/Classes/native_add.cpp
更改为以下愚蠢的代码,该代码与官方教程:
#include< stdint.h>#include< opencv2/core.hpp>外部"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);返回m.rows + m.cols;}
Android
第0步:下载官方网站下载"rel =" nofollow noreferrer> 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:增大minSdkVersion]]]//参见https://github.com/opencv/opencv/issues/14419minSdkVersion 21//[[[CHANGE 2:添加这些标志和过滤器]]]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 = trues.dependency'OpenCV','〜>4.5英尺
第1步:在 native_with_opencv/example/ios
下运行 pod install
.
第2步:编译并享受!
注释0 :必须遵循在iOS上,您需要告诉Xcode静态链接文件:..."的步骤.在 tut 中.否则,iOS会在最后一步抱怨找不到该符号.
注释0b:可能需要检查(验证)XCode中的以下设置(将某些文件拖到XCode中时似乎会自动包括在内,但不确定).否则,您的最终IPA文件(可以由此生成)将包含您的 .cpp
源文件除了已编译的代码外,因此源代码也被泄漏.
设置:转到构建阶段"赛跑者"的目标.(1)查看复制捆绑包资源",并确认您的 .cpp
文件或文件夹不在其中.(2)查看编译源",并验证其中的 .cpp
文件 .(您可能需要先在编译源"中添加文件,然后再在复制捆绑资源"中将其删除.)
注释1 :如果您使用其他 .hpp
标头,并且发现奇怪的错误,例如OpenCV应该使用C ++构建,或者包含非模块化标头在框架模块内部,则可以尝试以下方法:
创建包含以下 framework模块the_name_of_your_module {}
的 xxx.modulemap
文件.然后更改您的podspec以使用此模块映射 s.module_map ='xxx.modulemap"
.然后再次运行 pod install
刷新.然后编译并运行,应该没问题.
注释2 :添加或删除某些c ++文件时,可能必须再次运行 pod install
(就像在步骤1中一样).否则,您可能会看到诸如找不到符号"之类的错误消息.(因为Xcode不会查看您新添加的C ++文件).
注释3 :如果遇到诸如无法查找符号(dlsym(RTLD_DEFAULT,your_function):未找到符号)
之类的问题,请查看此链接.我似乎可以通过应用该评论中的建议来解决此问题(但不能确定,因为还尝试了其他方法).如果仍然无法解决,请回复我.
(可选)有关Android配置如何工作的说明:(1)最初,我只是链接 core
,但存在数百个链接错误.然后,我搜索并修复其中的每个组.例如, error:对'carotene_o4t :: ...'的未定义引用
表示我,因此需要添加几行.(2)奇怪的是,应该将 tbb
放在之后 core
之后,否则它仍然不会链接.(3)由于 tegra_hal
不支持 x86
(因此不存在 .a
文件),因此需要 abiFilters
..(4)需要提高 minSdkVersion
,否则将找不到 fegetenv
.
I need to write some C++ code which uses OpenCV, and the Flutter code will call those C++ code.
There are tutorials about writing C++ with Flutter, but I cannot find any up-to-date and easy-to-deploy solution about working with OpenCV. How to do that?
Here is my solution.
Features
- Works for both Android and iOS.
- Use static linking instead of dynamic linking. (Thus code size is much smaller.)
- Up-to-date at 2021.3.7 working with OpenCV 4.5.1 (first version at 2020.7.28) and tested on both Flutter 1.x and 2.0. (Since those APIs change rapidly and many articles are a little bit old.)
Getting Started
NOTE: If you already have an app, you can skip this section :) This section assumes that you have no code at all.
The sample code can be downloaded from here.
step 0: Ensure you have Flutter environment, and have followed the official "writing C++ with Flutter" tutorial.
NOTE: It is a must to follow the step of "On iOS, you need to tell Xcode to statically link the file: ...". Otherwise, at our last step iOS will complain the symbol cannot be found.
NOTE: Also, you need to change the "strip style" as mentioned here for iOS. Otherwise, you will see problems in iOS release build while in debug build everything works.
step 1: Write whatever code you like using OpenCV. For instance, I change ios/Classes/native_add.cpp
to the following silly code, which is almost identical as in the 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;
}
Android
Step 0: Download the Android OpenCV sdk from the official website. Say I put it in /Users/tom/Others/OpenCVRelease/OpenCV-android-sdk
in my desktop.
Step 1.1: Change the android/CMakeLists.txt
to the content of this gist. NOTE: First change the OPENCV_BASE_DIR
to your folder.
Of course, the lib/native_with_opencv.dart
should change the .so
file name to "libnative_with_opencv.so"
.
Remark: If you need more OpenCV features (such as imread
), have a try using this gist.
Step 1.2: Change the android/build.gradle
as following:
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'
}
}
...
}
...
}
Of course, the minSdkVersion
in your actual project (native_with_opencv/example/android/app/build.gradle
) should also change to 21.
Done! Compile and enjoy it (and go to the next section for iOS)! If you see 1 + 2 == 3
, then everything is fine.
Bonus: If you build in release mode and look at the apk size, you will see our .so
file is less than 1MB. Thus static linking and file size reduction does work :)
iOS
Step 0: In ios/native_with_opencv.podspec
, add:
s.static_framework = true
s.dependency 'OpenCV', '~> 4.5'
Step 1: Run pod install
under native_with_opencv/example/ios
.
Step 2: Compile and enjoy!
Remark 0: It is a must to follow the step of "On iOS, you need to tell Xcode to statically link the file: ..." in the tut. Otherwise, at our last step iOS will complain the symbol cannot be found.
Remark 0b: May need to check (verify) the following settings in XCode (which seems to be automatically included when dragging some files into XCode but not sure). Otherwise, your final IPA file (can be generated by this) will contain your .cpp
source file besides compiled code, thus the source code is leaked.
The setting: Go to "Build Phase" of the "Runner" Target. (1) Look at "Copy Bundle Resources", and verify that your .cpp
file or folders are not there. (2) Look at "Compile Sources", and verify your .cpp
files are there. (You may need to first add your file in "Compile Sources" before removing it in "Copy Bundle Resources".)
Remark 1: If you are using other .hpp
headers and see strange errors, such as OpenCV should be built with C++, or include of a non-modular header inside framework module, then may try this:
Create xxx.modulemap
file containing the following framework module the_name_of_your_module {}
. Then change your podspec to use this modulemap s.module_map = 'xxx.modulemap'
. Then run pod install
again to refresh. Then compile and run and it should be OK.
My guess about this problem is that, Cocoapod generates an "umbrella header" (say vision_utils-umbrella.h), and your header is automatically included there. Thus, when compiling that header, things get broken. Thus, my method above tries to remove this umbrella header.
Remark 2: When you add or remove some c++ files, you may have to run pod install
again (just like in step 1). Otherwise, you may see errors like "cannot find the symbol" (because Xcode does not look at your newly added C++ file).
Remark 3: If you see problems like Failed to lookup symbol (dlsym(RTLD_DEFAULT, your_function): symbol not found)
, have a look at this link. I seem to solve it by applying what is suggested in that comment (but not sure since also have tried other ways). If still not solved please reply to me.
(Optional) Explanations of how do the Android configuration work: (1) Originally, I just link the core
, but there are hundreds of linking errors. Then I search and fix for each group of them. For instance, error: undefined reference to 'carotene_o4t::...'
means I need to link with libtegra_hal
, thus I add several lines. (2) Strangely, the tbb
should be put after core
, otherwise, it still does not link. (3) The abiFilters
is needed, since tegra_hal
does not support x86
(thus no .a
file exists). (4) minSdkVersion
needs to be raised up, otherwise fegetenv
will not be found.
这篇关于如何在Flutter的本机C ++中使用OpenCV 4(在2021年)(支持Flutter 2.0)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!