OpenCV开发之——在官方人脸检测的基础上添加人脸识别

/**

  • 在2秒内识别出的数目>5才是识别成功

*/

public boolean isFaceRecon(long startTime, long endTime, Rect[] facesArray) {

if (startTime < endTime) {

if (facesArray.length == 1) {

num++;

} else {

num = 0;

}

}

return num > 5;

}

4.2 人脸识别

4.2.1 界面布局

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

第一个图像显示识别出的图像

相似度:根据识别出的图像与本地库对比结果

照片库:显示照片库中的图片

4.2.2 FaceUtil工具类

public class FaceUtil {

private static final String TAG = “FaceUtil”;

private FaceUtil() {

}

/**

  • 特征保存

  • @param image Mat

  • @param rect 人脸信息

  • @return 保存是否成功

*/

public static boolean saveImage(Mat image, Rect rect) {

// 原图置灰

Mat grayMat = new Mat();

Imgproc.cvtColor(image, grayMat, Imgproc.COLOR_BGR2GRAY);

//Imgproc.cvtColor(image, grayMat, Imgproc.COLORMAP_JET);

// 把检测到的人脸重新定义大小后保存成文件

Mat sub = grayMat.submat(rect);

Mat mat = new Mat();

Size size = new Size(100, 100);

Imgproc.resize(sub, mat, size);

return Imgcodecs.imwrite(getRecFileName(), mat);

}

/**

  • 删除特征

  • @param context Context

  • @param fileName 特征文件

  • @return 是否删除成功

*/

public static boolean deleteImage(Context context, String fileName) {

// 文件名不能为空

if (TextUtils.isEmpty(fileName)) {

return false;

}

// 文件路径不能为空

String path = getRecFileNameList()[0];

if (path != null) {

File file = new File(path);

return file.exists() && file.delete();

} else {

return false;

}

}

/**

  • 提取特征

  • @param

  • @param fileName 文件名

  • @return 特征图片

*/

public static Bitmap getImage(String fileName) {

//String filePath = getRecFileNameList()[0];

if (TextUtils.isEmpty(fileName)) {

return null;

} else {

return BitmapFactory.decodeFile(fileName);

}

}

public static double recon(Context context) {

String[] dataPath = getDataFileNameList();

String recPath = getRecFileNameList()[0];

double diff = 0;

for (int i = 0; i < dataPath.length; i++) {

diff = compare(dataPath[i], recPath);

if (diff >= 90) {

break;

}

}

return diff;

}

/**

  • 特征对比

  • @param

  • @param fileName1 人脸特征

  • @param fileName2 人脸特征

  • @return 相似度

*/

public static double compare(String fileName1, String fileName2) {

try {

IplImage image1 = cvLoadImage(fileName1, opencv_imgcodecs.IMREAD_GRAYSCALE);

IplImage image2 = cvLoadImage(fileName2, opencv_imgcodecs.IMREAD_GRAYSCALE);

if (null == image1 || null == image2) {

return -1;

}

int l_bins = 256;

int hist_size[] = {l_bins};

float v_ranges[] = {0, 255};

float ranges[][] = {v_ranges};

IplImage imageArr1[] = {image1};

IplImage imageArr2[] = {image2};

CvHistogram Histogram1 = CvHistogram.create(1, hist_size, CV_HIST_ARRAY, ranges, 1);

CvHistogram Histogram2 = CvHistogram.create(1, hist_size, CV_HIST_ARRAY, ranges, 1);

cvCalcHist(imageArr1, Histogram1, 0, null);

cvCalcHist(imageArr2, Histogram2, 0, null);

cvNormalizeHist(Histogram1, 100.0);

cvNormalizeHist(Histogram2, 100.0);

// 参考:http://blog.csdn.net/nicebooks/article/details/8175002

double c1 = cvCompareHist(Histogram1, Histogram2, CV_COMP_CORREL) * 100;

double c2 = cvCompareHist(Histogram1, Histogram2, CV_COMP_INTERSECT);

// Log.i(TAG, “compare: ----------------------------”);

// Log.i(TAG, "compare: c1 = " + c1);

// Log.i(TAG, "compare: c2 = " + c2);

// Log.i(TAG, "compare: 平均值 = " + ((c1 + c2) / 2));

// Log.i(TAG, “compare: ----------------------------”);

return (c1 + c2) / 2;

} catch (Exception e) {

e.printStackTrace();

return -1;

}

}

/**

  • @return 路径

*/

public static File getDataSourcePath() {

File file = new File(Environment.getExternalStorageDirectory(), “/FaceDetect/sourcePic/”);

if (!file.exists()) {

file.mkdirs();

}

return file;

//return new File(Environment.getExternalStorageDirectory(),“/FaceDetect/sourcePic/”);

}

public static File getRecPath() {

File file = new File(Environment.getExternalStorageDirectory(), “FaceDetect”);

if (!file.exists()) {

file.mkdirs();

}

return file;

// return new File(Environment.getExternalStorageDirectory(),“FaceDetect”);

}

private static String getRecFileName() {

String name = new SimpleDateFormat(“yyyy-MM-dd-HH:mm:ss”).format(new Date()) + “.jpg”;

return new File(getRecPath().getAbsolutePath(), name).getAbsolutePath();

//return getRecPath().getAbsolutePath() + new SimpleDateFormat(“yyyy-MM-dd-HH:mm:ss”).format(new Date()) + “.jpg”;

}

/**

  • @return

  • @description:获取识别库下的所有文件

*/

public static String[] getDataFileNameList() {

File pathName = getDataSourcePath();

File[] files = pathName.listFiles();

String[] fileNames = null;

if (files != null) {

fileNames = fileFilterEnd(files, “jpg”);

Arrays.sort(fileNames, Collections.reverseOrder());

}

return fileNames;

}

/**

  • @return

  • @description:获取最近识别出的文件

*/

public static String getRecFileAbsolutePath() {

String fileName = FaceUtilNew.getRecFileNameList()[0];

return new File(getRecPath().getAbsolutePath(), fileName).getAbsolutePath();

}

public static String[] getRecFileNameList() {

File pathName = getRecPath();

File[] files = pathName.listFiles();

String[] fileNames = null;

if (files != null) {

fileNames = fileFilterEnd(files, “jpg”);

Arrays.sort(fileNames, Collections.reverseOrder());

}

return fileNames;

}

//删除所有临时文件

public static void deleteRecFiles(){

String [] recStringFiles=getRecFileNameList();

for (String str:recStringFiles) {

File file=new File(getRecPath().getAbsolutePath(),str);

file.delete();

}

}

private static String[] fileFilterEnd(File[] f, String end) {

int count = 0;

for (int i = 0; i < f.length; i++) {

if (f[i].getName().endsWith(end)) count++;

}

String[] s1 = new String[count];

count = 0;

for (int i = 0; i < f.length; i++) {

if (f[i].getName().endsWith(end)) {

s1[count] = f[i].getName();

count++;

}

}

return s1;

}

}

