JavaCV人脸训练和人脸识别代码实现

短命女 2024-03-31 12:32 167阅读 0赞

JavaCV

JavaCV是一个基于OpenCV和FFmpeg的Java开发库,用于实现计算机视觉和图像处理功能。它提供了一系列的类和方法,使得开发者能够在Java应用程序中轻松地使用计算机视觉算法和技术。

  1. OpenCV和FFmpeg集成:JavaCV紧密整合了OpenCV和FFmpeg这两个重要的计算机视觉和视频处理库。开发者可以直接在Java代码中调用OpenCV和FFmpeg的功能,无需使用其他外部工具或库。
  2. 图像与视频捕获:JavaCV允许开发者从摄像头和视频文件中捕获图像和视频流。通过简单的几行代码,您就可以将图像或视频输入到Java应用程序中进行处理和分析。
  3. 图像处理和分析:JavaCV提供了各种图像处理和分析功能,包括图像过滤、边缘检测、直方图均衡化等。开发者可以利用这些功能来改进和优化图像,以及提取图像的特征。
  4. 特征检测和描述符:JavaCV支持多种特征检测和描述符算法,如SIFT(尺度不变特征转换)、SURF(加速稳健特征)和ORB(旋转不变性二进制)。这些算法可以用于目标识别、图像匹配和图像拼接等应用。
  5. 人脸检测和识别:JavaCV提供了人脸检测和识别功能,使开发者能够在Java应用程序中实现人脸相关的应用。您可以使用JavaCV来检测人脸、标记面部特征点,并进行人脸识别。
  6. 机器学习支持:JavaCV与深度学习框架OpenCV DNN集成,使开发者能够在Java中使用预训练的神经网络模型。这使得开发者可以轻松地进行图像分类、目标检测和图像分割等计算机视觉任务。
  7. 多媒体处理:JavaCV对音频和视频文件进行处理的能力也非常强大。它可以读取、写入和编辑各种音频和视频格式,同时还支持音频和视频流的处理。

总结起来,JavaCV是一个强大而多功能的Java开发库,用于实现计算机视觉和图像处理任务。它的集成性以及丰富的功能和应用使得开发者能够更方便地进行图像和视频处理,并构建出色的视觉应用程序。

代码教程

一、首先找两个人物的头像照片,分别用文件区分放置

6ec14d2178d345da9f604baa32cf2dc0.png

9e13042a305249e6b50972648dae2357.png

二,然后用java代码训练生成模型文件

首先maven中引入javacv依赖jar包

  1. <!-- https://mvnrepository.com/artifact/org.bytedeco/javacv-platform -->
  2. <dependency>
  3. <groupId>org.bytedeco</groupId>
  4. <artifactId>javacv-platform</artifactId>
  5. <version>1.5.5</version>
  6. </dependency>

