Androidstudio4 集成dlib

本文详细介绍了如何在Android Studio项目中集成dlib库,通过CMakeLists.txt进行编译配置,包括新建工程、设置调试支持、添加依赖库、配置CMakeLists文件、修改app/build.gradle以及测试代码。此外,还提供了测试环境的配置方法,如文件拷贝到设备等。
摘要由CSDN通过智能技术生成


下面介绍在AS中集成dlib,通过CMakeList.txt方式

建议看这个GitHub - bookzhan/bzdlib: dlib demo for android,face tracker,face landmark

一、新建工程

1. 在创建工程的对话框中选择Include C++ support,如下图所示:

创建工程

2. 一直点击Next,直到最后一步。选择Exception Support(-fexceptions)Runtime Type Information Support(-frtti),便于出错时的调试。如下图所示:

 调试支持

为了防止错误提示:Installed Build Tools revision 32.0.0 is corrupted. Remove and install again using the SDK Manager.

SDK选择30

 Project/build.gradle增加阿里云

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    repositories {
        maven{url "https://maven.aliyun.com/repository/central"}
        maven{url "https://maven.aliyun.com/repository/public"}
        maven{url "https://maven.aliyun.com/repository/google"}
        maven{url "https://maven.aliyun.com/repository/gradle-plugin"}
    }
    dependencies {
        classpath "com.android.tools.build:gradle:4.2.1"
    }
}

allprojects {
    repositories {
        maven{url "https://maven.aliyun.com/repository/central"}
        maven{url "https://maven.aliyun.com/repository/public"}
        maven{url "https://maven.aliyun.com/repository/google"}
        maven{url "https://maven.aliyun.com/repository/gradle-plugin"}
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

Module/build.gradle设置编译的sdk

plugins {
    id 'com.android.application'
}

android {
    compileSdkVersion 30
    buildToolsVersion "30.0.3"

    defaultConfig {
        applicationId "com.hc.facetest2"
        minSdkVersion 23
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        externalNativeBuild {
            cmake {
                arguments '-DANDROID_STL=c++_shared'  #防止报libc++_shared.so  not found错误
                cppFlags '-std=c++11  -frtti -fexceptions'
                abiFilters "armeabi-v7a", "arm64-v8a", "x86_64", "x86"
            }
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    externalNativeBuild {
        cmake {
            path file('src/main/cpp/CMakeLists.txt')
            version '3.10.2'
        }
    }
    buildFeatures {
        viewBinding true
    }
}

dependencies {

    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'com.google.android.material:material:1.2.1'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}

  • 配置文件

将opencv或dlib-19.22解压后整个文件夹,拷贝到main/cpp文件夹下面

AndroidManifest.xml文件,打开摄像头,和文件读写权限

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

          package="com.tzutalin.dlibtest">

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <uses-permission android:name="android.permission.CAMERA" />

    <uses-permission android:name="android.permission.INTERNET" />

<uses-permission android:name="android.permission.RECORD_AUDIO" />

    <application

        android:allowBackup="true"

        android:icon="@mipmap/ic_launcher"

        android:label="@string/app_name"

        android:supportsRtl="true"

        android:theme="@style/AppTheme">

        <activity

            android:name=".MainActivity_"

            android:configChanges="orientation|screenSize"

            android:label="@string/app_name"

            android:theme="@style/AppTheme.NoActionBar">

            <intent-filter>

                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>

            </intent-filter>

        </activity>

    </application>

</manifest>

  • 配置CMakeLists文件

Main/cpp/CMakeList.txt文件

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.10.2)

project("cmaketest2")

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.


include(./dlib-19.22/dlib/cmake)

# Include headers
add_library( # Sets the name of the library.
             native-lib
             # Sets the library as a shared library.
             SHARED
             # Provides a relative path to your source file(s).
             native-lib.cpp)

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

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 )

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.

target_link_libraries( # Specifies the target library.
                       native-lib

                       # Links the target library to the log library
                       # included in the NDK.
                       dlib ${log-lib} )

增加的dlib库名在dlib-19.22\dlib\CMakeList.txt文件夹找

project(dlib)  这个文件夹名就是

四、配置app/build.gradle

1. 添加CPU架构的支持

abiFilters  "armeabi-v7a", "arm64-v8a",  "x86", "x86_64"

如下:

plugins {
    id 'com.android.application'
}

android {
    compileSdkVersion 30
    buildToolsVersion "30.0.3"

    defaultConfig {
        applicationId "com.hc.facetest2"
        minSdkVersion 23
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        externalNativeBuild {
            cmake {
                cppFlags ''
                abiFilters "armeabi-v7a", "arm64-v8a"
            }
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    externalNativeBuild {
        cmake {
            path file('src/main/cpp/CMakeLists.txt')
            version '3.10.2'
        }
    }
    buildFeatures {
        viewBinding true
    }
}

dependencies {

    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'com.google.android.material:material:1.2.1'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}

五、测试文件

main/cpp/native-lib.cpp内容如下:

#include <jni.h>
#include <string>
#include "dlib/dnn.h"
#include "dlib/clustering.h"
#include "dlib/string.h"
#include "dlib/image_io.h"
#include "dlib/image_processing/frontal_face_detector.h"


using namespace dlib;
using namespace std;


template <template <int, template<typename>class, int, typename> class block, int N, template<typename>class BN, typename SUBNET>
using residual = add_prev1<block<N, BN, 1, tag1<SUBNET>>>;

template <template <int, template<typename>class, int, typename> class block, int N, template<typename>class BN, typename SUBNET>
using residual_down = add_prev2<avg_pool<2, 2, 2, 2, skip1<tag2<block<N, BN, 2, tag1<SUBNET>>>>>>;

template <int N, template <typename> class BN, int stride, typename SUBNET>
using block = BN<con<N, 3, 3, 1, 1, relu<BN<con<N, 3, 3, stride, stride, SUBNET>>>>>;

template <int N, typename SUBNET> using ares = relu<residual<block, N, affine, SUBNET>>;
template <int N, typename SUBNET> using ares_down = relu<residual_down<block, N, affine, SUBNET>>;

template <typename SUBNET> using alevel0 = ares_down<256, SUBNET>;
template <typename SUBNET> using alevel1 = ares<256, ares<256, ares_down<256, SUBNET>>>;
template <typename SUBNET> using alevel2 = ares<128, ares<128, ares_down<128, SUBNET>>>;
template <typename SUBNET> using alevel3 = ares<64, ares<64, ares<64, ares_down<64, SUBNET>>>>;
template <typename SUBNET> using alevel4 = ares<32, ares<32, ares<32, SUBNET>>>;

using anet_type = loss_metric<fc_no_bias<128, avg_pool_everything<
        alevel0<
                alevel1<
                        alevel2<
                                alevel3<
                                        alevel4<
                                                max_pool<3, 3, 2, 2, relu<affine<con<32, 7, 7, 2, 2,
                                                        input_rgb_image_sized<150>
                                                >>>>>>>>>>>>;

//正向人脸检测器
frontal_face_detector detector;
// We will also use a face landmarking model to align faces to a standard pose:  (see face_landmark_detection_ex.cpp for an introduction)
shape_predictor sp;
// And finally we load the DNN responsible for face recognition.#生成面部识别器
anet_type net;
bool isInit = 0;
int i=0;
matrix<rgb_pixel> img;

struct membuf : std::streambuf {
    membuf(char* begin, char* end) {
        this->setg(begin, begin, end);
    }
};

string getstring(const int n)
{
    std::stringstream newstr;
    newstr<<n;
    return newstr.str();
}

std::string convertJStrToString(JNIEnv* env, jstring lString) {
    const char* lStringTmp;
    std::string str;

    lStringTmp = env->GetStringUTFChars(lString, NULL);
    if (lStringTmp == NULL)
        return NULL;

    str = lStringTmp;

    env->ReleaseStringUTFChars(lString, lStringTmp);

    return str;
}

void initLib(){
    if(!isInit){
        deserialize("/sdcard/Android/data/com.hc.facetest2/files/shape_predictor_68_face_landmarks.dat") >> sp;
        deserialize("/sdcard/Android/data/com.hc.facetest2/files/dlib_face_recognition_resnet_model_v1.dat") >> net;
        //load_image(img, imagenamePath);
        load_image(img, "/sdcard/Android/data/com.hc.facetest2/files/6.jpg");
        isInit = 1;
    }
}

extern "C" JNIEXPORT jstring JNICALL
Java_com_hc_facetest2_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    i+=1;
    std::string hello = "Hello from C++" +getstring(i);
    return env->NewStringUTF(hello.c_str());
}

extern "C" JNIEXPORT jfloatArray JNICALL
Java_com_hc_facetest2_MainActivity_getLibFaceValue(
        JNIEnv* env,
        jobject, jstring imagePath) {
    initLib();
    //正向人脸检测器
    detector = get_frontal_face_detector();
    //string image = convertJStrToString(env, imagePath);

    // and centered. 图片放大到150x150,旋转居中。人脸对齐
    std::vector<matrix<rgb_pixel>> faces;
    for (auto face :  detector(img))
    {
        auto shape =  sp(img, face);
        matrix<rgb_pixel> face_chip;
        extract_image_chip(img, get_face_chip_details(shape, 150, 0.25), face_chip);
        faces.push_back(move(face_chip));
    }
    if (faces.size() == 0)
    {
        cout << "No faces found in image!" << endl;
        return NULL;
    }
    //提取特征 - 图像中的68个关键点转换为128D面部描述符,其中同一人的图片被映射到彼此附近,并且不同人的图片被远离地映射。
    std::vector<matrix<float, 0, 1>> face_descriptors = net(faces);
    if (face_descriptors.size() > 0)
    {
        float dx[128]{};
        matrix<float, 0, 1> xx = face_descriptors[0];
        //遍历行
        for (size_t _rowIdx = 0; _rowIdx < xx.nr(); _rowIdx++)
        {
            //遍历列,由于它只有128行,1列,所以不遍历列
            // for (size_t _colIdx = 0; _colIdx < xx.nc(); _colIdx++)
            // {
            dx[_rowIdx] = xx(_rowIdx, 0);
            //}
        }
        jfloatArray faceFeatureArray = env->NewFloatArray(128);
        env->SetFloatArrayRegion(faceFeatureArray, 0, 128, dx);
        return faceFeatureArray;
    }
    return NULL;
}

Main/java/com/hc/facetest2/MainActivy.java

package com.hc.facetest2;

import androidx.appcompat.app.AppCompatActivity;

import android.Manifest;
import android.os.Build;
import android.os.Bundle;
import android.widget.TextView;

import com.hc.facetest2.databinding.ActivityMainBinding;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

   

// Used to load the 'native-lib' library on application startup.
static{
    System.loadLibrary("native-lib");
}

private static Handler handler=new Handler();

private ActivityMainBinding binding;

private Button testBtn;
TextView tv;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    binding = ActivityMainBinding.inflate(getLayoutInflater());
    setContentView(binding.getRoot());
    // Example of a call to a native method
     tv = binding.sampleText;

  //  tv = findViewById(R.id.sample_text);
    tv.setText(stringFromJNI());

    testBtn = binding.buttonTest;// = findViewById(R.id.button_test);
    testBtn.setOnClickListener(v -> {
        getvalue();
    });
}

@Override
protected void onResume() {
    super.onResume();
    requestPermission();
}

public void getvalue(){
    tv.setText("开始计时");
    Log.i("MainActivity","点击按钮2");

    new Thread("Thread#1") {
        @Override
        public void run() {
            //tv.setText(stringFromJNI());
            long begintime = System.currentTimeMillis();

            float[] xxs = getLibFaceValue("");
            for (float xx : xxs) {
                Log.i("MainActivity", String.valueOf(xx));
            }
            handler.post(new Runnable() {
                @Override
                public void run() {
                    tv.setText("用时"+(System.currentTimeMillis() - begintime) / 1000+""+xxs);
                }
             });
        }
    }.start();
}

private boolean requestPermission() {
    ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA}, 1);
    return true;
}

/**
 * A native method that is implemented by the 'native-lib' native library,
 * which is packaged with this application.
 */
public native String stringFromJNI();

public native float[] getLibFaceValue(String imagePath);

}

六、配置测试环境

将下面两个文件(Index of /files),以及一个名叫6.jpg的人脸图片,拷贝到虚拟机设备sd卡,根目录中。

dlib_face_recognition_resnet_model_v1.dat

shape_predictor_68_face_landmarks.dat

手工拷贝会出错,应该用adb工具拷贝命令格式如下:

多设备查询

>adb  devices

 >adb  -s 2557fe09  push d:/pics/6.jpg  /sdcard/      上传文件命令

查看模拟器的文件夹

#adb shell     单设备控制端

#adb  -s  2557fe09  shell      多设备控制端

2021-12-28 14:49:05.498 23866-23866/com.hc.facetest2 I/System.out: -0.09826109

2021-12-28 14:49:05.498 23866-23866/com.hc.facetest2 I/System.out: 0.10588784

2021-12-28 14:49:05.498 23866-23866/com.hc.facetest2 I/System.out: 0.03188623

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值