/**
- 在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();
}
}
});
}
说明:
- 若本地图片库为空,提示用户,实现存储本地图片库
架构师筑基包括哪些内容
我花了将近半个月时间将:深入 Java 泛型.、注解深入浅出、并发编程.、数据传输与序列化、Java 虚拟机原理、反射与类加载、高效 IO、Kotlin项目实战等等Android架构师筑基必备技能整合成了一套系统知识笔记PDF,相信看完这份文档,你将会对这些Android架构师筑基必备技能有着更深入、更系统的理解。
由于文档内容过多,为了避免影响到大家的阅读体验,在此只以截图展示部分内容
注:资料与上面思维导图一起看会更容易学习哦!每个点每个细节分支,都有对应的目录内容与知识点!
这份资料就包含了所有Android初级架构师所需的所有知识!
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!
show();
}
}
});
}
说明:
- 若本地图片库为空,提示用户,实现存储本地图片库
架构师筑基包括哪些内容
我花了将近半个月时间将:深入 Java 泛型.、注解深入浅出、并发编程.、数据传输与序列化、Java 虚拟机原理、反射与类加载、高效 IO、Kotlin项目实战等等Android架构师筑基必备技能整合成了一套系统知识笔记PDF,相信看完这份文档,你将会对这些Android架构师筑基必备技能有着更深入、更系统的理解。
由于文档内容过多,为了避免影响到大家的阅读体验,在此只以截图展示部分内容
注:资料与上面思维导图一起看会更容易学习哦!每个点每个细节分支,都有对应的目录内容与知识点!
[外链图片转存中…(img-euLF5as2-1714940388563)]
[外链图片转存中…(img-HFdAZAEW-1714940388564)]
这份资料就包含了所有Android初级架构师所需的所有知识!
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!