android opencv NDK人脸识别和对比,银行软件开发面试题

build script, prebuilt third-party libraries, or system libraries.

target_link_libraries( # Specifies the target library.

人脸识别

hxgopencv-lib

opencv_java3

#加入该依赖库 undefined reference to `AndroidBitmap_getInfo’

jnigraphics

Links the target library to the log library

included in the NDK.

${log-lib})

  • 加载级联选择器

在这里插入图片描述

/**

  • 加载人脸识别的分类器文件

*/

private void copyCaseCadeFile() {

try {

// load cascade file from application resources

InputStream is = getResources().openRawResource(R.raw.lbpcascade_frontalface);

File cascadeDir = getDir(“cascade”, Context.MODE_PRIVATE);

mCascadeFile = new File(cascadeDir, “lbpcascade_frontalface.xml”);

if (mCascadeFile.exists()) return;

FileOutputStream os = new FileOutputStream(mCascadeFile);

byte[] buffer = new byte[4096];

int bytesRead;

while ((bytesRead = is.read(buffer)) != -1) {

os.write(buffer, 0, bytesRead);

}

is.close();

os.close();

} catch (IOException e) {

e.printStackTrace();

}

}

/**

  • 加载人脸识别的分类器文件

  • @param filePath

*/

public native void loadCascade(String filePath);

#include <jni.h>

#include

#include “opencv2/opencv.hpp”

#include “android/bitmap.h”

#include “android/log.h”

//使用命名空间

using namespace cv;

using namespace dnn;

/**

  • 加载人脸识别的分类器文件

*/

CascadeClassifier cascadeClassifier;

extern “C”

JNIEXPORT void JNICALL

Java_com_hxg_ndkface_FaceDetection_loadCascade(JNIEnv *env, jobject instance, jstring file_path) {

const char *filePath = env->GetStringUTFChars(file_path, 0);

cascadeClassifier.load(filePath);

__android_log_print(ANDROID_LOG_INFO, “TTTTT”, “%s”, “分类器文件加载成功”);

env->ReleaseStringUTFChars(file_path, filePath);

}

  • 只检测是否有人脸

/**

  • 只检测是否有人脸

*/

extern “C”

JNIEXPORT jboolean JNICALL

Java_com_hxg_ndkface_FaceDetection_faceDetection(JNIEnv *env, jobject thiz, jobject bitmap) {

//检测人脸,opencv 有个关键类 是Mat open只会处理Mat android里面是Bitmap

//1.Bitmap转成opencv能操作的C++对象Mat

Mat mat;

bitmap2Mat(env, mat, bitmap);

//处理灰度图,提高效率

Mat gray_mat;

__android_log_print(ANDROID_LOG_INFO, “TTTTT”, “%s”, “处理灰度图”);

cvtColor(mat, gray_mat, COLOR_BGRA2GRAY);

__android_log_print(ANDROID_LOG_INFO, “TTTTT”, “%s”, “再次处理 直方均衡补偿”);

//再次处理 直方均衡补偿

Mat equalize_mat;

equalizeHist(gray_mat, equalize_mat);

//识别人脸,要加载人脸分类器文件

std::vector faces;

cascadeClassifier.detectMultiScale(equalize_mat, faces, 1.1, 3, CV_HAAR_SCALE_IMAGE,

Size(30, 30));

__android_log_print(ANDROID_LOG_INFO, “TTTTT”, “人脸个数:%d”, faces.size());

if (faces.size() == 1) {

return true;

}

return false;

}

  • 检测有无人脸,并保存到文件夹

/**

  • 检测有无人脸,并保存到文件夹

*/

extern “C”

JNIEXPORT jint JNICALL

