java 实现人脸特征提取和比对

特征提取 

1. 安装必要的库

确保你已经安装了JPEG库、BLAS和LAPACK库。在Ubuntu或Debian系统上,可以使用以下命令安装:

sudo apt-get update
sudo apt-get update
sudo apt-get install build-essential cmake
sudo apt-get install libgtk-3-dev
sudo apt-get install libboost-all-dev
sudo apt-get install libopenblas-dev liblapack-dev
sudo apt-get install libx11-dev libatlas-base-dev
sudo apt-get install libjpeg-dev libpng-dev libtiff-dev
sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev

在CentOS或Fedora系统上,可以使用以下命令安装:

sudo yum update
sudo yum groupinstall "Development Tools"
sudo yum install gtk3-devel
sudo yum install boost-devel
sudo yum install openblas-devel lapack-devel
sudo yum install xorg-x11-devel
sudo yum install atlas-devel
sudo yum install libjpeg-devel libpng-devel libtiff-devel
sudo yum install ffmpeg-devel  # 注意用ffmpeg-devel代替libavcodec-dev等


#首先,删除已安装的CMake版本(如果需要的话):

sudo yum remove cmake
#下载并安装CMake的新版:

wget https://github.com/Kitware/CMake/releases/download/v3.16.3/cmake-3.16.3-Linux-x86_64.sh
chmod +x cmake-3.16.3-Linux-x86_64.sh
sudo ./cmake-3.16.3-Linux-x86_64.sh --prefix=/usr/local --exclude-subdir
#注意:这里使用的是3.16.3版本,你可以下载最新的稳定版本。

#使CMake的更新生效:

source /etc/profile
#检查CMake版本:
#安装完成后,通过运行以下命令来检查CMake的版本:

cmake --version
#确保输出显示的版本号是3.8.0或更高。


sudo yum install centos-release-scl
sudo yum install devtoolset-9-gcc* 

2. 确保dlib使用正确的库

dlib通常会自动检测系统上的JPEG、BLAS和LAPACK库。如果你已经安装了这些库,dlib应该能够自动找到并使用它们。

3. 重新编译dlib库

重新编译dlib库,并确保启用位置无关代码(PIC):

git clone https://github.com/davisking/dlib.git
cd dlib
mkdir build
cd build
cmake .. -DDLIB_USE_CUDA=OFF -DUSE_AVX_INSTRUCTIONS=ON -DCMAKE_POSITION_INDEPENDENT_CODE=ON
cmake --build .
sudo make install
 

FaceRecognition.java

注意dlib_face_recognition,extractFeatures这些名称,g++编译的是libdlib_face_recognition.so,需要去掉前面的lib和后面的.so,extractFeatures名称在C++中需要前缀Java_FaceRecognition_,FaceRecognition这java类名一致

public class FaceRecognition {
    static {
        System.loadLibrary("dlib_face_recognition");
    }

    public native String extractFeatures(String imagePath);

    public static void main(String[] args) {
        if (args.length != 1) {
            System.out.println("Usage: java FaceRecognition <image_path>");
            return;
        }

        String imagePath = args[0];
        FaceRecognition fr = new FaceRecognition();
        String features = fr.extractFeatures(imagePath);
        System.out.println("Extracted features: \n" + features);
    }
}

dlib_face_recognition.cpp

include <jni.h>
#include <dlib/image_processing/frontal_face_detector.h>
#include <dlib/image_processing/render_face_detections.h>
#include <dlib/image_processing.h>
#include <dlib/image_io.h>
#include <dlib/dnn.h>
#include <sstream>
#include <string>
#include <vector>

// 定义用于脸部识别的深度神经网络
template <template <int, template <typename> class, int, typename> class block, int N, template <typename> class BN, typename SUBNET>
using residual = dlib::add_prev1<block<N, BN, 1, dlib::tag1<SUBNET>>>;

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

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

