Android 人脸识别+人脸匹配(OpenCV+JavaCV)

╰+哭是因爲堅強的太久メ 2021-09-14 02:58 949阅读 0赞

http://m.blog.csdn.net/sky286753213/article/details/11887913

项目源码 http://download.csdn.net/detail/sky286753213/6617075

之前不想上传源码是因为代码写的实在很烂,参考价值不是很大,主要代码都在CameraActivity中

这里吐下槽,目前Android人脸识别技术分享的感觉很少

我也是参考一些资料和别人的代码加以改进

上个项目中用到的技术现在有些遗忘了,把关键性的代码给大家分享下

  1. public void DetectFace() {
  2. Mat image = Highgui.imread(FACE);
  3. MatOfRect faceDetections = new MatOfRect();
  4. mJavaDetector.detectMultiScale(image, faceDetections);
  5. for (Rect rect : faceDetections.toArray()) {
  6. Core.rectangle(image, new Point(rect.x, rect.y), new Point(rect.x
  7. + rect.width, rect.y + rect.height), new Scalar(0, 255, 0));
  8. // 把检测到的人脸重新定义大小后保存成文件
  9. Mat sub = image.submat(rect);
  10. Mat mat = new Mat();
  11. Size size = new Size(100, 100);
  12. Imgproc.resize(sub, mat, size);
  13. Highgui.imwrite(FACEDONE, mat);
  14. }
  15. }

FACE和FACEDONE为两个路径 一个是拍照完成的图片路径,另一个是生成的人脸图片的路径

这里使用了OpenCV中的人脸识别方法,方法很简单,把你的照片路径带进去他会检测到这张图片里有多少个人头,然后进行循环输出人脸图片

这里需要注意下的是 如果进行人脸比对的话需要每张图片的大小一样,否则会报异常

另外,想使用OpenCV之前还需定义一个BaseLoaderCallback对象来加载识别的人脸xml库

  1. private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
  2. public void onManagerConnected(int status) {
  3. switch (status) {
  4. case LoaderCallbackInterface.SUCCESS: {
  5. mJavaDetector = new CascadeClassifier(
  6. "/sdcard/FaceDetect/haarcascade_frontalface_alt2.xml");
  7. }
  8. break;
  9. default: {
  10. super.onManagerConnected(status);
  11. }
  12. break;
  13. }
  14. }
  15. };

然后在OnResume中加载BaseLoaderCallback对象

  1. OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_5, this,
  2. mLoaderCallback);

人脸匹配使用的是JavaCV中的匹配方法

该方法的博客一会附上连接

  1. public int Identification() {
  2. FaceRecognizer fr = createFisherFaceRecognizer();
  3. MatVector mv = new MatVector(faceList.size());
  4. CvMat cvMat = CvMat.create(faceList.size(), 1, CV_32SC1);
  5. for (int i = 0; i < faceList.size(); i++) {
  6. IplImage img = cvLoadImage(faceList.get(i).getPath(),
  7. CV_LOAD_IMAGE_GRAYSCALE);
  8. mv.put(i, img);
  9. cvMat.put(i, 0, i);
  10. }
  11. fr.train(mv, cvMat);
  12. IplImage testImage = cvLoadImage(
  13. Environment.getExternalStorageDirectory()
  14. + "/FaceDetect/faceDone.jpg", CV_LOAD_IMAGE_GRAYSCALE);
  15. return fr.predict(testImage);
  16. }

faceList中放的是人脸图片文件夹里所有人脸图片的路径

循环把他们放入MatVector和CvMat中

然后对FaceRecognizer进行训练

  1. /FaceDetect/faceDone.jpg

这个路径是经过上面识别方法处理完图片后所输出的人脸图片的路径

predict()方法把刚才的人脸图片放入训练模型中进行匹配 会返回一个模型中的索引值

获取到索引值后就大功告成了

下面一个方法可以获取到两张图片的相似度,最大值是100

  1. public double CmpPic(String path) {
  2. int l_bins = 20;
  3. int hist_size[] = { l_bins };
  4. float v_ranges[] = { 0, 100 };
  5. float ranges[][] = { v_ranges };
  6. IplImage Image1 = cvLoadImage(Environment.getExternalStorageDirectory()
  7. + "/FaceDetect/faceDone.jpg", CV_LOAD_IMAGE_GRAYSCALE);
  8. IplImage Image2 = cvLoadImage(path, CV_LOAD_IMAGE_GRAYSCALE);
  9. IplImage imageArr1[] = { Image1 };
  10. IplImage imageArr2[] = { Image2 };
  11. CvHistogram Histogram1 = CvHistogram.create(1, hist_size,
  12. CV_HIST_ARRAY, ranges, 1);
  13. CvHistogram Histogram2 = CvHistogram.create(1, hist_size,
  14. CV_HIST_ARRAY, ranges, 1);
  15. cvCalcHist(imageArr1, Histogram1, 0, null);
  16. cvCalcHist(imageArr2, Histogram2, 0, null);
  17. cvNormalizeHist(Histogram1, 100.0);
  18. cvNormalizeHist(Histogram2, 100.0);
  19. return cvCompareHist(Histogram1, Histogram2, CV_COMP_CORREL);
  20. }

