一、前言

之前上传了一个资源,就是Java实现人脸检测,发现很多人都不会用,就是这个https://download.csdn.net/download/b379685397/10023135。各种乱七八糟评论都有,那就如大家所愿,我发个教程吧。

当前很多博客实现人脸识别的大部分都是调用云厂家的接口,如百度,阿里云。以及我们乐橙开放平台也支持人脸识别等人工智能服务。这些都比较简单,会接开放平台,走接口请求基本上都掌握了。缺点就是有限制,收费。

那么我就在想,能不能不依赖第三方,自己实现人脸检测呢。搜索了相关开源软件,发现有几款比较合适,如openCV,SeetaFaceEngine,openface等。经测试,SeetaFaceEngine准确率最高,因为模型经过大量训练。但存在内存泄漏问题。应该是底层库没有处理好(猜测,没有深究)。openCV对JAVA支持性最好,但准确率差点。需要自己调参不断尝试。

接下来,开始使用Java+openCV实现人脸识别和人眼识别等功能.

其实功能比较简单,主要就是使用了openCV,默认训练好的分类器。接下来进入正片。

二、openCV安装

1、opencv下载

打开opencv官网https://opencv.org/releases/。下载opencv。我使用的是3.43版本。本地为windows、所以选择windows的3.43版本。按照自己的需求进行下载。

2、安装openCV

安装比较简单,一直下一步即可。但记得修改安装路径。

3、openCV重要目录

安装好opencv之后,有build以及source目录。

build目录如下。有对应支持的语言的dll库和引用包。

sources\data目录下,存放着为opencv实现的各种分类器。我们需要使用的人脸和人眼检测的分类器都在里面。如果想详细了解的话可以在opencv的官网里进行查看。

三、工程搭建

人脸识别项目已经上传github,大家可以进行下载导入,下载地址为https://github.com/379685397/FaceDetect。可以的话,帮忙加个星啊亲~。哈哈

1、工程目录

config目录存放的为opencv的分类器。此处使用了正面人脸以及人眼的分类器。

func为实现人脸相关接口

image存放的为测试用图片

tmp为测试使用输出图片。

lib里包含opencv的使用jar包和本地dll库。

工程导入完成之后,需要配置对应的jar包以及修改JDK。

IDEA的话通过file->Project Structure进行设置。选中加号,选择外部jar包引用。选择工程里lib目录下的openCV343.jar。

之后重新编译。看是否报错。没有报错的话项目导入成功

2、代码实现

1、DetectFace

package com.facedetect.func;import org.opencv.core.*;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;/*** @Auther: DarkKing* @Date: 2019/10/2 11:06* @Description:*/
public class DetectFace {//定义程序的基础路径private String basePath =System.getProperty("user.dir");//人眼识别分类器路径private   String eyeConfigPath=basePath+"\\src\\com\\facedetect\\config\\haarcascade_eye_tree_eyeglasses.xml";//人脸识别分类器路径private   String faceConfigPath=basePath+"\\src\\com\\facedetect\\config\\haarcascade_frontalface_alt2.xml";static{// 载入opencv的库String opencvpath = System.getProperty("user.dir") + "\\libs\\x64\\";String opencvDllName = opencvpath + Core.NATIVE_LIBRARY_NAME + ".dll";System.load(opencvDllName);}/*** opencv实现人脸识别* @param imagePath* @param outFile* @throws Exception*/public  void detectFace(String imagePath,  String outFile) throws Exception{System.out.println("Running DetectFace ...,config path is  "+faceConfigPath);String basePath =System.getProperty("user.dir");String path= basePath+ "\\src\\com\\facedetect\\tmp\\";// 从配置文件lbpcascade_frontalface.xml中创建一个人脸识别器,该文件位于opencv安装目录中,为了方便从安装方便放到了程序路径里CascadeClassifier faceDetector = new CascadeClassifier(faceConfigPath);//创建图片处理对象Mat image = Imgcodecs.imread(imagePath);// 在图片中检测人脸MatOfRect faceDetections = new MatOfRect();//多条件结果检测faceDetector.detectMultiScale(image, faceDetections);System.out.println(String.format("Detected %s faces", faceDetections.toArray().length));//检测结果集Rect[] rects = faceDetections.toArray();// 在每一个识别出来的人脸周围画出一个方框for (int i = 0; i < rects.length; i++) {Rect rect = rects[i];Imgproc.rectangle(image, new Point(rect.x-2, rect.y-2),new Point(rect.x + rect.width, rect.y + rect.height),new Scalar(0, 255, 0));Mat copy = new Mat(image,rect);Mat temp  = new Mat();copy.copyTo(temp);//输出图片Imgcodecs.imwrite(path+i+".png", temp);}Imgcodecs.imwrite(outFile, image);System.out.println(String.format("人脸识别成功,人脸图片文件为: %s", outFile));}/*** opencv实现人眼识别* @param imagePath* @param outFile* @throws Exception*/public  void detectEye(String imagePath,  String outFile) throws Exception {System.out.println("Running DetectFace ...,config path is  "+eyeConfigPath);CascadeClassifier eyeDetector = new CascadeClassifier(eyeConfigPath);Mat image = Imgcodecs.imread(imagePath);  //读取图片// 在图片中检测人脸MatOfRect faceDetections = new MatOfRect();eyeDetector.detectMultiScale(image, faceDetections, 2.0,1,1,new Size(20,20),new Size(20,20));System.out.println(String.format("Detected %s eyes", faceDetections.toArray().length));Rect[] rects = faceDetections.toArray();if(rects != null && rects.length <2){throw new RuntimeException("不是一双眼睛");}Rect eyea = rects[0];Rect eyeb = rects[1];System.out.println("a-中心坐标 " + eyea.x + " and " + eyea.y);System.out.println("b-中心坐标 " + eyeb.x + " and " + eyeb.y);//获取两个人眼的角度double dy=(eyeb.y-eyea.y);double dx=(eyeb.x-eyea.x);double len=Math.sqrt(dx*dx+dy*dy);System.out.println("dx is "+dx);System.out.println("dy is "+dy);System.out.println("len is "+len);double angle=Math.atan2(Math.abs(dy),Math.abs(dx))*180.0/Math.PI;System.out.println("angle is "+angle);for(Rect rect:faceDetections.toArray()) {Imgproc.rectangle(image, new Point(rect.x, rect.y), new Point(rect.x+ rect.width, rect.y + rect.height), new Scalar(0, 255, 0));}Imgcodecs.imwrite(outFile, image);System.out.println(String.format("人眼识别成功,人眼图片文件为: %s", outFile));}
}

