前言:
公司前期有图片上传需求,已经满足,然后在此基础上又要求实现人脸检测,这时我懵逼了呀,没做过这呀,这不是难为我吗?我们用的还是H5页面,于是一顿网上查找资料,最终决定使用opencv.
正文:
1 首先导入maven jar包
<dependency>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>opencv-platform</artifactId>
<version>3.4.1-1.4.1</version>
</dependency>
2 opencv下载,并将一些文件放置项目
首先需要安装opcv opcv官网下载链接,在这里下载版本要和maven里的版本区别不能太大,我曾经因为版本相差太大,调试了好久才发现这个问题。
下载完之后,进行安装。安装比较简单,直接装就行。
1 获取opencv dll文件,放到到项目里。
根据下方图片找到java需要用到的dll文件,
然后我这里放的位置是web-inf下面,当然也可以放到其他位置,只要能读取到就行。
2 项目里读取dll文件,并且放到环境变量中。
这里我是放到了filter里,在项目启动的时候就加载。
public class InitOpencv implements ServletContextListener {
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
}
public void contextInitialized(ServletContextEvent arg0) {
// 1 如果服务器装了opencv,则直接用这个就行
//System.load("D:/opencv/opencv/build/java/x64/opencv_java341.dll");
//2 如果没装 则用此方法
//获取存放dll文件的绝对路径(假设将dll文件放在系统根目录下的WEB-INF文件夹中)
String path=arg0.getServletContext().getRealPath("WEB-INF");
//将此目录添加到系统环境变量中
addDirToPath(path);
//加载相应的dll文件,注意要将'\'替换为'/'
System.load(path.replaceAll("\\\\","/")+"/opencv_java341.dll");
}
private void addDirToPath(String s){
try {
//获取系统path变量对象
Field field=ClassLoader.class.getDeclaredField("sys_paths");
//设置此变量对象可访问
field.setAccessible(true);
//获取此变量对象的值
String[] path=(String[])field.get(null);
//创建字符串数组,在原来的数组长度上增加一个,用于存放增加的目录
String[] tem=new String[path.length+1];
//将原来的path变量复制到tem中
System.arraycopy(path,0,tem,0,path.length);
//将增加的目录存入新的变量数组中
tem[path.length]=s;
//将增加目录后的数组赋给path变量对象
field.set(null,tem);
} catch (Exception e) {
e.printStackTrace();
}
}
}
3在web.xml里加入listener
<listener>
<listener-class>com.ejoysoft.ecton.web.filter.InitOpencv</listener-class>
</listener>
2 人脸检测器放置项目里
根据此目录将人脸检测器xml放到项目里,这里我放的位置是资源文件里resources/propertites
到此,要做的环境准备工作以ok,下面是调用代码:
@Value("classpath:properties/haarcascade_frontalface_alt.xml")
private Resource xml;
public int check(MultipartFile file, HttpServletRequest request,String userNo) {
try {
log.info("人脸检测开始……");
String path = request.getSession().getServletContext().getRealPath("/") + "/static/images/upload/opencv/";
File targetXmlFile = new File(path + xml.getFilename() + "");
FileUtils.copyInputStreamToFile(xml.getInputStream(), targetXmlFile);
CascadeClassifier faceDetector = new CascadeClassifier(targetXmlFile.toString());
if (faceDetector.empty()) {
log.info("请引入文件……");
return 0;
}
// 创建图片tempFile
// File tempFile = new File(path + file.getOriginalFilename() + "");
File tempFile = new File(path + userNo + ".jpg");
FileUtils.copyInputStreamToFile(file.getInputStream(), tempFile);
// 读取创建的图片tempFile
Mat image = Imgcodecs.imread(tempFile.toString());
MatOfRect faceDetections = new MatOfRect();
// 进行人脸检测
faceDetector.detectMultiScale(image, faceDetections);
int checkNum = faceDetections.toArray().length;
log.info("检测到人脸{}",checkNum);
if (checkNum>0&& tempFile.exists() && tempFile.isFile()) {
if (tempFile.delete()) {
log.info("删除临时文件{}成功!",tempFile);
}
}
// System.out.println(String.format("检测到人脸: %s", faceDetections.toArray().length));
return checkNum;
} catch (IOException e) {
log.info("人脸检测失败{}",e);
return 0;
}
}
在后台图片上传地方,先调用此方法检测照片是否有人脸,如果有进行原先逻辑保存图片,没有检测到返给前端。
在我使用的过程中,有时候检测不是很精确,但是大部分情况下是ok的。