java代码如下:

  1. import org.bytedeco.opencv.global.opencv_imgcodecs;
  2. import org.bytedeco.opencv.opencv_core.Mat;
  3. import org.bytedeco.opencv.opencv_core.MatVector;
  4. import org.bytedeco.opencv.opencv_core.Size;
  5. import org.bytedeco.opencv.opencv_face.FaceRecognizer;
  6. import org.bytedeco.opencv.opencv_face.FisherFaceRecognizer;
  7. import java.io.File;
  8. import java.io.IOException;
  9. import java.nio.IntBuffer;
  10. import java.util.LinkedList;
  11. import java.util.List;
  12. import static org.bytedeco.opencv.global.opencv_core.CV_32SC1;
  13. import static org.bytedeco.opencv.global.opencv_imgcodecs.IMREAD_GRAYSCALE;
  14. import static org.bytedeco.opencv.global.opencv_imgproc.resize;
  15. /**
  16. * @author willzhao
  17. * @version 1.0
  18. * @description 训练
  19. * @date 2021/12/12 18:26
  20. */
  21. public class FaceTrainDemo {
  22. /**
  23. * 从指定目录下
  24. * @param dirs
  25. * @param outputPath
  26. */
  27. private void train(String[] dirs, String outputPath) {
  28. int totalImageNums = 0;
  29. // 统计每个路径下的照片数,加在一起就是照片总数
  30. for(String dir : dirs) {
  31. List<String> files = getAllFilePath(dir);
  32. totalImageNums += files.size();
  33. }
  34. //todo截取人脸
  35. System.out.println("total : " + totalImageNums);
  36. // 这里用来保存每一张照片的序号,和照片的Mat对象
  37. MatVector imageIndexMatMap = new MatVector(totalImageNums);
  38. Mat lables = new Mat(totalImageNums, 1, CV_32SC1);
  39. // 这里用来保存每一张照片的序号,和照片的类别
  40. IntBuffer lablesBuf = lables.createBuffer();
  41. // 类别序号,从1开始,dirs中的每个目录就是一个类别
  42. int kindIndex = 1;
  43. // 照片序号,从0开始
  44. int imageIndex = 0;
  45. // 每个目录下的照片都遍历
  46. for(String dir : dirs) {
  47. // 得到当前目录下所有照片的绝对路径
  48. List<String> files = getAllFilePath(dir);
  49. // 处理一个目录下的每张照片,它们的序号不同,类别相同
  50. for(String file : files) {
  51. // imageIndexMatMap放的是照片的序号和Mat对象
  52. imageIndexMatMap.put(imageIndex, read(file));
  53. // bablesBuf放的是照片序号和类别
  54. lablesBuf.put(imageIndex, kindIndex);
  55. // 照片序号加一
  56. imageIndex++;
  57. }
  58. // 每当遍历完一个目录,才会将类别加一
  59. kindIndex++;
  60. }
  61. // 实例化人脸识别类
  62. FaceRecognizer faceRecognizer = FisherFaceRecognizer.create();
  63. // 训练,入参就是图片集合和分类集合
  64. faceRecognizer.train(imageIndexMatMap, lables);
  65. // 训练完成后,模型保存在指定位置
  66. faceRecognizer.save(outputPath);
  67. //释放资源
  68. faceRecognizer.close();
  69. }
  70. /**
  71. * 读取指定图片的灰度图,调整为指定大小
  72. * @param path
  73. * @return
  74. */
  75. private static Mat read(String path) {
  76. Mat faceMat = opencv_imgcodecs.imread(path,IMREAD_GRAYSCALE);
  77. resize(faceMat, faceMat, new Size(164, 164));
  78. return faceMat;
  79. }
  80. /**
  81. * 把指定路径下所有文件的绝对路径放入list集合中返回
  82. * @param path
  83. * @return
  84. */
  85. public static List<String> getAllFilePath(String path) {
  86. List<String> paths = new LinkedList<>();
  87. File file = new File(path);
  88. if (file.exists()) {
  89. // 列出该目录下的所有文件
  90. File[] files = file.listFiles();
  91. for (File f : files) {
  92. if (!f.isDirectory()) {
  93. // 把每个文件的绝对路径都放在list中
  94. paths.add(f.getAbsolutePath());
  95. }
  96. }
  97. }
  98. return paths;
  99. }
  100. public static void main(String[] args) throws IOException {
  101. String base = "D:\\face_img\\";
  102. // 存储图片的两个目录
  103. // man目录下保存了群众演员A的所有人脸照片,
  104. // woman目录下保存了群众演员B的所有人脸照片
  105. String[] dirs = {base + "msk", base + "tlp"};
  106. // 开始训练,并指定模型输出位置
  107. new FaceTrainDemo().train(dirs, base + "faceRecognizer.xml");
  108. }
  109. }

注意 dirs数组至少是两个。

idea编辑器右键run运行即可,会生成一个faceRecognizer.xml的模型文件。

java识别代码如下