template <int N, typename SUBNET> using res  = dlib::relu<residual<block, N, dlib::bn_con, SUBNET>>;
template <int N, typename SUBNET> using ares = dlib::relu<residual<block, N, dlib::affine, SUBNET>>;
template <int N, typename SUBNET> using res_down  = dlib::relu<residual_down<block, N, dlib::bn_con, SUBNET>>;
template <int N, typename SUBNET> using ares_down = dlib::relu<residual_down<block, N, dlib::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 = dlib::loss_metric<dlib::fc_no_bias<128, dlib::avg_pool_everything<
                            alevel0<
                            alevel1<
                            alevel2<
                            alevel3<
                            alevel4<
                            dlib::max_pool<3, 3, 2, 2, dlib::relu<dlib::affine<dlib::con<32, 7, 7, 2, 2,
                            dlib::input_rgb_image_sized<150>
                            >>>>>>>>>>>>;


extern "C" JNIEXPORT jstring JNICALL Java_FaceRecognition_extractFeatures(JNIEnv *env, jobject obj, jstring imagePath) {
    const char *path = env->GetStringUTFChars(imagePath, 0);

    dlib::frontal_face_detector detector = dlib::get_frontal_face_detector();
    dlib::shape_predictor sp;
    dlib::deserialize("shape_predictor_68_face_landmarks.dat") >> sp;
    anet_type net;
    dlib::deserialize("dlib_face_recognition_resnet_model_v1.dat") >> net;

    dlib::matrix<dlib::rgb_pixel> img;
    dlib::load_image(img, path);

    std::vector<dlib::matrix<dlib::rgb_pixel>> faces;
    for (auto face : detector(img)) {
        auto shape = sp(img, face);
        dlib::matrix<dlib::rgb_pixel> face_chip;
        dlib::extract_image_chip(img, dlib::get_face_chip_details(shape,150,0.25), face_chip);
        faces.push_back(std::move(face_chip));
    }

    std::vector<dlib::matrix<float,0,1>> face_descriptors = net(faces);

    std::ostringstream oss;
    for (auto& descriptor : face_descriptors) {
        for (int i = 0; i < descriptor.size(); ++i) {
            oss << descriptor(i) << " ";
        }
        oss << "\n";
    }

    env->ReleaseStringUTFChars(imagePath, path);
    return env->NewStringUTF(oss.str().c_str());
}
                                            

4. 编译你的C++代码

g++ -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux -shared -o libdlib_face_recognition.so -fPIC dlib_face_recognition.cpp -ldlib -lpthread -lblas -llapack -ljpeg

5.编译Java代码并生成头文件

确保在编译Java代码时指定编码为UTF-8:

javac -encoding UTF-8 -h . FaceRecognition.java

6. 运行Java程序 

java -Djava.library.path=. FaceRecognition 1.jpg

人脸比对

#include <jni.h>
#include <dlib/image_processing/frontal_face_detector.h>
#include <dlib/image_processing/render_face_detections.h>
#include <dlib/image_processing.h>
#include <dlib/image_io.h>
#include <dlib/dnn.h>
#include <sstream>
#include <string>
#include <vector>

// 定义用于脸部识别的深度神经网络
template <template <int, template <typename> class, int, typename> class block, int N, template <typename> class BN, typename SUBNET>
using residual = dlib::add_prev1<block<N, BN, 1, dlib::tag1<SUBNET>>>;

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

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

template <int N, typename SUBNET> using res  = dlib::relu<residual<block, N, dlib::bn_con, SUBNET>>;
template <int N, typename SUBNET> using ares = dlib::relu<residual<block, N, dlib::affine, SUBNET>>;
template <int N, typename SUBNET> using res_down  = dlib::relu<residual_down<block, N, dlib::bn_con, SUBNET>>;
template <int N, typename SUBNET> using ares_down = dlib::relu<residual_down<block, N, dlib::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 = dlib::loss_metric<dlib::fc_no_bias<128, dlib::avg_pool_everything<
                            alevel0<
                            alevel1<
                            alevel2<
                            alevel3<
                            alevel4<
                            dlib::max_pool<3, 3, 2, 2, dlib::relu<dlib::affine<dlib::con<32, 7, 7, 2, 2,
                            dlib::input_rgb_image_sized<150>
                            >>>>>>>>>>>>;

