下载地址 - https://opencv.org/releases/
1.人脸信息录入
2.获取相机的Bitmap,检测人脸信息(保证人脸特征信息比较精准),正常,眨眼睛,张嘴巴
3.提取特征值
// 将Mat转bitmap
void mat2Bitmap(JNIEnv *env,jobject bitmap,Mat mat){
// 1. 获取 bitmap 信息
AndroidBitmapInfo info;
void* pixels;
AndroidBitmap_getInfo(env,bitmap,&info);
// 锁定 Bitmap 画布
AndroidBitmap_lockPixels(env,bitmap,&pixels);
if(info.format == ANDROID_BITMAP_FORMAT_RGBA_8888){// C4
Mat temp(info.height,info.width,CV_8UC4,pixels);
if(mat.type() == CV_8UC4){
mat.copyTo(temp);
}
else if(mat.type() == CV_8UC2){
cvtColor(mat,temp,COLOR_BGR5652BGRA);
}
else if(mat.type() == CV_8UC1){// 灰度 mat
cvtColor(mat,temp,COLOR_GRAY2BGRA);
}
} else if(info.format == ANDROID_BITMAP_FORMAT_RGB_565){// C2
Mat temp(info.height,info.width,CV_8UC2,pixels);
if(mat.type() == CV_8UC4){
cvtColor(mat,temp,COLOR_BGRA2BGR565);
}
else if(mat.type() == CV_8UC2){
mat.copyTo(temp);
}
else if(mat.type() == CV_8UC1){// 灰度 mat
cvtColor(mat,temp,COLOR_GRAY2BGR565);
}
}
// 解锁 Bitmap 画布
AndroidBitmap_unlockPixels(env,bitmap);
}
// 将bitmap转Mat
void bitmap2Mat(JNIEnv *env,jobject bitmap,Mat &mat){
// Mat 里面有个 type : CV_8UC4 刚好对上我们的 Bitmap 中 ARGB_8888 , CV_8UC2 刚好对象我们的 Bitmap 中 RGB_565
// 1. 获取 bitmap 信息
AndroidBitmapInfo info;
void* pixels;
AndroidBitmap_getInfo(env,bitmap,&info);
// 锁定 Bitmap 画布
AndroidBitmap_lockPixels(env,bitmap,&pixels);
// 指定 mat 的宽高和type BGRA
mat.create(info.height,info.width,CV_8UC4);
if(info.format == ANDROID_BITMAP_FORMAT_RGBA_8888){
__android_log_print(ANDROID_LOG_INFO,"JNI_TAG","bitmap2Mat : RGBA_8888 -> CV_8UC4");
// 对应的 mat 应该是 CV_8UC4
Mat temp(info.height,info.width,CV_8UC4,pixels);
// 把数据 temp 复制到 mat 里面
temp.copyTo(mat);
} else if(info.format == ANDROID_BITMAP_FORMAT_RGB_565){
__android_log_print(ANDROID_LOG_INFO,"JNI_TAG","bitmap2Mat : RGB_565 -> CV_8UC4");
// 对应的 mat 应该是 CV_8UC2
Mat temp(info.height,info.width,CV_8UC2,pixels);
// mat 是 CV_8UC4 ,CV_8UC2 -> CV_8UC4
cvtColor(temp,mat,COLOR_BGR5652BGRA);
}
// 解锁 Bitmap 画布
AndroidBitmap_unlockPixels(env,bitmap);
}
Java部分代码
// 拷贝文件至可读取位置
public String copyCascadeClassifier() {
String fileName = "lbpcascade_frontalface.xml";
// 先判断该文件是否存在
String filePath = getFilesDir().getAbsolutePath() + File.separator + fileName;
File file = new File(filePath);
if(!file.exists()){
Log.d(FaceRecognition.TAG,"文件不存在开始拷贝");
try {
InputStream inputStream = getAssets().open(fileName);
FileOutputStream fileOutputStream = new FileOutputStream(file);
int length = 0;
byte[] bytes = new byte[1024 * 1024];
while ((length = inputStream.read(bytes))!= -1){
fileOutputStream.write(bytes,0,length);
}
fileOutputStream.close();
inputStream.close();
}catch (Exception e){
e.printStackTrace();
}
}
return filePath;
}
C++部分代码
CascadeClassifier cascadeClassifier;
extern "C"
JNIEXPORT void JNICALL
Java_com_barray_opencvdemo_FaceRecognition_loadCascadeClassifier(JNIEnv *env, jobject thiz,
jstring file_path) {
const char * c_file_path = env->GetStringUTFChars(file_path,JNI_FALSE);
cascadeClassifier.load(c_file_path);
__android_log_print(ANDROID_LOG_INFO,"JNI_TAG","加载人脸分类器成功");
env->ReleaseStringUTFChars(file_path,c_file_path);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_barray_opencvdemo_FaceRecognition_saveFaceInfo(JNIEnv *env, jobject thiz,
jobject bitmap) {
// 检测人脸
Mat mat;
bitmap2Mat(env,bitmap,mat);
// 灰度处理
Mat grey_mat;
cvtColor(mat,grey_mat,COLOR_BGRA2GRAY);
// 直方均衡补偿(轮廓会比较明显)
Mat equalize_mat;
equalizeHist(grey_mat,equalize_mat);
// 识别人脸
std::vector faces;
// 加载人脸分类器文件
cascadeClassifier.detectMultiScale(equalize_mat,faces,1.1,5);
__android_log_print(ANDROID_LOG_INFO,"JNI_TAG","人脸个数:%lu",faces.size());
if(!faces.empty()){
Rect faceRect = faces[0];
// 在人脸上画个框
rectangle(mat,faceRect,Scalar(255,155,155),8);
// 将数据保存到bitmap中
mat2Bitmap(env,bitmap,mat);
Mat face_info_mat(equalize_mat,faceRect);
// 可以保存到本地
}
}
build.gradle
plugins {
id 'com.android.application'
}
android {
compileSdkVersion 30
buildToolsVersion "30.0.3"
defaultConfig {
applicationId "com.barray.opencvdemo"
minSdkVersion 23
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags ""
abiFilters 'arm64-v8a'
arguments "-DANDROID_STL=c++_shared" // 很重要
}
}
}
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'
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.10.2)
project("opencvdemo")
include_directories(include)
set(distribution_DIR ${CMAKE_SOURCE_DIR}/../../../libs)
# 编解码(最重要的库)
add_library(
opencv_java
SHARED
IMPORTED)
set_target_properties(
opencv_java
PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/${ANDROID_ABI}/libopencv_java4.so)
add_library(
native-lib
SHARED
native-lib.cpp )
find_library(
log-lib
log )
target_link_libraries(
native-lib jnigraphics -landroid opencv_java
${log-lib} )
注意
源码下载