NDK环境配置好的基础上移植DSST到安卓所需的改动并不多,主要还是编译的配置。
版权声明
原创文章,转载请说明出处:sheng-blog.cn
原文出处
博文结构:
顺利运行需要目标机器cpu架构是x86或x86_64的(直接使用SSE)或者arm64-v8a(原因上篇博文说过的)。自己的渣机还是armeabi-v7a的,跑不了,在室友清明去浪的前夜赶紧测试了一下他的手机和平板,正是我想要的!果断扣下平板留着后面测试啊哈哈!
啥?白天出去浪晚上回旅馆要拿平板看电影?
诶诶诶,一堆人晚上玩点别的多好,狼人杀啥的,还一个人看电影?
室友对曰:一堆人看电影最好~
我:……
我:要看你就还是拿手机看吧2333~
查看自己手机或平板的cpu架构方法:
adb shell
cat /proc/cpuinfo
如图为室友平板的信息,对于flag一栏,需有sse。
ARM架构的长这样(Features这一栏需有neon,当然这还不够,ARMv7还是32位机器,这个工程需要64位机器才能正常运行):
首先在/app/src/main下新建一个include文件夹用于保存c头文件,将DSST的那几个头文件拷贝进来,而cpp文件则和native-lib.cpp放一块,即/app/src/main/cpp。然后在CMakeLists里加入头文件路径,并把其余cpp文件也编译添加到native-lib中来:
include_directories(src/main/include)
add_library(
native-lib
SHARED
src/main/cpp/native-lib.cpp src/main/cpp/fdssttracker.cpp src/main/cpp/fhog.cpp)
如图:
然后同样的,如果目标机器是arm架构,sse.hpp里需做相应头文件的调整,编译,得到熟悉的报错:
error: "NEON support not enabled"
解决方案:在app下的build.gradle的externalNativeBuild{cmake{}}下加入如下代码(注意大括号的包含关系):
arguments "-DANDROID_ARM_NEON=TRUE", "-DANDROID_TOOLCHAIN=clang"
编译,搞定,移植工作就算完成了。java层实现一下CameraBridgeViewBase.CvCameraViewListener2这个接口。控制逻辑上,在用户框选了跟踪目标后,将目标框和此帧画面喂给native层对tracker进行初始化,随后的每一帧都喂给native层另一个函数对tracker进行更新并返回新的目标位置给java层更新。
平时调试C/C++程序一般习惯用printf来掌握程序走向,判断可能的逻辑错误,NDK下自然也有这个需求。找到一种方法可以像java层使用Log类在logcat里打印消息:
首先是编译配置,在app下的build.gradle的android{defaultConfig{ndk{}}}下加入ldLibs “log”(加完如下,注意大括号的包含关系):
ndk{
ldLibs "log"
abiFilters 'armeabi-v7a'
}
此外在CMakeLists中也要添加对log库的链接,如图:
在代码中使用如下:
#include"android/log.h"
//打印一个简单Info级别的日志 对应Java的Log.i("JNI","This is log")
__android_log_print(ANDROID_LOG_INFO,"JNI","This is log");
//打印格式化字符串 这里使用的是C语言中printf中的格式。关于C中的printf格式化输出可自行百度,文档非常多。
int i=5;
__android_log_print(ANDROID_LOG_INFO,"JNI","i=%d",i);
利用参考资料4提供的更优雅地使用方式是新建一个头文件,拷贝以下代码:
#include "android/log.h"
#ifndef LOG_TAG
#define LOG_TAG "JNI"
#endif
#ifndef IS_DEBUG
#define IS_DEBUG true
#endif
#define LOG_NOOP (void) 0
//__FILE__ 输出文件名
//__LINE__ 输出行数
//__PRETTY_FUNCTION__ 输出方法名
//可以按需选取 %s %u %s 分别与之对应
#define LOG_PRINT(level,fmt,...) __android_log_print(level,LOG_TAG,"(%s:%u) %s: " fmt,__FILE__,__LINE__,__PRETTY_FUNCTION__,##__VA_ARGS__)
//通过IS_DEBUG来控制是否输出日志
#if IS_DEBUG
#define LOGI(fmt,...) LOG_PRINT(ANDROID_LOG_INFO,fmt,##__VA_ARGS__)
#else
#define LOGI(...) LOG_NOOP
#endif
#if IS_DEBUG
#define LOGW(fmt,...) LOG_PRINT(ANDROID_LOG_WARN,fmt ,##__VA_ARGS__)
#else
#define LOGW(...) LOG_NOOP
#endif
#if IS_DEBUG
#define LOGD(fmt,...) LOG_PRINT(ANDROID_LOG_DEBUG,fmt ,##__VA_ARGS__)
#else
#define LOGD(...) LOG_NOOP
#endif
#if IS_DEBUG
#define LOGE(fmt,...) LOG_PRINT(ANDROID_LOG_ERROR,fmt ,##__VA_ARGS__)
#else
#define LOGE(...) LOG_NOOP
#endif
#if IS_DEBUG
#define LOGF(fmt,...) LOG_PRINT(ANDROID_LOG_FATAL,fmt ,##__VA_ARGS__)
#else
#define LOGF(...) LOG_NOOP
#endif
然后在需要使用的cpp文件中include即可
#include"LogUtils.h"
int func(int i)
{
LOGW("this is a warning");
LOGE("i = %d",i);
}
以下是用室友的荣耀8跟踪鹅厂公仔的效果录屏: