opencv
基于Opencv-java的人脸分析----后端之前帮同学做了一个轮廓位点计算的小软件,用到了opencv,看到可以进行人脸识别,感觉挺有趣的就摸索了一阵子。这里就做一个总结记录,以便日后查阅1.什么是opencv?OpenCV的全称是Open Source Computer Vision Library,是一个跨平台的计算机视觉库。OpenCV是由英特尔公司发起并参与开发,以BSD许可证授权发行
基于Opencv-java的人脸分析----后端
之前帮同学做了一个轮廓位点计算的小软件,用到了opencv,看到可以进行人脸识别,感觉挺有趣的 就摸索了一阵子。这里就做一个总结记录,以便日后查阅
1.什么是opencv?
OpenCV的全称是Open Source Computer Vision Library,是一个跨平台的计算机视觉库。OpenCV是由英特尔公司发起并参与开发,以BSD许可证授权发行,可以在商业和研究领域中免费使用。OpenCV可用于开发实时的图像处理、计算机视觉以及模式识别程序。该程序库也可以使用英特尔公司的IPP进行加速处理。(该段内容来自于维基百科https://zh.wikipedia.org/wiki/OpenCV)
2.准备
java使用opencv的话 一般来说分为常见的两种,一种是官网下载导入jar包,还有一种就是引用maven依赖
2.1官网下载https://opencv.org/releases/
根据自身使用的环境去进行选择相应的下载,下载完成后是一个exe文件,安装完成后进入如下目录下
其中opencv-451.jar 就是我们所需要的jar包,而x64和x86是对应64位和32位系统所需要的 dll文件。
缺点:
- 目前该jar包中是缺少OpenCv Contrib的,而人脸识别中的FaceRecognizer 都是来自于它的,如果需要 需自行编译
2.2导入maven依赖
一般选择的依赖有 opencv和opencv-platform
前者的缺点和上面一样,缺少一些类,而后者的缺点在于,打包后,jar包过于臃肿,有400多M
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>opencv</artifactId>
<version>4.5.1-1.5.5</version>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>opencv-platform</artifactId>
<version>4.5.1-1.5.5</version>
</dependency>
如果是选择jar包导入的 或者 opencv依赖的 需要加载opencv_java451.dll 具体措施 可以自行百度或者在底下评论
3.项目开始(基于opencv的人脸识别)
这里我选择的是通过maven引入依赖,因为需要用到LBPHFaceRecognizer,所以暂定先用opencv-platform,如果用更好的方法,欢迎大家的底下评论
3.1项目开始前,先谈一下之后要选择的FaceRecognizer,目前opencv提供的有三种主要是:
我这里选择用的是LBPH,原因在于 其他两种是不支持更新的,只有LBPH才支持。
3.2大体步骤
一个完整的人脸识别,分为人脸训练+人脸识别,人脸训练的主要目的是,便于机器去识别。
比如一个新人入职,会首先将自己的人脸或者指纹和名字录入进系统,这样当下一次打卡时,就可以根据人脸或者指纹比对当前打卡人是谁,这里的原理是互通。
Tips:进行训练的人脸 需要先转化为大小相同的灰度图,之后再进行训练,具体的方法为opencv的 resize,否则的话可能会抛出一些异常 如: 大小超出32400 这里的size的值,可以自行定义
opencv_imgproc.resize(mat,mat,new Size(180,180));
在进行训练和更新时,如果需要加上
Loader.load(opencv_java.class);
-
train
-
/** * LBph 训练 * * @param source source 为样本图片的绝对地址的map 键为对应的样本名 值为绝对地址 */ public static void train(Map<String, List<String>> source) { //创建一个FaceRecognizer LBPHFaceRecognizer faceRecognizer = LBPHFaceRecognizer.create(); //sum 为 训练样本总数 int sum = 0; for (String faceName : source.keySet()) { final List<String> faces = source.get(faceName); sum += faces.size(); } log.info("total face:{}", sum); Mat labels = new Mat(sum, 1, opencv_core.CV_32SC1); //开辟一个给定初始大小的matVector 用来存放mat MatVector images = new MatVector(sum); //设置标签 //这里的1 是代表 标签的序号的 比如1代表胡歌 2 代表黄晓明 。。。 更新的话只要接着下面的数就行 setLabels(source, images, labels, 1); //进行训练 faceRecognizer.train(images, labels); //保存 faceRecognizer.save("D:\\desk\\project\\opencv_lesson412\\model\\lbph_face_model.xml"); }
-
-
update
-
/** * 更新 * * @param source . */ public static void update(Map<String, List<String>> source) { final LBPHFaceRecognizer faceRecognizer = LBPHFaceRecognizer.create(); //如果不先读取对应的xml文件的话 是无法进行更新的 会将原来的 覆盖掉 faceRecognizer.read("D:\\desk\\project\\opencv_lesson412\\model\\lbph_face_model.xml"); int sum = 0; for (String faceName : source.keySet()) { final List<String> faces = source.get(faceName); sum += faces.size(); } log.info("total face:{}", sum); //开辟一个给定初始大小的matVector 用来存放mat MatVector images = new MatVector(sum); //final int length = labels.getIntBuffer().array().length; Mat labels = new Mat(sum, 1, opencv_core.CV_32SC1); // kind 这个值根据 自己的业务设计 这里只是演示 setLabels(source, images, labels, 4); faceRecognizer.update(images, labels); faceRecognizer.save("D:\\desk\\project\\opencv_lesson412\\model\\lbph_face_model.xml"); }
-
-
recognizer
-
/** * 人脸识别 * * @param filePath 图片绝对路径 * @param threshold 人脸识别的阈值 */ public static void faceRecognizer(String filePath, double threshold) { LBPHFaceRecognizer faceRecognizer = LBPHFaceRecognizer.create(); //读取训练好的xml文件 faceRecognizer.read("model/lbph_face_model.xml"); //设置阈值 //阈值越低则识别的越严格,阈值越高则识别的越容易 但错误率也会提高 //在进行是别的时候 宁愿识别的严格一点 让错误率低一些。 //我一般设置在50-70左右 faceRecognizer.setThreshold(threshold); //级联分类器 获取人脸识别模型 可以从该网址中获取 或者自己训练得到 //https://github.com/opencv/opencv/tree/master/data/haarcascades CascadeClassifier cascadeClassifier = new CascadeClassifier(); cascadeClassifier.load("model/haarcascade_frontalface_alt.xml"); //进行是别的人脸需要转化为灰度图 final Mat grayImage = opencv_imgcodecs.imread(filePath, opencv_imgcodecs.IMREAD_GRAYSCALE); //直方图 opencv_imgproc.equalizeHist(grayImage, grayImage); RectVector faces = new RectVector(); cascadeClassifier.detectMultiScale(grayImage, faces); //标签 IntPointer label = new IntPointer(1); //置信率 DoublePointer confidence = new DoublePointer(1); //识别的时候 有可能出现的问题 就是 明明是一张脸 但是却识别出了 两张 出来, 可能得到两个不同的结果 for (Rect face : faces.get()) { final Mat apply = grayImage.apply(face); opencv_imgproc.resize(apply, apply, new Size(180, 180)); faceRecognizer.predict(apply, label, confidence); final int i = label.get(0); final double v = confidence.get(0); String name; System.out.println(i); if (i == 1) { name = "黄家驹"; } else if (i == 2) { name = "胡歌"; } else if (i == 3) { name = "lujy"; } else if (i == 4) { name = "tf-boys"; } else { name = null; System.out.println("识别失败"); } }
-
-
setLables
-
static void setLabels(Map<String, List<String>> source, MatVector images, Mat labels, int kind) { int kindIndex = kind; int index = 0; final IntBuffer buffer = labels.createBuffer(); for (String faceName : source.keySet()) { final List<String> faces = source.get(faceName); for (String face : faces) { //存放每一张图片的序号和每种图片序号 buffer.put(index, kindIndex); final Mat imread = opencv_imgcodecs.imread(face, 0); //存放每一张图片的 mat images.put(index++, imread); } kindIndex++; } }
-
4.总结
之前刚开始摸索的时候遇到过许多的问题,但是没有具体记录,如果有小伙伴遇到了什么无法解决的问题 可以底下评论大家一起讨论解决。总得来说的话,人脸识别虽然成功了 但是 由于环境原因和其他一些原因,还是会有一些误差。之后的话,可能会考虑和web端关联 做一个人脸考勤系统。
更多推荐
所有评论(0)