//检测人脸
extern "C" JNIEXPORT jint JNICALL Java_FaceRecognition_detectFaces(JNIEnv *env, jobject obj, jstring imagePath) {
    const char *path = env->GetStringUTFChars(imagePath, 0);

    dlib::frontal_face_detector detector = dlib::get_frontal_face_detector();
    dlib::matrix<dlib::rgb_pixel> img;
    dlib::load_image(img, path);

    std::vector<dlib::rectangle> faces = detector(img);

    env->ReleaseStringUTFChars(imagePath, path);
    return faces.size();
}

//人脸关键点提取
extern "C" JNIEXPORT jstring JNICALL Java_FaceRecognition_getFaceLandmarks(JNIEnv *env, jobject obj, jstring imagePath) {
    const char *path = env->GetStringUTFChars(imagePath, 0);

    dlib::frontal_face_detector detector = dlib::get_frontal_face_detector();
    dlib::shape_predictor sp;
    dlib::deserialize("shape_predictor_68_face_landmarks.dat") >> sp;

    dlib::matrix<dlib::rgb_pixel> img;
    dlib::load_image(img, path);

    std::vector<dlib::rectangle> faces = detector(img);
    std::ostringstream oss;
    for (auto face : faces) {
        auto shape = sp(img, face);
        for (int i = 0; i < shape.num_parts(); ++i) {
            oss << shape.part(i).x() << "," << shape.part(i).y() << " ";
        }
        oss << "\n";
    }

    env->ReleaseStringUTFChars(imagePath, path);
    return env->NewStringUTF(oss.str().c_str());
}

//人脸特征提取
extern "C" JNIEXPORT jstring JNICALL Java_getFaceFeatures(JNIEnv *env, jobject obj, jstring imagePath) {
    const char *path = env->GetStringUTFChars(imagePath, 0);

    dlib::frontal_face_detector detector = dlib::get_frontal_face_detector();
    dlib::shape_predictor sp;
    dlib::deserialize("shape_predictor_68_face_landmarks.dat") >> sp;
    anet_type net;
    dlib::deserialize("dlib_face_recognition_resnet_model_v1.dat") >> net;

    dlib::matrix<dlib::rgb_pixel> img;
    dlib::load_image(img, path);

    std::vector<dlib::matrix<dlib::rgb_pixel>> faces;
    for (auto face : detector(img)) {
        auto shape = sp(img, face);
        dlib::matrix<dlib::rgb_pixel> face_chip;
        dlib::extract_image_chip(img, dlib::get_face_chip_details(shape,150,0.25), face_chip);
        faces.push_back(std::move(face_chip));
    }

    std::vector<dlib::matrix<float,0,1>> face_descriptors = net(faces);

    std::ostringstream oss;
    for (auto& descriptor : face_descriptors) {
        for (int i = 0; i < descriptor.size(); ++i) {
            oss << descriptor(i) << " ";
        }
        oss << "\n";
    }

    env->ReleaseStringUTFChars(imagePath, path);
    return env->NewStringUTF(oss.str().c_str());
}