该函数主要实现了两个方法,一个是人脸检测,一个是人眼检测。方法都差不多。主要是加载的分类器不同。以及结果集的过滤。其中重要的一个方法时是MatOfRect的detectMultiScale方法。该方法共有7个参数。含义如下。

  • 参数1:image--待检测图片,一般为灰度图像加快检测速度;
  • 参数2:objects--被检测物体的矩形框向量组;
  • 参数3:scaleFactor--表示在前后两次相继的扫描中,搜索窗口的比例系数。默认为1.1即每次搜索窗口依次扩大10%;
  • 参数4:minNeighbors--表示构成检测目标的相邻矩形的最小个数(默认为3个)。        如果组成检测目标的小矩形的个数和小于 min_neighbors - 1 都会被排除。       如果min_neighbors 为 0, 则函数不做任何操作就返回所有的被检候选矩形框,        这种设定值一般用在用户自定义对检测结果的组合程序上;
  • 参数5:flags--要么使用默认值,要么使用CV_HAAR_DO_CANNY_PRUNING,如果设置为          CV_HAAR_DO_CANNY_PRUNING,那么函数将会使用Canny边缘检测来排除边缘过多或过少的区域,       因此这些区    域通常不会是人脸所在区域;
  • 参数6、7:minSize和maxSize用来限制得到的目标区域的范围。

2、ImageUtils

