Ncnn使用详解(2)——Android端 - DmrfCoder的博客 - CSDN博客

标签: | 发表时间:2019-02-17 17:43 | 作者:
出处:https://blog.csdn.net

摘要

本片文章基于你已经完成了 这篇文章的学习,主要介绍如何将写好的c代码应用到Android项目中。

环境说明

系统:Ubuntu16.04 
软件:Android Studio

前期准备之 ndk安装

在正式开始前我们需要先下载安装ndk,这里介绍一种简单高效的方式,打开Android Studio,然后依次点击File->Settings->Appearance&Behavior->System Settings->Android SDK,然后在SDK Tools下找到ndk,然后选中,点击apply就可以自动下载安装了,如图: 
这里写图片描述
完成之后在你的sdk目录下会多出一个ndk-bundle的包,这就是你ndk的路径,类似下图: 
这里写图片描述
至此,ndk已经安装完毕了,下一步是配置ndk的环境变量: 
首先打开profile:

  sudo vim /etc/profile  
  • 1

打开后在profile文件的末尾加上:

  export NDK_HOME=sdkroot/ndk-bundle
PATH=$NDK_HOME:$PATH  
  • 1
  • 2

sdkroot是你的sdk目录,每个人的不一样,视情况而定,下面是我的配置 截图: 
这里写图片描述
添加完成后保存退出,使用以下命令使配置的环境变量生效:

  source /etc/profile  
  • 1

验证ndk是否配置成功:

  ndk-build -v  
  • 1

出现类似以下输出即说明ndk配置成功: 
这里写图片描述

编译ncnn sdk

我们需要将ncnn打包,这样我们才能在android ndk的代码中使用include

  mkdir build-android
cd build-android
cmake -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \
    -DANDROID_ABI="armeabi-v7a" -DANDROID_ARM_NEON=ON \
    -DANDROID_PLATFORM=android-14 ..
make
make install  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

参数说明:

  ANDROID_ABI 是架构名字,"armeabi-v7a" 支持绝大部分手机硬件

ANDROID_ARM_NEON 是否使用 NEON 指令集,设为 ON 支持绝大部分手机硬件

ANDROID_PLATFORM 指定最低系统版本,"android-14" 就是 android-4.0  
  • 1
  • 2
  • 3
  • 4
  • 5

你可以根据自己的需要设置自己的参数,详见 这里 
完成后你就可以在ncnn/build-android下找到install了,大概如图: 
这里写图片描述
install下有include和lib两个文件夹,这两个文件夹下的东西后面会用到。

进行ndk开发

Android可以通过ndk-build和cmake两种方式来编译c,而且官方比较推荐的是cmake的方式,但是我用cmake试了好长时间一直报各种诡异的错误,应该是我还没有学到ncnn in ndk with cmake的正确打开方式,所以这里介绍一下使用ndk-build这种方式编译c,步骤如下: 
我这里新建了一个android 的demo项目,项目结构如下: 
这里写图片描述 
主要是assets文件夹下放置你的bin和param文件,jni文件夹下放置你的cpp和两个mk文件,具体内容下面会介绍(可以直接在对应位置新建这两个文件夹),然后要修改你的app gradle文件: 
这里写图片描述
对应的内容你可以根据自己的情况修改,然后配置两个mk文件: 
* Android.mk

  LOCAL_PATH := $(call my-dir)

#把这个路径改成你自己刚才编译的install路径,用全路径!
NCNN_INSTALL_PATH := ncnn-master/build-android/install

include $(CLEAR_VARS)
LOCAL_MODULE := ncnn
LOCAL_SRC_FILES := $(NCNN_INSTALL_PATH)/lib/libncnn.a
include $(PREBUILT_STATIC_LIBRARY)

include $(CLEAR_VARS)

LOCAL_MODULE := demo
#这个是你的cpp文件
LOCAL_SRC_FILES := demo.cpp

LOCAL_C_INCLUDES := $(NCNN_INSTALL_PATH)/include

LOCAL_STATIC_LIBRARIES := ncnn

LOCAL_CFLAGS := -O2 -fvisibility=hidden -fomit-frame-pointer -fstrict-aliasing -ffunction-sections -fdata-sections -ffast-math
LOCAL_CPPFLAGS := -O2 -fvisibility=hidden -fvisibility-inlines-hidden -fomit-frame-pointer -fstrict-aliasing -ffunction-sections -fdata-sections -ffast-math
LOCAL_LDFLAGS += -Wl,--gc-sections

LOCAL_CFLAGS += -fopenmp
LOCAL_CPPFLAGS += -fopenmp
LOCAL_LDFLAGS += -fopenmp

LOCAL_LDLIBS := -lz -llog -ljnigraphics

