写点什么

Java 实现人脸检测,oppojava 后端面试几面

作者:Java高工P7
  • 2021 年 11 月 10 日
  • 本文字数:4488 字

    阅读完需:约 15 分钟

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));


}


/**


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


  • 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(dxdx+dydy);


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());


//生成图片为 PNG


ImageIO.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();// 释放图形上下文使用的系统资源


//生成图片为 PNG


ImageIO.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;

用户头像

Java高工P7

关注

还未添加个人签名 2021.11.08 加入

还未添加个人简介

评论

发布
暂无评论
Java实现人脸检测,oppojava后端面试几面