特征提取?
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
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);// 如果圖像中沒有人臉獲取人臉大于1if (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);// 如果圖像中沒有人臉獲取人臉大于1if (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();// 使用圖像路徑和特征向量調用 compareFaceFeaturesdouble distance = fr.compareFaceFeatures(imagePath, featureVector);System.out.println("The distance between the image and the feature vector is: " + distance);}
}