4.2.3 识别成功后,将识别到的图像保存到本地文件夹下([内部存储]/FaceDetect/yyyy-MM-dd-HH:mm:ss.jpg)

FaceUtil.saveImage(mat, rect); //将当前识别到的图像保存到/SDCard/FaceDetect文件夹下

4.2.4 将识别到图片与本地库进行对比

public void onFaceLocalLib(final Mat mat, final Rect rect, final CameraBridgeViewBase mOpenCvCameraView) {

runOnUiThread(new Runnable() {

@Override

public void run() {

FaceUtil.saveImage(mat, rect); //将当前识别到的图像保存到/SDCard/FaceDetect文件夹下

String[] dataFileNameList = FaceUtil.getDataFileNameList(); //本地库所有源文件

recPath = FaceUtil.getRecFileAbsolutePath();

if (dataFileNameList.length == 0) {

Toast.makeText(FdActivity2.this,“图片库为空,请先准备本地图片库”,Toast.LENGTH_SHORT).show();

//FaceUtil.deleteRecFiles();

//finish();

return;

}

for (String fileName : dataFileNameList) {

dataNamePath = new File(FaceUtilNew.getDataSourcePath().getAbsolutePath(), fileName).getAbsolutePath();

diff = FaceUtil.compare(dataNamePath, recPath);

mImageViewFace1.setImageBitmap(FaceUtilNew.getImage(recPath));

mImageViewFace2.setImageBitmap(FaceUtilNew.getImage(dataNamePath));

mCmpPic.setText(String.format(“相似度 : %.2f”, diff) + “%”);

if (diff >= 75)

break;

}

if (diff <= 75) {

mOpenCvCameraView.enableView();

} else {

mOpenCvCameraView.disableView();

Toast.makeText(FdActivity2.this, “识别成功!!” + diff, Toast.LENGTH_LONG).show();

}

}

});

}

说明:

  • 若本地图片库为空,提示用户,实现存储本地图片库

最后

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

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

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

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助**。

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

[外链图片转存中…(img-PsqxngMp-1715714583309)]

[外链图片转存中…(img-huVWyxOt-1715714583310)]

[外链图片转存中…(img-hmB4UrdF-1715714583311)]

[外链图片转存中…(img-5Rvsrq4L-1715714583313)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值