Java_com_hxg_ndkface_FaceDetection_faceDetectionSaveInfo(JNIEnv *env, jobject instance,

jstring name,

jobject bitmap) {

const char *filePath = env->GetStringUTFChars(name, 0);

//检测人脸,opencv 有个关键类 是Mat open只会处理Mat android里面是Bitmap

//1.Bitmap转成opencv能操作的C++对象Mat

Mat mat;

bitmap2Mat(env, mat, bitmap);

//处理灰度图,提高效率

Mat gray_mat;

cvtColor(mat, gray_mat, COLOR_BGRA2GRAY);

//再次处理 直方均衡补偿

Mat equalize_mat;

equalizeHist(gray_mat, equalize_mat);

//识别人脸,要加载人脸分类器文件

std::vector faces;

cascadeClassifier.detectMultiScale(equalize_mat, faces, 1.1, 5, 0 | CV_HAAR_SCALE_IMAGE,

Size(160, 160));

__android_log_print(ANDROID_LOG_INFO, “TTTTT”, “人脸个数:%d”, faces.size());

if (faces.size() == 1) {

Rect faceRect = faces[0];

//在人脸部分画个图

rectangle(mat, faceRect, Scalar(255, 0, 0), 3);

__android_log_print(ANDROID_LOG_ERROR, “TTTTT”, “人脸个数:%s”, “在人脸部分画个图”);

//把mat我们又放到bitmap中

mat2Bitmap(env, mat, bitmap);

//保存人脸信息Mat,图片jpg

Mat saveMat = Mat(equalize_mat, faceRect);

//保存face_info_mat

imwrite(filePath, equalize_mat);

return 1;

}

env->ReleaseStringUTFChars(name, filePath);

return 0;

}

  • 人脸对比

/**

*人脸对比

*/

extern “C”

JNIEXPORT jdouble JNICALL

Java_com_hxg_ndkface_FaceDetection_histogramMatch(JNIEnv *env, jobject instance, jobject bitmap1,

jobject bitmap2) {

//1.Bitmap转成opencv能操作的C++对象Mat

Mat mat, mat1;

bitmap2Mat(env, mat, bitmap1);

bitmap2Mat(env, mat1, bitmap2);

// 转灰度矩阵

cvtColor(mat, mat, COLOR_BGR2HSV);

cvtColor(mat1, mat1, COLOR_BGR2HSV);

int channels[] = {0, 1};

int histsize[] = {180, 255};

float r1[] = {0, 180};

float r2[] = {0, 255};

const float *ranges[] = {r1, r2};

Mat hist1, hist2;

calcHist(&mat, 3, channels, Mat(), hist1, 2, histsize, ranges, true);

//https://www.cnblogs.com/bjxqmy/p/12292421.html

normalize(hist1, hist1, 1, 0, NORM_L1);

calcHist(&mat1, 3, channels, Mat(), hist2, 2, histsize, ranges, true);

normalize(hist2, hist2, 1, 0, NORM_L1);

double similarity = compareHist(hist1, hist2, HISTCMP_CORREL);

__android_log_print(ANDROID_LOG_ERROR, “TTTTT”, “相识度:%f”, similarity);

return similarity;

}

  • Dnn模式的人脸识别,并抠图

private void copyCaseCadeFilePbtxt() {

InputStream is = null;

FileOutputStream os = null;

try {

// load cascade file from application resources

is = getResources().openRawResource(R.raw.opencv_face_detector);

File cascadeDir = getDir(“cascade”, Context.MODE_PRIVATE);

mCascadeFile = new File(cascadeDir, “opencv_face_detector.pbtxt”);

if (mCascadeFile.exists()) return;

os = new FileOutputStream(mCascadeFile);

byte[] buffer = new byte[1024 * 1024];

int bytesRead;

while ((bytesRead = is.read(buffer)) != -1) {

os.write(buffer, 0, bytesRead);

}

is.close();

os.close();

} catch (IOException e) {

e.printStackTrace();

} finally {

try {

if (is != null) {

is.close();

}

if (os != null) {

os.close();

}

} catch (IOException e) {

e.printStackTrace();

}

}

}