extern "C" JNIEXPORT jdouble JNICALL Java_FaceRecognition_compareFaceFeatures(
    JNIEnv *env, jobject obj, jstring imagePath, jstring featureVectorStr) {

    // 从 Java 获取图像路径和特征向量字符串
    const char *path = env->GetStringUTFChars(imagePath, 0);
    const char *featureVectorC = env->GetStringUTFChars(featureVectorStr, 0);

    // 初始化 dlib 的人脸检测器、形状预测器和神经网络模型
    dlib::frontal_face_detector detector = dlib::get_frontal_face_detector();
    dlib::shape_predictor sp;
    dlib::deserialize("shape_predictor_68_face_landmarks.dat") >> sp;
    // 确保 anet_type 已经定义且正确
    anet_type net;
    dlib::deserialize("dlib_face_recognition_resnet_model_v1.dat") >> net;

    // 加载图像
    dlib::matrix<dlib::rgb_pixel> img;
    load_image(img, path);

    // 检测图像中的人脸
    std::vector<dlib::rectangle> dets = detector(img);
    
    // 如果图像中没有人脸获取人脸大于1
    if (dets.empty() || dets.size() > 1) {
        env->ReleaseStringUTFChars(imagePath, path);
        env->ReleaseStringUTFChars(featureVectorStr, featureVectorC);
        throw  std::invalid_argument("no face or faces greater than 1");
    }

    std::vector<dlib::matrix<dlib::rgb_pixel>> faces;

    for (auto face : dets) {
        auto shape = sp(img, face);
        dlib::matrix<dlib::rgb_pixel> face_chip;
        dlib::extract_image_chip(img, dlib::get_face_chip_details(shape,150,0.25), face_chip);
        faces.push_back(std::move(face_chip));
    }

    std::vector<dlib::matrix<float,0,1>> imageFeatures = net(faces);

    // 将传入的特征字符串转换为 dlib 矩阵
    std::istringstream featureStream(featureVectorC);

    std::vector<float> featureVector;
    float value;
    while (featureStream >> value) {
        featureVector.push_back(value);
    }

    // 确保特征向量大小与模型输出大小一致
    if (featureVector.size() != imageFeatures[0].size()) {     
        // 释放 Java 字符串
        env->ReleaseStringUTFChars(imagePath, path);
        env->ReleaseStringUTFChars(featureVectorStr, featureVectorC);
        throw std::invalid_argument("Feature vector size does not match model output size.");
    }

    // 计算特征向量之间的欧氏距离
    double distance = 0;
  // 假定第一个人脸特征 imageFeatures[0] 是我们要比较的特征向量
    for (size_t i = 0; i < imageFeatures[0].size(); ++i) {
        distance += (imageFeatures[0](i) - featureVector[i]) * (imageFeatures[0](i) - featureVector[i]);
    }
    distance = std::sqrt(distance);

    // 释放 Java 字符串
    env->ReleaseStringUTFChars(imagePath, path);
    env->ReleaseStringUTFChars(featureVectorStr, featureVectorC);

    return distance;
}

避免模型多次加载

#include <jni.h>
#include <dlib/image_processing/frontal_face_detector.h>
#include <dlib/image_processing.h>
#include <dlib/image_io.h>
#include <dlib/dnn.h>
#include <sstream>
#include <string>
#include <vector>
#include <mutex>



// 定义用于脸部识别的深度神经网络
template <template <int, template <typename> class, int, typename> class block, int N, template <typename> class BN, typename SUBNET>
using residual = dlib::add_prev1<block<N, BN, 1, dlib::tag1<SUBNET>>>;

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

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

template <int N, typename SUBNET> using res  = dlib::relu<residual<block, N, dlib::bn_con, SUBNET>>;
template <int N, typename SUBNET> using ares = dlib::relu<residual<block, N, dlib::affine, SUBNET>>;
template <int N, typename SUBNET> using res_down  = dlib::relu<residual_down<block, N, dlib::bn_con, SUBNET>>;
template <int N, typename SUBNET> using ares_down = dlib::relu<residual_down<block, N, dlib::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 = dlib::loss_metric<dlib::fc_no_bias<128, dlib::avg_pool_everything<
                            alevel0<
                            alevel1<
                            alevel2<
                            alevel3<
                            alevel4<
                            dlib::max_pool<3, 3, 2, 2, dlib::relu<dlib::affine<dlib::con<32, 7, 7, 2, 2,
                            dlib::input_rgb_image_sized<150>
                            >>>>>>>>>>>>;

// 前置声明全局静态变量
std::mutex& get_global_mutex();
dlib::frontal_face_detector& get_global_face_detector();
dlib::shape_predictor& get_global_shape_predictor();
anet_type& get_global_anet_type();

// 全局静态变量定义在.cpp文件中
std::mutex global_mutex;
dlib::frontal_face_detector global_face_detector;
dlib::shape_predictor global_shape_predictor;
anet_type global_anet_type;

// 实现线程安全的单例模式
std::mutex& get_global_mutex() {
    return global_mutex;
}

dlib::frontal_face_detector& get_global_face_detector() {
    static dlib::frontal_face_detector detector = dlib::get_frontal_face_detector();
    return detector;
}

