Android JNI 使用 NCNN

Android JNI 使用 NCNN

前一篇文章介绍了怎么编译生成 ncnn 的动态库。

NCNN - 适用于移动端的高性能神经网络前向计算框架

这里就介绍一下怎么在 Android 中使用 ncnn 吧。

以 MTCNN 的人脸检测为例:

网上可以找到不少 MTCNN + NCNN 做人脸检测的例子(C++版本)。

MTCNN + NCNN (C++版) 人脸检测的核心代码可以参考:附录 I:MTCNN + NCNN 人脸检测核心代码(C++版本)

其中包含 mtcnn.cppmtcnn.h

JNI 使用 NCNN

看 MTCNN + NCNN 的代码,是 C++ 代码。

那么如果想要在 Android 中使用,显然需要编写 JNI 接口,调用 C++ 代码。

从上一篇文章:NCNN - 适用于移动端的高性能神经网络前向计算框架

我们知道最后执行完 make install 可以得到:

install/libs - NCNN 的静态库

install/include - NCNN 的相关头文件

这两个目录需要添加到 Android 工程中:

  • main
    • cpp
      • face_detect
        • armeabi-v7a
          • include
          • lib
        • arm64-v8a
          • include
          • lib
        • mtcnn.cpp
        • mtcnn.h
        • mtcnn_jni.cpp

注意不同架构的 NCNN 库路径有所不同。

接下来,上 CMakeLists.txt

cmake_minimum_required(VERSION 3.4.1)



# 编译后的 so 保存的位置
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI})

set(CMAKE_VERBOSE_MAKEFILE on)

set(PATH_LIB_NCNN      ${CMAKE_SOURCE_DIR}/src/main/cpp/face_detect/${ANDROID_ABI}/lib/libncnn.a)


# LOG
find_library( # Sets the name of the path variable.
        log-lib

        # Specifies the name of the NDK library that
        # you want CMake to locate.
        log )


# 链接库
link_libraries(
        ${log-lib}
        ${PATH_LIB_NCNN}
)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopenmp          ")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11                ")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -frtti                    ")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions              ")

set(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS}   -fopenmp                    ")

include_directories(
        ${CMAKE_SOURCE_DIR}/src/main/cpp/face_detect
        ${CMAKE_SOURCE_DIR}/src/main/cpp/face_detect/${ANDROID_ABI}/include
        )

file(GLOB
        MTCNN_SRC

        ${CMAKE_SOURCE_DIR}/src/main/cpp/face_detect/mtcnn.h
        ${CMAKE_SOURCE_DIR}/src/main/cpp/face_detect/mtcnn.cpp
        ${CMAKE_SOURCE_DIR}/src/main/cpp/face_detect/mtcnn_jni.cpp
        )

add_library(libncnn STATIC IMPORTED)
set_target_properties(libncnn
        PROPERTIES IMPORTED_LOCATION
        ${PATH_LIB_NCNN})

add_library(
            cvteresearch_facedetect
            SHARED
            ${MTCNN_SRC}
            )

因为 NCNN 需要用到 fopenmpopenmp。所以需要增加配置。

注意

如果遇到 STL 错误,请确保编译 libncnn.a 的 ndk 与 Android Studio 使用的 ndk 版本一致。

这个折腾了很久,因为 Android 的 ndk 是通过 Android Studio 的 SDK Tools 下载的。

与直接官网下载的 NDK 缺少一些文件(STL 相关,mips 相关等)。

修改为官网下载的 NDK 版本,就可以避免 STL 出错的问题了。

附录 I:MTCNN + NCNN 人脸检测核心代码(C++版本)

mtcnn.h

#pragma once

#ifndef __MTCNN_NCNN_H__
#define __MTCNN_NCNN_H__

#include "net.h"
#include <math.h>
#include <string>
#include <vector>
#include <time.h>
#include <algorithm>
#include <map>
#include <iostream>

using namespace std;
struct Bbox {
   
    float score;
    int x1;
    int y1;
    int x2;
    int y2;
    float area;
    float ppoint[10];
    float regreCoord[4];
};

class MTCNN {
   
public:
    MTCNN(const string &model_path);
    MTCNN(std::vector<std::string> param_files, std::vector<std::string> bin_files);
    ~MTCNN();

    void SetMinFace(int minSize);
    void detect(ncnn::Mat &img_, std::vector<Bbox> &finalBbox);

private:
    void generateBbox(ncnn::Mat score, ncnn::Mat location, vector<Bbox> &boundingBox_, float scale);
    void nms(vector<Bbox> &boundingBox_, const float overlap_threshold, string modelname = "Union");
    void refine(vector<Bbox> &vecBbox, const int &height, const int &width, bool square);
    void PNet();
    void RNet();
    void ONet();

    ncnn::Net Pnet, Rnet, Onet;
    ncnn::Mat img;
    const float nms_threshold[3] = {
   0.5f, 0.7f, 0.7f};
    const float mean_vals[3] = {
   127.5, 127.5, 127.5};
    const float norm_vals[3] = {
   0.0078125, 0.0078125, 0.0078125};
    const int MIN_DET_SIZE = 12;
    std::vector<Bbox> firstBbox, secondBbox, thirdBbox;
    int img_w, img_h;

private:
    const float threshold[3] = {
   0.8f, 0.8f, 0.6f};
    int minsize = 40;
    const float pre_facetor = 0.709f;

};
#endif //__MTCNN_NCNN_H__

mtcnn.cpp

#include "mtcnn.h"

bool cmpScore(Bbox lsh, Bbox rsh) {
   
    return lsh.score < rsh.score;
}

MTCNN::MTCNN(const string &model_path) {
   
    std::vector<std::string> param_files = {
   
            model_path + "/det1.param",
            model_path + "/det2.param",
            model_path + "/det3.param"
    };
    std::vector<std::string> bin_files = {
   
            model_path + "/det1.bin",
            model_path + "/det2.bin",
            model_path + "/det3.bin"
    };
    Pnet.load_param(param_files[0].data());
    Pnet.load_model
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值