private void copyCaseCadeFileUint8() {

InputStream is = null;

FileOutputStream os = null;

try {

// load cascade file from application resources

is = getResources().openRawResource(R.raw.opencv_face_detector_uint8);

File cascadeDir = getDir(“cascade”, Context.MODE_PRIVATE);

mCascadeFile = new File(cascadeDir, “opencv_face_detector_uint8.pb”);

if (mCascadeFile.exists()) return;

os = new FileOutputStream(mCascadeFile);

byte[] buffer = new byte[1024 * 1024];

int bytesRead;

while ((bytesRead = is.read(buffer)) != -1) {

os.write(buffer, 0, bytesRead);

}

is.close();

os.close();

} catch (IOException e) {

e.printStackTrace();

} finally {

try {

if (is != null) {

is.close();

}

if (os != null) {

os.close();

}

} catch (IOException e) {

e.printStackTrace();

}

}

}

/**

*Dnn模式的人脸识别,并抠图

*/

extern “C”

JNIEXPORT jboolean JNICALL

Java_com_hxg_ndkface_FaceDetection_faceDnnDetection(JNIEnv *env, jobject instance,

jstring model_binary,

jstring model_desc,

jstring checkPath,

jstring resultPath) {

const char *model_binary_path = env->GetStringUTFChars(model_binary, 0);

const char *model_desc_path = env->GetStringUTFChars(model_desc, 0);

const char *check_path = env->GetStringUTFChars(checkPath, 0);

const char *result_path = env->GetStringUTFChars(resultPath, 0);

Net net = readNetFromTensorflow(model_binary_path, model_desc_path);

net.setPreferableBackend(DNN_BACKEND_OPENCV);

net.setPreferableTarget(DNN_TARGET_CPU);

if (net.empty()) {

__android_log_print(ANDROID_LOG_ERROR, “TTTTT”, “%s”, “could not load net…”);

return false;

}

Mat frame = imread(check_path); //读入检测文件

__android_log_print(ANDROID_LOG_ERROR, “TTTTT”, “%s”, “输入数据调整”);

// 输入数据调整

Mat inputBlob = blobFromImage(frame, 1.0,

Size(300, 300), Scalar(104.0, 177.0, 123.0), false, false);

net.setInput(inputBlob, “data”);

// 人脸检测

Mat detection = net.forward(“detection_out”);

Mat detectionMat(detection.size[2], detection.size[3], CV_32F, detection.ptr());

Mat face_area;

for (int i = 0; i < detectionMat.rows; i++) {

// 置信度 0~1之间

float confidence = detectionMat.at(i, 2);

if (confidence > 0.7) {

//count++;

int xLeftBottom = static_cast(detectionMat.at(i, 3) * frame.cols);

int yLeftBottom = static_cast(detectionMat.at(i, 4) * frame.rows);

int xRightTop = static_cast(detectionMat.at(i, 5) * frame.cols);

int yRightTop = static_cast(detectionMat.at(i, 6) * frame.rows);

Rect object((int) xLeftBottom, (int) yLeftBottom,

(int) (xRightTop - xLeftBottom),

(int) (yRightTop - yLeftBottom));

face_area = frame(object); //扣出图片

rectangle(frame, object, Scalar(0, 255, 0)); //画框

}

}

imwrite(result_path, face_area); //写出文件

env->ReleaseStringUTFChars(model_binary, model_binary_path);

env->ReleaseStringUTFChars(model_desc, model_desc_path);

env->ReleaseStringUTFChars(checkPath, check_path);

env->ReleaseStringUTFChars(resultPath, result_path);

return true;

}

  • Bitmap和Mat互转

/**

  • Bitmap转成opencv能操作的C++对象Mat

  • @param env

  • @param mat

  • @param bitmap

*/