dlib::shape_predictor& get_global_shape_predictor() {
    static dlib::shape_predictor sp;
    static std::once_flag flag;
    std::call_once(flag, []() {
        dlib::deserialize("shape_predictor_68_face_landmarks.dat") >> sp;
    });
    return sp;
}

anet_type& get_global_anet_type() {
    static anet_type net;
    static std::once_flag flag;
    std::call_once(flag, []() {
        dlib::deserialize("dlib_face_recognition_resnet_model_v1.dat") >> net;
    });
    return net;
}

//检测人脸
extern "C" JNIEXPORT jint JNICALL Java_FaceRecognition_detectFaces(JNIEnv *env, jobject obj, jstring imagePath) {

    const char *path = env->GetStringUTFChars(imagePath, 0);

    dlib::frontal_face_detector& detector = get_global_face_detector();
    dlib::matrix<dlib::rgb_pixel> img;
    dlib::load_image(img, path);

    std::vector<dlib::rectangle> faces = detector(img);

    env->ReleaseStringUTFChars(imagePath, path);
    return faces.size();
}

//人脸关键点提取
extern "C" JNIEXPORT jstring JNICALL Java_FaceRecognition_getFaceLandmarks(JNIEnv *env, jobject obj, jstring imagePath) {

    const char *path = env->GetStringUTFChars(imagePath, 0);

     // 使用 get_global_face_detector() 获取全局人脸检测器
    dlib::frontal_face_detector& detector = get_global_face_detector();
    // 使用 get_global_shape_predictor() 获取全局形状预测器
    dlib::shape_predictor& sp = get_global_shape_predictor();

    dlib::matrix<dlib::rgb_pixel> img;
    dlib::load_image(img, path);

    std::vector<dlib::rectangle> faces = detector(img);
    std::ostringstream oss;
    for (auto face : faces) {
        auto shape = sp(img, face);
        for (int i = 0; i < shape.num_parts(); ++i) {
            oss << shape.part(i).x() << "," << shape.part(i).y() << " ";
        }
        oss << "\n";
    }

    env->ReleaseStringUTFChars(imagePath, path);
    return env->NewStringUTF(oss.str().c_str());
}

//人脸特征提取
extern "C" JNIEXPORT jstring JNICALL Java_getFaceFeatures(JNIEnv *env, jobject obj, jstring imagePath) {
 
    const char *path = env->GetStringUTFChars(imagePath, 0);

     // 使用 get_global_face_detector() 获取全局人脸检测器
    dlib::frontal_face_detector& detector = get_global_face_detector();
    // 使用 get_global_shape_predictor() 获取全局形状预测器
    dlib::shape_predictor& sp = get_global_shape_predictor();
    anet_type& net = get_global_anet_type();

    dlib::matrix<dlib::rgb_pixel> img;
    dlib::load_image(img, path);

    std::vector<dlib::matrix<dlib::rgb_pixel>> faces;
    for (auto face : detector(img)) {
        auto shape = sp(img, face);
        dlib::matrix<dlib::rgb_pixel> face_chip;
        dlib::extract_image_chip(img, dlib::get_face_chip_details(shape,150,0.25), face_chip);
        faces.push_back(std::move(face_chip));
    }

    std::vector<dlib::matrix<float,0,1>> face_descriptors = net(faces);

    std::ostringstream oss;
    for (auto& descriptor : face_descriptors) {
        for (int i = 0; i < descriptor.size(); ++i) {
            oss << descriptor(i) << " ";
        }
        oss << "\n";
    }

    env->ReleaseStringUTFChars(imagePath, path);
    return env->NewStringUTF(oss.str().c_str());
}