package com.facedetect.func;import org.opencv.core.Mat;
import org.opencv.core.Rect;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;/*** @Auther: DarkKing* @Date: 2019/10/2 11:12* @Description:*/
public class ImageUtils {/*** 裁剪图片并重新装换大小* @param imagePath* @param posX* @param posY* @param width* @param height* @param outFile*/public static void imageCut(String imagePath,String outFile, int posX,int posY,int width,int height ){//原始图像Mat image = Imgcodecs.imread(imagePath);//截取的区域:参数,坐标X,坐标Y,截图宽度,截图长度Rect rect = new Rect(posX,posY,width,height);//两句效果一样Mat sub = image.submat(rect);   //Mat sub = new Mat(image,rect);Mat mat = new Mat();Size size = new Size(300, 300);Imgproc.resize(sub, mat, size);//将人脸进行截图并保存Imgcodecs.imwrite(outFile, mat);System.out.println(String.format("图片裁切成功,裁切后图片文件为: %s", outFile));}/**** @param imagePath* @param outFile*/public static void setAlpha(String imagePath,  String outFile) {/*** 增加测试项* 读取图片,绘制成半透明*/try {ImageIcon imageIcon = new ImageIcon(imagePath);BufferedImage bufferedImage = new BufferedImage(imageIcon.getIconWidth(),imageIcon.getIconHeight(), BufferedImage.TYPE_4BYTE_ABGR);Graphics2D g2D = (Graphics2D) bufferedImage.getGraphics();g2D.drawImage(imageIcon.getImage(), 0, 0, imageIcon.getImageObserver());//循环每一个像素点,改变像素点的Alpha值int alpha = 100;for (int j1 = bufferedImage.getMinY(); j1 < bufferedImage.getHeight(); j1++) {for (int j2 = bufferedImage.getMinX(); j2 < bufferedImage.getWidth(); j2++) {int rgb = bufferedImage.getRGB(j2, j1);rgb = ( (alpha + 1) << 24) | (rgb & 0x00ffffff);bufferedImage.setRGB(j2, j1, rgb);}}g2D.drawImage(bufferedImage, 0, 0, imageIcon.getImageObserver());//生成图片为PNGImageIO.write(bufferedImage, "png",  new File(outFile));System.out.println(String.format("绘制图片半透明成功,图片文件为: %s", outFile));}catch (Exception e) {e.printStackTrace();}}/*** 为图像添加水印* @param buffImgFile 底图* @param waterImgFile 水印* @param outFile 输出图片* @param alpha   透明度* @throws IOException*/private static void watermark(String buffImgFile,String waterImgFile,String outFile, float alpha) throws IOException {// 获取底图BufferedImage buffImg = ImageIO.read(new File(buffImgFile));// 获取层图BufferedImage waterImg = ImageIO.read(new File(waterImgFile));// 创建Graphics2D对象,用在底图对象上绘图Graphics2D g2d = buffImg.createGraphics();int waterImgWidth = waterImg.getWidth();// 获取水印层图的宽度int waterImgHeight = waterImg.getHeight();// 获取水印层图的高度// 在图形和图像中实现混合和透明效果g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));// 绘制g2d.drawImage(waterImg, 0, 0, waterImgWidth, waterImgHeight, null);g2d.dispose();// 释放图形上下文使用的系统资源//生成图片为PNGImageIO.write(buffImg, "png",  new File(outFile));System.out.println(String.format("图片添加水印成功,图片文件为: %s", outFile));}/*** 图片合成* @param image1* @param image2* @param posw* @param posh* @param outFile* @return*/public static void simpleMerge(String image1, String image2, int posw, int posh, String outFile) throws IOException{// 获取底图BufferedImage buffImg1 = ImageIO.read(new File(image1));// 获取层图BufferedImage buffImg2 = ImageIO.read(new File(image2));//合并两个图像int w1 = buffImg1.getWidth();int h1 = buffImg1.getHeight();int w2 = buffImg2.getWidth();int h2 = buffImg2.getHeight();BufferedImage imageSaved = new BufferedImage(w1, h1, BufferedImage.TYPE_INT_ARGB); //创建一个新的内存图像Graphics2D g2d = imageSaved.createGraphics();g2d.drawImage(buffImg1, null, 0, 0);  //绘制背景图像for (int i = 0; i < w2; i++) {for (int j = 0; j < h2; j++) {int rgb1 = buffImg1.getRGB(i + posw, j + posh);int rgb2 = buffImg2.getRGB(i, j);/*if (rgb1 != rgb2) {rgb2 = rgb1 & rgb2;}*/imageSaved.setRGB(i + posw, j + posh, rgb2); //修改像素值}}ImageIO.write(imageSaved, "png", new File(outFile));System.out.println(String.format("图片合成成功,合成图片文件为: %s", outFile));}
}

改类为文件处理类。

3、DetectFaceTest 测试类

package com.facedetect;import java.awt.AlphaComposite;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;import javax.imageio.ImageIO;
import javax.swing.ImageIcon;import com.facedetect.func.DetectFace;
import com.facedetect.func.ImageUtils;
import com.sun.imageio.plugins.common.ImageUtil;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;/*** DrakKing*/
public class DetectFaceTest {public static void main(String[] args) throws Exception {DetectFace df = new DetectFace();String basePath =System.getProperty("user.dir");String s1= basePath+ "\\src\\com\\facedetect\\image\\test1.jpg";String s2= basePath+ "\\src\\com\\facedetect\\image\\test2.jpg";String s3= basePath+ "\\src\\com\\facedetect\\image\\test3.jpg";String e1= basePath+ "\\src\\com\\facedetect\\image\\1.png";String faceTemp = basePath+"\\src\\com\\facedetect\\tmp\\faceTemp.png";String eyeTemp = basePath+"\\src\\com\\facedetect\\tmp\\eyeTemp.png";//人脸识别df.detectFace(s1, faceTemp);//人眼识别df.detectEye(e1,  eyeTemp);//图片裁切// ImageUtils.imageCut(s3,temp, 50, 50,100,100);//设置图片为半透明
//        ImageUtils.setAlpha(s, temp);//为图片添加水印
//        ImageUtils.watermark(s,"E:\\ling.jpg",temp, 0.2f);//图片合成
//        ImageUtils.simpleMerge(s, "E:\\ling.jpg", 45, 50, temp);}
}

4、测试结果

测试拿test1图片做人脸测试,1.png做人眼测试。查看输出结果

执行DetectFaceTest。查看结果。人脸检测到3张。人眼检测到一张。

图片输出

到这教程就结束了,在实际使用过程中,我发现人眼识别准确率很低。可能是我的参数有问题。大家可以多进行测试一下。

Java实现人脸检测相关推荐

