/**
- 在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开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!