extern "C" JNIEXPORT jdouble JNICALL Java_FaceRecognition_compareFaceFeatures(
    JNIEnv *env, jobject obj, jstring imagePath, jstring featureVectorStr) {

    // 从 Java 获取图像路径和特征向量字符串
    const char *path = env->GetStringUTFChars(imagePath, 0);
    const char *featureVectorC = env->GetStringUTFChars(featureVectorStr, 0);

     // 使用 get_global_face_detector() 获取全局人脸检测器
    dlib::frontal_face_detector& detector = get_global_face_detector();
    // 使用 get_global_shape_predictor() 获取全局形状预测器
    dlib::shape_predictor& sp = get_global_shape_predictor();

    anet_type& net = get_global_anet_type();

    // 加载图像
    dlib::matrix<dlib::rgb_pixel> img;
    load_image(img, path);

    // 检测图像中的人脸
    std::vector<dlib::rectangle> dets = detector(img);
    
    // 如果图像中没有人脸获取人脸大于1
    if (dets.empty() || dets.size() > 1) {
        env->ReleaseStringUTFChars(imagePath, path);
        env->ReleaseStringUTFChars(featureVectorStr, featureVectorC);
        throw  std::invalid_argument("no face or faces greater than 1");
    }

    std::vector<dlib::matrix<dlib::rgb_pixel>> faces;

    for (auto face : dets) {
        auto shape = sp(img, face);
        dlib::matrix<dlib::rgb_pixel> face_chip;
        dlib::extract_image_chip(img, dlib::get_face_chip_details(shape,150,0.25), face_chip);
        faces.push_back(std::move(face_chip));
    }

    std::vector<dlib::matrix<float,0,1>> imageFeatures = net(faces);

    // 将传入的特征字符串转换为 dlib 矩阵
    std::istringstream featureStream(featureVectorC);

    std::vector<float> featureVector;
    float value;
    while (featureStream >> value) {
        featureVector.push_back(value);
    }

    // 确保特征向量大小与模型输出大小一致
    if (featureVector.size() != imageFeatures[0].size()) {     
        // 释放 Java 字符串
        env->ReleaseStringUTFChars(imagePath, path);
        env->ReleaseStringUTFChars(featureVectorStr, featureVectorC);
        throw std::invalid_argument("Feature vector size does not match model output size.");
    }

    // 计算特征向量之间的欧氏距离
    double distance = 0;
  // 假定第一个人脸特征 imageFeatures[0] 是我们要比较的特征向量
    for (size_t i = 0; i < imageFeatures[0].size(); ++i) {
        distance += (imageFeatures[0](i) - featureVector[i]) * (imageFeatures[0](i) - featureVector[i]);
    }
    distance = std::sqrt(distance);

    // 释放 Java 字符串
    env->ReleaseStringUTFChars(imagePath, path);
    env->ReleaseStringUTFChars(featureVectorStr, featureVectorC);

    return distance;
}

java

public class FaceRecognition {
    static {
        System.loadLibrary("dlib_face_recognition");
    }

    // 以下方法已经定义好,用于检测人脸、获取特征、比对特征和获取关键点
    public native int detectFaces(String imagePath);
    public native String getFaceFeatures(String imagePath);
    public native double compareFaceFeatures(String imagePath, String featureVector);
    public native String getFaceLandmarks(String imagePath);

    public static void main(String[] args) {
        // 确保传入正确的参数数量
        if (args.length != 2) {
            System.out.println("Usage: java FaceRecognition <image_path> <feature_vector>");
            return;
        }

        String imagePath = args[0];
        String featureVector = args[1]; // 128维特征向量,以空格分隔的字符串形式
        FaceRecognition fr = new FaceRecognition();

        // 使用图像路径和特征向量调用 compareFaceFeatures
        double distance = fr.compareFaceFeatures(imagePath, featureVector);
        System.out.println("The distance between the image and the feature vector is: " + distance);
    }
}


改进特征提取(效率不高)