include $(BUILD_SHARED_LIBRARY)
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • Application.mk
  
# APP_STL := stlport_static
APP_STL := gnustl_static
# APP_ABI := armeabi armeabi-v7a
APP_ABI := armeabi-v7a
APP_PLATFORM := android-9
#NDK_TOOLCHAIN_VERSION := 4.9
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

这两个.mk文件我的建议是复制粘贴到你的项目里,只改动必要的文件路径,其余的参数别动,除非你直到你改的意思是什么~ 
因为ndk的原理是使用 java接口调用c代码,所以我们需要进行java接口的编写,给出一个示例代码:

  public class Ncnn
{
    public native boolean InitNcnn(String gestureDetectionModelPath);


    public native  void Detect(float[] i,float[] q,float []scores,int[] a);


    static {
        System.loadLibrary("demo");
    }



}
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

一共两个方法,一个是初始化,一个是执行预测,需要注意的是初始化方法调用的时候需要传入一个二进制文件路径的参数,大概思路是把bin和param文件拷贝到手机上然后让c代码读取,这里给出模板代码:

   private void IniteNcnn() throws IOException {


        ncnn = new Ncnn();//实例化上面的java接口类


        try {
            copyBigDataToSD("demo.bin");

            copyBigDataToSD("demo.param");
        } catch (IOException e) {
            e.printStackTrace();
        }
        //模型初始化
        File sdDir = Environment.getExternalStorageDirectory();//获取跟目录
        String sdPath = sdDir.toString() + "/gesturencnn/";
        boolean b = ncnn.InitNcnn(sdPath);


    }


    private void copyBigDataToSD(String strOutFileName) throws IOException {

        File sdDir = Environment.getExternalStorageDirectory();
        File file = new File(sdDir.toString() + "/demo/");
        if (!file.exists()) {
            file.mkdir();
        }

        String tmpFile = sdDir.toString() + "/demo/" + strOutFileName;
        File f = new File(tmpFile);
        if (f.exists()) {
            return;
        }
        InputStream myInput;
        java.io.OutputStream myOutput = new FileOutputStream(sdDir.toString() + "/demo/" + strOutFileName);
        myInput = context.getAssets().open(strOutFileName);
        byte[] buffer = new byte[1024];
        int length = myInput.read(buffer);
        while (length > 0) {
            myOutput.write(buffer, 0, length);
            length = myInput.read(buffer);
        }
        myOutput.flush();
        myInput.close();
        myOutput.close();

    }

  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

直接在你需要的地方调用IniteNcnn()就可以了,需要注意的是要 进行内存卡读取权限的申请

然后将你上一篇教程写的demo.cpp放在jni目录下,对里面的代码进行必要的修改,主要需要实现模型的初始化和执行预测两个函数,初始化这里给出一个模板,至于执行预测的函数直接写一个对应函数然后调用你之前写好的c代码就可以了:

  • 初始化 
    这个函数是通用的,建议全部复制粘贴,具体对应的java接口代码后面会介绍
  