void bitmap2Mat(JNIEnv *env, Mat &mat, jobject bitmap) {

//Mat 里面有个type :CV_8UC4刚好对上我们的Bitmap中的ARGB_8888 , CV_8UC2对应Bitmap中的RGB_555

//获取 bitmap 信息

AndroidBitmapInfo info;

void *pixels;

try {

// AndroidBitmap_getInfo(env, bitmap, &info);

//锁定Bitmap画布

// AndroidBitmap_lockPixels(env, bitmap, &pixels);

CV_Assert(AndroidBitmap_getInfo(env, bitmap, &info) >= 0);

CV_Assert(info.format == ANDROID_BITMAP_FORMAT_RGBA_8888 ||

info.format == ANDROID_BITMAP_FORMAT_RGB_565);

CV_Assert(AndroidBitmap_lockPixels(env, bitmap, &pixels) >= 0);

CV_Assert(pixels);

//指定mat的宽高type BGRA

mat.create(info.height, info.width, CV_8UC4);

if (info.format == ANDROID_BITMAP_FORMAT_RGBA_8888) {

//对应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) {

//对应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);

return;

} catch (Exception &e) {

AndroidBitmap_unlockPixels(env, bitmap);

jclass je = env->FindClass(“java/lang/Exception”);

env->ThrowNew(je, e.what());

return;

} catch (…) {

AndroidBitmap_unlockPixels(env, bitmap);

jclass je = env->FindClass(“java/lang/Exception”);

env->ThrowNew(je, “Unknown exception in JNI code {nBitmapToMat}”);

return;

}

}

/**

  • 把mat转成bitmap

  • @param env

  • @param mat

  • @param bitmap

*/

void mat2Bitmap(JNIEnv *env, Mat mat, jobject bitmap) {

//Mat 里面有个type :CV_8UC4刚好对上我们的Bitmap中的ARGB_8888 , CV_8UC2对应Bitmap中的RGB_555

//获取 bitmap 信息

AndroidBitmapInfo info;

void *pixels;

try {

// AndroidBitmap_getInfo(env, bitmap, &info);

//锁定Bitmap画布

// AndroidBitmap_lockPixels(env, bitmap, &pixels);

CV_Assert(AndroidBitmap_getInfo(env, bitmap, &info) >= 0);

CV_Assert(info.format == ANDROID_BITMAP_FORMAT_RGBA_8888 ||

info.format == ANDROID_BITMAP_FORMAT_RGB_565);

CV_Assert(mat.dims == 2 && info.height == (uint32_t) mat.rows &&

info.width == (uint32_t) mat.cols);

CV_Assert(mat.type() == CV_8UC1 || mat.type() == CV_8UC3 || mat.type() == CV_8UC4);

CV_Assert(AndroidBitmap_lockPixels(env, bitmap, &pixels) >= 0);

CV_Assert(pixels);

if (info.format == ANDROID_BITMAP_FORMAT_RGBA_8888) {

//对应mat应该是CV_8UC4

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);

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

面试复习笔记:

这份资料我从春招开始,就会将各博客、论坛。网站上等优质的Android开发中高级面试题收集起来,然后全网寻找最优的解答方案。每一道面试题都是百分百的大厂面经真题+最优解答。包知识脉络 + 诸多细节。
节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

《960页Android开发笔记》

《1307页Android开发面试宝典》

包含了腾讯、百度、小米、阿里、乐视、美团、58、猎豹、360、新浪、搜狐等一线互联网公司面试被问到的题目。熟悉本文中列出的知识点会大大增加通过前两轮技术面试的几率。

《507页Android开发相关源码解析》

只要是程序员,不管是Java还是Android,如果不去阅读源码,只看API文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。

真正最能锻炼能力的便是直接去阅读源码,不仅限于阅读各大系统源码,还包括各种优秀的开源库。

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img
零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!**

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-NkYxa7kL-1712684803952)]

面试复习笔记:

这份资料我从春招开始,就会将各博客、论坛。网站上等优质的Android开发中高级面试题收集起来,然后全网寻找最优的解答方案。每一道面试题都是百分百的大厂面经真题+最优解答。包知识脉络 + 诸多细节。
节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

《960页Android开发笔记》

[外链图片转存中…(img-zWD173dm-1712684803953)]

《1307页Android开发面试宝典》

包含了腾讯、百度、小米、阿里、乐视、美团、58、猎豹、360、新浪、搜狐等一线互联网公司面试被问到的题目。熟悉本文中列出的知识点会大大增加通过前两轮技术面试的几率。

[外链图片转存中…(img-G9umHhRY-1712684803953)]

《507页Android开发相关源码解析》

只要是程序员,不管是Java还是Android,如果不去阅读源码,只看API文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。

真正最能锻炼能力的便是直接去阅读源码,不仅限于阅读各大系统源码,还包括各种优秀的开源库。

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-fBLpPToX-1712684803953)]

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值