extern "C" JNIEXPORT jstring JNICALL Java_FaceRecognition_getFaceFeatures(JNIEnv *env, jobject obj, jstring imagePath) {
    time_t start_time = time(NULL);
    // 获取图像路径
    const char *path = env->GetStringUTFChars(imagePath, 0);
    // 使用 get_global_face_detector() 获取全局人脸检测器
    dlib::frontal_face_detector& detector = get_global_face_detector();
    // 使用 get_global_shape_predictor() 获取全局形状预测器
    dlib::shape_predictor& sp = get_global_shape_predictor();

    anet_type& net = get_global_anet_type();

    dlib::matrix<dlib::rgb_pixel> img;
    dlib::load_image(img, path);

    // 初始化随机数生成器
    dlib::rand rnd(time(0));

    std::vector<dlib::rectangle> faces = detector(img);
    std::ostringstream oss;
    std::vector<dlib::matrix<float, 0, 1>> featuresList;

    if (faces.empty() || faces.size() > 1 ){
        env->ReleaseStringUTFChars(imagePath, path);
        return env->NewStringUTF("no face or face greater than 1");
    }

    for (int i = 0; i < 15 ; ++i) {
        // 调整图片的对比度与亮度
        double contrast = rnd.get_double_in_range(0.5, 1.5);
        int brightness = rnd.get_integer_in_range(-50, 50);
        dlib::matrix<dlib::rgb_pixel> adjusted_img(img);
        for (long r = 0; r < adjusted_img.nr(); ++r) {
            for (long c = 0; c < adjusted_img.nc(); ++c) {
                dlib::rgb_pixel& pixel = adjusted_img(r, c);

                // 调整对比度,确保对比度调整后的值在0-255范围内
                auto contrast_adjust = [](int val, double c) {
                    auto adjusted = static_cast<int>(val * c);
                    return static_cast<unsigned char>(std::min(255, std::max(0, adjusted)));
                };

                // 应用对比度调整
                pixel.red   = contrast_adjust(pixel.red,   contrast);
                pixel.green = contrast_adjust(pixel.green, contrast);
                pixel.blue  = contrast_adjust(pixel.blue,  contrast);

                // 调整亮度,确保亮度调整后的值在0-255范围内
                pixel.red   = std::min(static_cast<unsigned char>(pixel.red) + brightness, 255);
                pixel.green = std::min(static_cast<unsigned char>(pixel.green) + brightness, 255);
                pixel.blue  = std::min(static_cast<unsigned char>(pixel.blue) + brightness, 255);
            }
        }
        std::vector<dlib::matrix<dlib::rgb_pixel>> adjusted_img_faces;
        std::vector<dlib::rectangle> adjusted_det_faces = detector(adjusted_img);
        if (adjusted_det_faces.empty()){
            continue;
        }
        for (auto face : adjusted_det_faces) {
            // sp 函数是有效的并且已经在适当的作用域中
            auto shape = sp(adjusted_img, face);
            dlib::matrix<dlib::rgb_pixel> face_chip;
            dlib::extract_image_chip(img, dlib::get_face_chip_details(shape, 150, 0.25), face_chip);
            adjusted_img_faces.push_back(std::move(face_chip));
            
        }
        // 并且 net 函数接受单个 face_chip 作为参数,返回一个包含单个特征向量的 std::vector
        std::vector<dlib::matrix<float, 0, 1>> features = net(adjusted_img_faces); // 这里假设 net 接受单个图像片段
        //需要遍历 features 并将其每个元素添加到 featuresList 中
        for (auto& feature : features) {
            featuresList.push_back(feature);
        }

    }
    // 计算特征向量的平均值
    if (!featuresList.empty()) {

        dlib::matrix<float, 0, 1> meanFeatures(128, 0);
        for (const auto& features : featuresList) {
            meanFeatures += features;
        }
        meanFeatures /= featuresList.size();
   
        // 将特征向量转换为字符串
        for (long j = 0; j < meanFeatures.size(); ++j) {
            oss << meanFeatures(j) << " ";
        }
    } else {
        oss << "0";
    }

    env->ReleaseStringUTFChars(imagePath, path);
    time_t end_time = time(NULL);
    // 计算经过的秒数
    long int elapsed_seconds = difftime(end_time, start_time);
    printf("Elapsed time in seconds: %ld\n", elapsed_seconds);
    return env->NewStringUTF(oss.str().c_str());
}

部分优化