带入两张图片的路径即可,这里不在阐述

下面是源码,写的很烂,仅供参考

  1. package com.comdosoft.face;
  2. import static com.googlecode.javacv.cpp.opencv_contrib.createFisherFaceRecognizer;
  3. import static com.googlecode.javacv.cpp.opencv_core.CV_32SC1;
  4. import static com.googlecode.javacv.cpp.opencv_highgui.CV_LOAD_IMAGE_GRAYSCALE;
  5. import static com.googlecode.javacv.cpp.opencv_highgui.cvLoadImage;
  6. import static com.googlecode.javacv.cpp.opencv_imgproc.CV_COMP_CORREL;
  7. import static com.googlecode.javacv.cpp.opencv_imgproc.CV_HIST_ARRAY;
  8. import static com.googlecode.javacv.cpp.opencv_imgproc.cvCalcHist;
  9. import static com.googlecode.javacv.cpp.opencv_imgproc.cvCompareHist;
  10. import static com.googlecode.javacv.cpp.opencv_imgproc.cvNormalizeHist;
  11. import java.io.BufferedOutputStream;
  12. import java.io.File;
  13. import java.io.FileOutputStream;
  14. import java.util.ArrayList;
  15. import java.util.List;
  16. import java.util.Timer;
  17. import java.util.TimerTask;
  18. import org.opencv.android.BaseLoaderCallback;
  19. import org.opencv.android.LoaderCallbackInterface;
  20. import org.opencv.android.OpenCVLoader;
  21. import org.opencv.core.Core;
  22. import org.opencv.core.Mat;
  23. import org.opencv.core.MatOfRect;
  24. import org.opencv.core.Point;
  25. import org.opencv.core.Rect;
  26. import org.opencv.core.Scalar;
  27. import org.opencv.core.Size;
  28. import org.opencv.highgui.Highgui;
  29. import org.opencv.imgproc.Imgproc;
  30. import org.opencv.objdetect.CascadeClassifier;
  31. import android.app.Activity;
  32. import android.app.ProgressDialog;
  33. import android.content.Intent;
  34. import android.content.pm.ActivityInfo;
  35. import android.graphics.Bitmap;
  36. import android.graphics.BitmapFactory;
  37. import android.graphics.Matrix;
  38. import android.hardware.Camera;
  39. import android.os.Bundle;
  40. import android.os.Environment;
  41. import android.os.Handler;
  42. import android.os.Message;
  43. import android.view.LayoutInflater;
  44. import android.view.SurfaceHolder;
  45. import android.view.SurfaceView;
  46. import android.view.View;
  47. import android.view.ViewGroup;
  48. import android.view.Window;
  49. import android.view.WindowManager;
  50. import android.widget.ImageView;
  51. import android.widget.Toast;
  52. import com.comdosoft.pojo.FacePojo;
  53. import com.googlecode.javacv.cpp.opencv_contrib.FaceRecognizer;
  54. import com.googlecode.javacv.cpp.opencv_core.CvMat;
  55. import com.googlecode.javacv.cpp.opencv_core.IplImage;
  56. import com.googlecode.javacv.cpp.opencv_core.MatVector;
  57. import com.googlecode.javacv.cpp.opencv_imgproc.CvHistogram;
  58. public class CameraActivity extends Activity implements SurfaceHolder.Callback,
  59. Camera.PictureCallback {
  60. private List<FacePojo> faceList = new ArrayList<FacePojo>();
  61. private ProgressDialog proDialog;
  62. private CascadeClassifier mJavaDetector;
  63. private SurfaceView mSurfaceView;
  64. private SurfaceHolder holder;
  65. private Camera camera;
  66. private String FACE = "/sdcard/FaceDetect/face.jpg";
  67. private String FACEDONE = "/sdcard/FaceDetect/faceDone.jpg";
  68. private int index;
  69. private int type;
  70. private int t = 2;
  71. private int angle = 0;
  72. private boolean flag = true;
  73. private double value;
  74. private Toast toast;
  75. private FacePojo fp;
  76. private int cameraCount;
  77. private CameraUtil cu = new CameraUtil();
  78. private int[] iconArr = new int[] { R.drawable.icon1, R.drawable.icon2,
  79. R.drawable.icon3 };
  80. private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
  81. public void onManagerConnected(int status) {
  82. switch (status) {
  83. case LoaderCallbackInterface.SUCCESS: {
  84. mJavaDetector = new CascadeClassifier(
  85. "/sdcard/FaceDetect/haarcascade_frontalface_alt2.xml");
  86. }
  87. break;
  88. default: {
  89. super.onManagerConnected(status);
  90. }
  91. break;
  92. }
  93. }
  94. };
  95. private Handler updateUI = new Handler() {
  96. @Override
  97. public void handleMessage(Message msg) {
  98. switch (msg.what) {
  99. case 1:
  100. proDialog.dismiss();
  101. Intent intent = new Intent();
  102. if (type == 0 || type == 1) {
  103. index = Identification();
  104. fp = faceList.get(index);
  105. value = CmpPic(fp.getPath()) * 100;
  106. }
  107. // Toast.makeText(getApplicationContext(),
  108. // "相似度:" + value + "--" + num, 0).show();
  109. if (value < 70 && type != 2) {
  110. intent.setClass(getApplicationContext(), SignFail.class);
  111. startActivity(intent);
  112. } else {
  113. if (type == 0) {
  114. Bundle bundle = new Bundle();
  115. bundle.putString("id", fp.getId());
  116. bundle.putString("name", fp.getName());
  117. intent.putExtras(bundle);
  118. intent.setClass(getApplicationContext(), SignIn.class);
  119. startActivity(intent);
  120. } else if (type == 1) {
  121. Intent intent2 = getIntent();
  122. Bundle bundle2 = new Bundle();
  123. bundle2.putInt("status", 1);
  124. bundle2.putString("id", fp.getId());
  125. bundle2.putString("name", fp.getName());
  126. intent2.putExtras(bundle2);
  127. setResult(RESULT_OK, intent2);
  128. finish();
  129. } else if (type == 2) {
  130. Intent intent2 = getIntent();
  131. setResult(RESULT_OK, intent2);
  132. finish();
  133. }
  134. }
  135. break;
  136. }
  137. }
  138. };
  139. private Timer dataTimer = new Timer();
  140. private Handler dataHandler = new Handler() {
  141. @Override
  142. public void handleMessage(Message msg) {
  143. super.handleMessage(msg);
  144. int msgId = msg.what;
  145. switch (msgId) {
  146. case 1:
  147. if (flag && t == -1) {
  148. // camera.autoFocus(null);
  149. camera.takePicture(null, null, CameraActivity.this);
  150. flag = false;
  151. }
  152. if (flag) {
  153. timeDown();
  154. }
  155. }
  156. }
  157. };
  158. @Override
  159. protected void onCreate(Bundle savedInstanceState) {
  160. super.onCreate(savedInstanceState);
  161. getWindow().clearFlags(
  162. WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
  163. getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
  164. requestWindowFeature(Window.FEATURE_NO_TITLE);// 设置横屏模式以及全屏模式
  165. setContentView(R.layout.camera);// 设置View
  166. proDialog = new ProgressDialog(this);
  167. Intent bundle = getIntent();
  168. type = bundle.getIntExtra("type", 0);
  169. mSurfaceView = (SurfaceView) findViewById(R.id.camera);
  170. holder = mSurfaceView.getHolder();
  171. holder.addCallback(this);
  172. holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);// 指定Push Buffer
  173. }
  174. @Override
  175. protected void onStart() {
  176. super.onStart();
  177. LoadFaceData();
  178. }
  179. @Override
  180. protected void onResume() {
  181. super.onResume();
  182. if (getRequestedOrientation() != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
  183. setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
  184. }
  185. OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_5, this,
  186. mLoaderCallback);
  187. }
  188. public void onPictureTaken(byte[] data, Camera camera) {
  189. try {
  190. String path = Environment.getExternalStorageDirectory()
  191. + "/FaceDetect/face.jpg";
  192. // data2file(data, path);
  193. Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
  194. Matrix matrix = new Matrix();
  195. // 设置图像的旋转角度
  196. matrix.setRotate(angle);
  197. // 旋转图像,并生成新的Bitmap对像
  198. bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
  199. bitmap.getHeight(), matrix, true);
  200. cu.writePhoto(bitmap, bitmap.getWidth(), bitmap.getHeight(), path);
  201. if (type == 2) {
  202. proDialog.setMessage("正在检测...");
  203. } else {
  204. proDialog.setMessage("正在识别...");
  205. }
  206. proDialog.show();
  207. Thread loginThread = new Thread(new LoginFailureHandler());
  208. loginThread.start();
  209. } catch (Exception e) {
  210. }
  211. camera.startPreview();
  212. }
  213. class LoginFailureHandler implements Runnable {
  214. public void run() {
  215. DetectFace();
  216. Message message = new Message();
  217. message.what = 1;
  218. updateUI.sendMessage(message);
  219. }
  220. }
  221. public void surfaceCreated(SurfaceHolder holder) {
  222. try {
  223. camera = Camera.open(camera());// 摄像头的初始化
  224. camera.setPreviewDisplay(holder);
  225. dataTimer.schedule(new TimerTask() {
  226. @Override
  227. public void run() {
  228. Message message = new Message();
  229. message.what = 1;
  230. dataHandler.sendMessage(message);
  231. }
  232. }, 0, 2000);
  233. } catch (Exception e) {
  234. }
  235. }
  236. public void surfaceChanged(SurfaceHolder holder, int format, int width,
  237. int height) {
  238. Camera.Parameters parameters = camera.getParameters();
  239. // parameters.setPreviewSize(1280, 800);
  240. camera.setParameters(parameters);// 设置参数
  241. int flag = getWindowManager().getDefaultDisplay().getRotation();
  242. angle = 450 - flag * 90;
  243. if (angle >= 360) {
  244. angle = angle - 360;
  245. }
  246. camera.setDisplayOrientation(angle);
  247. camera.startPreview();// 开始预览
  248. }
  249. public void surfaceDestroyed(SurfaceHolder holder) {
  250. camera.setPreviewCallback(null);
  251. camera.stopPreview();
  252. camera.release();
  253. camera = null;
  254. }
  255. // private void data2file(byte[] w, String fileName) throws Exception {//
  256. // 将二进制数据转换为文件的函数
  257. // FileOutputStream out = null;
  258. // try {
  259. // out = new FileOutputStream(fileName);
  260. // out.write(w);
  261. // out.close();
  262. // } catch (Exception e) {
  263. // if (out != null)
  264. // out.close();
  265. // throw e;
  266. // }
  267. // }
  268. public void DetectFace() {
  269. Mat image = Highgui.imread(FACE);
  270. MatOfRect faceDetections = new MatOfRect();
  271. mJavaDetector.detectMultiScale(image, faceDetections);
  272. int k = 0;
  273. for (Rect rect : faceDetections.toArray()) {
  274. Core.rectangle(image, new Point(rect.x, rect.y), new Point(rect.x
  275. + rect.width, rect.y + rect.height), new Scalar(0, 255, 0));
  276. // 把检测到的人脸重新定义大小后保存成文件
  277. Mat sub = image.submat(rect);
  278. Mat mat = new Mat();
  279. Size size = new Size(100, 100);
  280. Imgproc.resize(sub, mat, size);
  281. Highgui.imwrite(FACEDONE, mat);
  282. k++;
  283. }
  284. if (k == 0) {
  285. cu.writePhoto(BitmapFactory.decodeFile(FACE), 100, 100, FACEDONE);
  286. }
  287. }
  288. public int Identification() {
  289. FaceRecognizer fr = createFisherFaceRecognizer();
  290. MatVector mv = new MatVector(faceList.size());
  291. CvMat cvMat = CvMat.create(faceList.size(), 1, CV_32SC1);
  292. for (int i = 0; i < faceList.size(); i++) {
  293. IplImage img = cvLoadImage(faceList.get(i).getPath(),
  294. CV_LOAD_IMAGE_GRAYSCALE);
  295. mv.put(i, img);
  296. cvMat.put(i, 0, i);
  297. }
  298. fr.train(mv, cvMat);
  299. IplImage testImage = cvLoadImage(
  300. Environment.getExternalStorageDirectory()
  301. + "/FaceDetect/faceDone.jpg", CV_LOAD_IMAGE_GRAYSCALE);
  302. return fr.predict(testImage);
  303. }
  304. public void LoadFaceData() {
  305. File[] files = new File("/sdcard/FaceData/").listFiles();
  306. File f;
  307. String id;
  308. String name;
  309. faceList.clear();
  310. for (int i = 0; i < files.length; i++) {
  311. f = files[i];
  312. if (!f.canRead()) {
  313. return;
  314. }
  315. if (f.isFile()) {
  316. id = f.getName().split("_")[0];
  317. name = f.getName().substring(f.getName().indexOf("_") + 1,
  318. f.getName().length() - 4);
  319. faceList.add(new FacePojo(id, name, Environment
  320. .getExternalStorageDirectory()
  321. + "/FaceData/"
  322. + f.getName()));
  323. }
  324. }
  325. }
  326. public double CmpPic(String path) {
  327. int l_bins = 20;
  328. int hist_size[] = { l_bins };
  329. float v_ranges[] = { 0, 100 };
  330. float ranges[][] = { v_ranges };
  331. IplImage Image1 = cvLoadImage(Environment.getExternalStorageDirectory()
  332. + "/FaceDetect/faceDone.jpg", CV_LOAD_IMAGE_GRAYSCALE);
  333. IplImage Image2 = cvLoadImage(path, CV_LOAD_IMAGE_GRAYSCALE);
  334. IplImage imageArr1[] = { Image1 };
  335. IplImage imageArr2[] = { Image2 };
  336. CvHistogram Histogram1 = CvHistogram.create(1, hist_size,
  337. CV_HIST_ARRAY, ranges, 1);
  338. CvHistogram Histogram2 = CvHistogram.create(1, hist_size,
  339. CV_HIST_ARRAY, ranges, 1);
  340. cvCalcHist(imageArr1, Histogram1, 0, null);
  341. cvCalcHist(imageArr2, Histogram2, 0, null);
  342. cvNormalizeHist(Histogram1, 100.0);
  343. cvNormalizeHist(Histogram2, 100.0);
  344. return cvCompareHist(Histogram1, Histogram2, CV_COMP_CORREL);
  345. }
  346. public void writePhoto(Bitmap bmp) {
  347. File file = new File("/sdcard/FaceDetect/faceDone.jpg");
  348. try {
  349. Bitmap bm = Bitmap.createBitmap(bmp, 0, 0, 100, 100);
  350. BufferedOutputStream bos = new BufferedOutputStream(
  351. new FileOutputStream(file));
  352. if (bm.compress(Bitmap.CompressFormat.JPEG, 100, bos)) {
  353. bos.flush();
  354. bos.close();
  355. }
  356. } catch (Exception e) {
  357. e.printStackTrace();
  358. }
  359. }
  360. public void timeDown() {
  361. LayoutInflater inflater = getLayoutInflater();
  362. View layout = inflater.inflate(R.layout.custom,
  363. (ViewGroup) findViewById(R.id.llToast));
  364. ImageView image = (ImageView) layout.findViewById(R.id.tvImageToast);
  365. image.setImageResource(iconArr[t--]);
  366. toast = new Toast(getApplicationContext());
  367. toast.setDuration(Toast.LENGTH_SHORT);
  368. toast.setView(layout);
  369. toast.show();
  370. }
  371. public int camera() {
  372. Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
  373. cameraCount = Camera.getNumberOfCameras(); // get cameras number
  374. for (int camIdx = 0; camIdx < cameraCount; camIdx++) {
  375. Camera.getCameraInfo(camIdx, cameraInfo);
  376. if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
  377. try {
  378. return camIdx;
  379. } catch (RuntimeException e) {
  380. e.printStackTrace();
  381. }
  382. }
  383. }
  384. return 1;
  385. }
  386. }

发表评论

表情:
评论列表 (有 0 条评论,949人围观)

还没有评论,来说两句吧...

相关阅读

    相关 人脸识别

    计划 实现了一个基于 PCA 的人脸识别 方法 ,我 称之为 “ 特征点方法 ”, 所有的功能简单而且实用 。 下面,我使用一个简单的MATLAB脚本 说明 它的用法

    相关 人脸识别

    人脸检测 [长文干货!走近人脸检测:从 VJ 到深度学习(上)][VJ] [长文干货!走近人脸检测:从VJ到深度学习(下)][VJ 1]

    相关 人脸识别系统_人脸注册

        基于上次的人脸检测后,一直纠结人脸注册,照片存放方式,我想到了两种方式,1.数据库存照片存放的路径,2.数据库存放照片的二进制码。但是针对我的毕业设计我想要是存路径的话

    相关 人脸识别系统_人脸检测

    项目:基于人脸识别的无卡ATM机模拟系统 主要实现内容: 包括实现AMT机模拟人脸识别和密码输入、PC端模拟实现储户数据库服务器系统。 1. ATM模拟端实现采用手