extern "C"{

#注意把这里的函数名改成你自己对应的,一定不能错!
JNIEXPORT jboolean JNICALL
Java_com_example_dmrf_JniClass_Ncnn_InitNcnn(JNIEnv *env, jobject instance,
                                                                    jstring DetectionModelPath_) {


    const char *DetectionModelPath = env->GetStringUTFChars(DetectionModelPath_, 0);
    if (NULL == DetectionModelPath) {
        return false;
    }

    string tModelDir = DetectionModelPath;
    string tLastChar = tModelDir.substr(tModelDir.length() - 1, 1);


    if ("\\" == tLastChar) {
        tModelDir = tModelDir.substr(0, tModelDir.length() - 1) + "/";
    } else if (tLastChar != "/") {
        tModelDir += "/";
    }


    std::vector<std::string> param_files;
    param_files.resize(1);
    param_files[0] = tModelDir + "/demo.param";

    std::vector<std::string> bin_files;
    bin_files.resize(1);
    bin_files[0] = tModelDir + "/demo.bin";


    squeezenet.load_param(param_files[0].data());
    squeezenet.load_model(bin_files[0].data());

    env->ReleaseStringUTFChars(DetectionModelPath_, DetectionModelPath);

    return true;
}


  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

至此所有代码已经编写完毕,然后就可以build了,步骤如下: 
cd到src/main/jni目录下,执行ndk-build,然后就会生成.so文件,然后你就可以干你的后序工作了。

相关 [ncnn android dmrfcoder] 推荐:

Ncnn使用详解(2)——Android端 - DmrfCoder的博客 - CSDN博客

- -
本片文章基于你已经完成了 这篇文章的学习,主要介绍如何将写好的c代码应用到Android项目中. 系统:Ubuntu16.04 . 软件:Android Studio. 前期准备之 ndk安装. 在正式开始前我们需要先下载安装ndk,这里介绍一种简单高效的方式,打开Android Studio,然后依次点击File->Settings->Appearance&Behavior->System Settings->Android SDK,然后在SDK Tools下找到ndk,然后选中,点击apply就可以自动下载安装了,如图: .

Windows下编译ncnn的android端的库 - 迷若烟雨的专栏 - CSDN博客

- -
ncnn是腾讯开源的一个为手机端极致优化的高性能神经网络前向计算框架,目前已在腾讯多款应用中使用. 由于开发者使用的是linux类似的环境,因此只提供了build.sh用来构建android和iOS的库,但好在提供了CMakelist.txt文件,我们可以借助CMake进行跨平台的交叉编译. 将以下代码存为build.bat文件,双击执行即可.

在Android手机上使用腾讯的ncnn实现图像分类 - 夜雨飘零 - CSDN博客

- -
在之前笔者有介绍过《在Android设备上使用PaddleMobile实现图像分类》,使用的框架是百度开源的PaddleMobile. 在本章中,笔者将会介绍使用腾讯的开源手机深度学习框架ncnn来实现在Android手机实现图像分类,这个框架开源时间比较长,相对稳定很多. ncnn的GitHub地址:https://github.com/Tencent/ncnn.

GitHub - Tencent/ncnn: ncnn is a high-performance neural network inference framework optimized for the mobile platform

- -
ncnn 是一个为手机端极致优化的高性能神经网络前向计算框架. ncnn 从设计之初深刻考虑手机端的部署和使用. 无第三方依赖,跨平台,手机端 cpu 的速度快于目前所有已知的开源框架. 基于 ncnn,开发者能够将深度学习算法轻松移植到手机端高效执行,开发出人工智能 APP,将 AI 带到你的指尖.

MobileNetSSD通过Ncnn前向推理框架在Android端的使用--Cmake编译(目标检测 objection detection)补充篇章(多目标也可以显示) - Che_Hongshu - CSDN博客

- -
安装win10+linux-Ubuntu16.04的双系统(超细致). ubuntu16.04+caffe+CUDA10.0+cudnn7.4+opencv2.4.9.1+python2.7 (超超细致). Caffe_ssd安装以及利用VOC2012,VOC2007数据集测试VGG_SSD网络. Caffe实现MobileNetSSD以及各个文件的具体解释,利用自己的数据集dataset训练MobileNetSSD建立模型.

树莓派NCNN环境搭建 | 异构 AI

- -
前言镜像已经做好了,传到百度网盘中了(请大家及时保存,不定期删除. https://pan.baidu.com/s/1fhiX86L8iL8tsLbsiVa6Wg密码: e64s. SD卡要求:至少16GB,板卡型号为树莓派3B+(其他型号未知). 本系列教程采用树莓派3B+开发板:. 1.4GHz 64位4核 ARM Cortex-A53 CPU.

基于insightface训练mobilefacenet的相关步骤及ncnn转换流程

- -
经多位网友的共同实验,原方案部分情况下迭代次数稍微不足,导致最终识别率略有小差异,为了相对容易获得论文的最佳结果,对训练方案进行简单更新,实际训练也可根据数据acc训练是否已稳定来判断lr下降的迭代次数:. 适当增大softmax迭代次数,4万-->12万;. 增大arcface第一级lr0.1的迭代次数,8万-->12万;.

MTCNN人脸及特征点检测--基于树莓派3B+及ncnn架构 - yuanlulu的博客 - CSDN博客

- -
本文尝试在树莓派3B+上用ncnn框架测试MTCNN. ncnn的基本编译和使用请参考《. 在树莓派3B+上编译ncnn并用benchmark和mobilenet_yolo测试》. mtcn-ncnn项目中下载mtcnn子目录,把这个目录放在最新的ncnn源码目录下. 修改ncnn最顶层的CMakeList.txt,增加对mtcnn的支持.

ncnn 载入insightface训练好的性别年龄识别模型 - sinat_31425585的博客 - CSDN博客

- -
从insightface项目中下载mxnet模型:. 2、使用ncnn的模型转换工具mxnet2ncnn进行模型转换.

Android 遥控车

- CasparZ - LinuxTOY
您确定您真的会用 Android 手机玩赛车. 16 岁的法国学生 Jonathan Rico 使用 Android 手机通过蓝牙实现了对改装玩具汽车的遥控. 操控的方式和那些标榜的智能手机游戏一样,使用重力感应,差别是这次控制的是现实世界中的遥控汽车. 收藏到 del.icio.us |.