extern "C" JNIEXPORT jstring JNICALL Java_FaceRecognition_getFaceFeatures(JNIEnv *env, jobject obj, jstring imagePath) {
    auto start = std::chrono::high_resolution_clock::now();
    // 获取图像路径
    const char *path = env->GetStringUTFChars(imagePath, 0);
    // 使用 get_global_face_detector() 获取全局人脸检测器
    dlib::frontal_face_detector& detector = get_global_face_detector();
    // 使用 get_global_shape_predictor() 获取全局形状预测器
    dlib::shape_predictor& sp = get_global_shape_predictor();

    anet_type& net = get_global_anet_type();

    dlib::matrix<dlib::rgb_pixel> img;
    dlib::load_image(img, path);

    // 初始化随机数生成器
    dlib::rand rnd(time(0));

    std::vector<dlib::rectangle> faces = detector(img);
    std::ostringstream oss;
    std::vector<dlib::matrix<float, 0, 1>> featuresList;
    
    if (faces.empty() || faces.size() > 1 ){
        env->ReleaseStringUTFChars(imagePath, path);
        return env->NewStringUTF("no face or face greater than 1");
    }

    dlib::matrix<dlib::rgb_pixel> adjusted_img(img);
    
    auto shape = sp(adjusted_img, faces[0]);
    dlib::matrix<dlib::rgb_pixel> face_chip_temp;
    dlib::extract_image_chip(img, dlib::get_face_chip_details(shape, 150, 0.25), face_chip_temp);

    
    int no_face = 0;
    for (int i = 0; i < 15 ; ++i) {
        std::vector<dlib::matrix<dlib::rgb_pixel>> adjusted_img_faces;
        dlib::matrix<dlib::rgb_pixel> face_chip(face_chip_temp);
        if(i > 1){
                for (long r = 0; r < face_chip.nr(); ++r) {
                    for (long c = 0; c < face_chip.nc(); ++c) {
                        // 调整图片的对比度与亮度
                        double contrast = rnd.get_double_in_range(0.5, 1.5);
                        int brightness = rnd.get_integer_in_range(-50, 50);
                        dlib::rgb_pixel& pixel = face_chip(r, c);
                        // 调整对比度,确保对比度调整后的值在0-255范围内
                        auto contrast_adjust = [](int val, double c) {
                            auto adjusted = static_cast<int>(val * c);
                            return static_cast<unsigned char>(std::min(255, std::max(0, adjusted)));
                        };

                        // 应用对比度调整
                        pixel.red   = contrast_adjust(pixel.red,   contrast);
                        pixel.green = contrast_adjust(pixel.green, contrast);
                        pixel.blue  = contrast_adjust(pixel.blue,  contrast);

                        // 调整亮度,确保亮度调整后的值在0-255范围内
                        pixel.red   = std::min(static_cast<unsigned char>(pixel.red) + brightness, 255);
                        pixel.green = std::min(static_cast<unsigned char>(pixel.green) + brightness, 255);
                        pixel.blue  = std::min(static_cast<unsigned char>(pixel.blue) + brightness, 255);
                    }
                }
        }
        if(detector(face_chip).size() != 0){
            adjusted_img_faces.push_back(std::move(face_chip));
        
            // 并且 net 函数接受单个 face_chip 作为参数,返回一个包含单个特征向量的 std::vector
            std::vector<dlib::matrix<float, 0, 1>> features = net(adjusted_img_faces); // 这里假设 net 接受单个图像片段
            //需要遍历 features 并将其每个元素添加到 featuresList 中
            for (auto& feature : features) {
                featuresList.push_back(feature);
            }
        }else{
            no_face++;
        }
       
        adjusted_img_faces.clear();
       
    }
    
    printf("no face num: %d \n",no_face);
    // 计算特征向量的平均值
    if (!featuresList.empty()) {

        dlib::matrix<float, 0, 1> meanFeatures(128, 0);
        for (const auto& features : featuresList) {
            meanFeatures += features;
        }
        meanFeatures /= featuresList.size();
   
        // 将特征向量转换为字符串
        for (long j = 0; j < meanFeatures.size(); ++j) {
            oss << meanFeatures(j) << " ";
        }
    } else {
        oss << "0";
    }
     
    featuresList.clear();
    env->ReleaseStringUTFChars(imagePath, path);

     // 计算运行时间
    auto end = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);

    // 设置cout的精度为小数点后两位
    std::cout << std::fixed << std::setprecision(2);
    // 打印运行时间,以秒为单位
    std::cout << "Elapsed time: " << duration.count() / 1000.0 << " seconds" << std::endl;
    return env->NewStringUTF(oss.str().c_str());
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值