特征提取
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());
}