kindNameMap的key是训练代码中dirs数组顺序,第一个是msk,第二个是tlp,以此类推。

  1. import org.bytedeco.javacv.Frame;
  2. import org.bytedeco.javacv.Java2DFrameConverter;
  3. import org.bytedeco.javacv.OpenCVFrameConverter;
  4. import org.bytedeco.opencv.opencv_core.*;
  5. import org.bytedeco.opencv.opencv_face.FaceRecognizer;
  6. import org.bytedeco.opencv.opencv_face.FisherFaceRecognizer;
  7. import org.bytedeco.opencv.opencv_objdetect.CascadeClassifier;
  8. import javax.imageio.ImageIO;
  9. import java.awt.image.BufferedImage;
  10. import java.io.File;
  11. import java.io.IOException;
  12. import java.util.HashMap;
  13. import java.util.Map;
  14. import static org.bytedeco.opencv.global.opencv_imgproc.*;
  15. /**
  16. * @author tarzan
  17. */
  18. public class FaceDemo {
  19. public static void main(String[] args) throws IOException {
  20. Map<Integer, String> kindNameMap=new HashMap<>(2);
  21. kindNameMap.put(1,"msk");
  22. kindNameMap.put(2,"tlp");
  23. faceRecognize("D:\\face_img\\test\\msk.jpg",kindNameMap);
  24. }
  25. /**
  26. * 调整后的文件宽度
  27. */
  28. public final static int RESIZE_WIDTH = 164;
  29. /**
  30. * 调整后的文件高度
  31. */
  32. public final static int RESIZE_HEIGHT = 164;
  33. /**
  34. * 超过这个置信度就明显有问题了
  35. */
  36. public final static double MAX_CONFIDENCE = 50d;
  37. public final static String frontalFaceModelPath="D:\\face_img\\lbpcascade_frontalface.xml";
  38. public final static String faceRecognizerPath="D:\\face_img\\faceRecognizer.xml";
  39. /**
  40. * 人脸检测
  41. *
  42. * @param filePath 图片路径
  43. */
  44. public static RectVector faceDetect(Mat grayImg) throws IOException {
  45. // 读取opencv人脸检测器
  46. CascadeClassifier cascade = new CascadeClassifier(frontalFaceModelPath);
  47. // 检测到的人脸
  48. RectVector faces = new RectVector();
  49. //多人脸检测
  50. cascade.detectMultiScale(grayImg, faces);
  51. return faces;
  52. }
  53. /**
  54. * 人脸识别
  55. *
  56. * @param kindNameMap 人物名称集合
  57. */
  58. public static void faceRecognize(String filePath,Map<Integer, String> kindNameMap) throws IOException {
  59. File file=new File(filePath);
  60. BufferedImage image = ImageIO.read(file);
  61. Java2DFrameConverter imageConverter = new Java2DFrameConverter();
  62. Frame frame = imageConverter.convert(image);
  63. //类型转换
  64. OpenCVFrameConverter.ToMat converter = new OpenCVFrameConverter.ToMat();
  65. Mat original = converter.convertToMat(frame);
  66. //存放灰度图
  67. Mat grayImg = new Mat();
  68. //模式设置成ImageMode.Gray下不需要再做灰度 摄像头获取的是彩色图像,所以先灰度化下
  69. cvtColor(original, grayImg, COLOR_BGRA2GRAY);
  70. // 均衡化直方图
  71. equalizeHist(grayImg, grayImg);
  72. RectVector faces=faceDetect(grayImg);
  73. // 遍历人脸
  74. for (int i = 0; i < faces.size(); i++) {
  75. Rect face_i = faces.get(i);
  76. //绘制人脸矩形区域,scalar色彩顺序:BGR(蓝绿红)
  77. rectangle(original, face_i, new Scalar(0, 255, 0, 1));
  78. int pos_x = Math.max(face_i.tl().x() - 10, 0);
  79. int pos_y = Math.max(face_i.tl().y() - 10, 0);
  80. oneFaceRecognize(grayImg,face_i,kindNameMap);
  81. // 在人脸矩形上方绘制提示文字(中文会乱码)
  82. putText(original, "people face", new Point(pos_x, pos_y), FONT_HERSHEY_COMPLEX, 1.0, new Scalar(0, 0, 255, 2.0));
  83. }
  84. frame = converter.convert(original);
  85. image = imageConverter.convert(frame);
  86. String fileName=file.getName();
  87. String extension=fileName.substring(fileName.lastIndexOf(".")+1);
  88. String newFileName=fileName.substring(0,fileName.lastIndexOf("."))+"_result."+extension;
  89. ImageIO.write(image, extension, new File(file.getParent()+File.separator+newFileName));
  90. }
  91. /**
  92. * 人脸识别
  93. *
  94. * @param kindNameMap 人物名称集合
  95. */
  96. public static String oneFaceRecognize(Mat grayImg,Rect face,Map<Integer, String> kindNameMap){
  97. String kindName=null;
  98. Mat mat=new Mat(grayImg, face);
  99. Size size= new Size(RESIZE_WIDTH, RESIZE_HEIGHT);
  100. // 核心代码,把检测到的人脸拿去识别
  101. // 调整到和训练一致的尺寸
  102. resize(mat, mat, size);
  103. // 推理结果的标签
  104. int[] labels = new int[1];
  105. // 推理结果的置信度
  106. double[] confidences = new double[1];
  107. try {
  108. // 推理(这一行可能抛出RuntimeException异常,因此要补货,否则会导致程序退出)
  109. FaceRecognizer faceRecognizer= FisherFaceRecognizer.create();
  110. // 加载的是训练时生成的模型
  111. faceRecognizer.read(faceRecognizerPath);
  112. // 设置门限,这个可以根据您自身的情况不断调整
  113. faceRecognizer.setThreshold(MAX_CONFIDENCE);
  114. //人脸检测
  115. faceRecognizer.predict(mat, labels, confidences);
  116. } catch (RuntimeException runtimeException) {
  117. runtimeException.printStackTrace();
  118. }
  119. // 得到分类编号后,从map中取得名字,用来显示
  120. if (kindNameMap.containsKey(labels[0])) {
  121. kindName = String.format("%s, confidence : %.4f", kindNameMap.get(labels[0]), confidences[0]);
  122. } else {
  123. // 取不到名字的时候,就显示unknown
  124. kindName = "unknown(" + labels[0] + ")";
  125. }
  126. System.out.println(kindName);
  127. return kindName;
  128. }
  129. }

右键运行,即可。

注意事项:

1.文件路径最好不要用中文。

2.图片格式不要自己随便改后缀,否则有可能读取不到图片。

相关文章推荐

JavaCV 实现图片中人脸检测完整代码教程_洛阳泰山的博客-CSDN博客_javacv人脸匹配

发表评论

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

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

相关阅读

    相关 Javacv人脸识别算法EigenFace

    这是我当年在安卓上用的一个人脸识别的算法。主要是用了PCA降维的方式,然后用欧式距离比较下最近的人脸。 趁热来一波刚出炉的Javacv写的特征脸算法,写得不是很好,但是也是费