  1. Java版人脸检测详解上篇:运行环境的Docker镜像(CentOS+JDK+OpenCV)

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 如果您看过<三分钟极速体验:Java版 ...

  2. Java版人脸检测详解下篇:开发java应用并做成docker镜像

    本篇概览 如果您看过<Java版人脸检测上篇>一文,甚至动手实际操作过,那么你应该会对背后的技术细节感兴趣,开发这样一个应用,咱们总共要做以下三件事: 1.准备好docker基础镜像 2. ...

  3. Java版人脸检测详解下篇:编码

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 如果您看过<三分钟极速体验:Java版 ...

  4. 三分钟极速体验:Java版人脸检测

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 检测照片中的人脸,用Java可以实现吗? 当 ...

  5. Java实现人脸检测,java线程教程

    @Auther: DarkKing @Date: 2019/10/2 11:06 @Description: */ public class DetectFace { //定义程序的基础路径 priv ...

  6. 人工智能Java SDK:人脸检测,应用于包括人脸门禁系统、刷脸支付等各行各业

    人脸检测SDK 人脸识别 广义的人脸识别实际包括构建人脸识别系统的一系列相关技术,包括人脸图像采集.人脸定位.人脸识别预处理.身份确认以及身份查找等: 而狭义的人脸识别特指通过人脸进行身份确认或者身份 ...

  7. 使用卷积神经网络(CupCnn)训练人脸检测模型

    结果展示 最近尝试做了下人脸检测,先上两张效果图吧: 这已经是跳出来的效果比较好的图片了,表现的确是有点差. 我用了4000(19*19)多张人脸图片和8000(19*19)多张非人脸图片训练出了这个 ...

  8. Day 12: OpenCV —— Java开发者的人脸检测

    今天我准备学习如何用Java来进行人脸检测.人脸检测有助于在任何数字图像上识别人脸,在做了一些研究后,我发现OpenCV的库可以帮我检测图像中的人脸.不过,我没能找到一个完整的通过Java使用Open ...

  9. java r$_基于javacv的人脸检测Demo

    [实例简介] 基于javacv的人脸检测Demo,参考文章:http://blog.csdn.net/viviwen123/article/details/6386302#reply [实例截图] [ ...

最新文章

  1. 预告|开源操作系统年度技术会议
  2. 中小企业信息化--网页设计模拟题1
  3. SSPL的MongoDB再被抛弃,GUN Health也合流PostgreSQL
  4. java h5获取ip,websocket中获取客户端通信的真实IP
  5. 【P1326】超级教主
  6. Java Socket实战之三:传输对象
  7. java斗破苍穹游戏阵容,斗破苍穹手游竞技场阵容搭配解析 最强阵容你知道吗
  8. 015_ICMP专项研究监控
  9. 基于canvas的视频遮罩插件
  10. 怎么做一张优雅的数据源监控报表
  11. Java将每半年发布一个版本
  12. spring boot集成swagger2
  13. MyBatis中出现Mapped Statements collection does not contain value 问题
  14. JQuery实战图片特效-遁地龙卷风
  15. win7录屏_谁说Windows7没有自带录屏功能?教你一招轻松录制,不会用可惜了
  16. 如何写出有吸引力的软文?经典软文案例分析
  17. mysql查询结果百分比表示_MySQL 查询结果以百分比显示简单实现
  18. 专利检索及分析模拟登陆(python)
  19. 在线超级计算器(微积分、方程)
  20. 字符及字符串(数字串)输入输出字符串处理函数

热门文章

  1. JavaScript 日期对象
  2. YOLOV5使用(一): docker跑通,详解TensorRT下plugin的onnx
  3. 2022年32篇最佳AI论文:DALL·E 2、Stable Diffusion、ChatGPT等入选
  4. JAVA整蛊朋友小游戏之屎王争霸赛
  5. DDD领域驱动设计-为什么要用DDD
  6. Http、Ftp、SQLServer默认的端口号是多少?
  7. IOCP 简单的完成端口读写文件
  8. 关掉vs2003 Disassembly 窗口
  9. 从注册表中获取文件的安装路径
  10. pycharm中的子类重写符号