Java利用opencv实现人脸识别
0
opencv下载地址:https://opencv.org/releases.html
下载后安装,找到安装目录下:/opencv/build/java/
,这个目录下面存放的就是Java的jar和所需要的dll。
然后还需要探测器:/opencv/build/etc/
,这个目录下面的xml配置文件。
下面是代码:
package com.acgist.face;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import javax.imageio.ImageIO;
import org.opencv.core.CvType;
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.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;
/**
* 人脸探测
*/
public class Face {
private static final String DDL_PATH = "/opencv/opencv_java341.dll";
private static final String XML_PATH = "/opencv/haarcascade_frontalface_alt.xml";
public static void main(String[] args) throws URISyntaxException, IOException {
// System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
System.load(localPath(DDL_PATH));
Mat image = openImage("/face/csol01.jpg");
// Mat image = openImage("/face/崔智云.jpg");
CascadeClassifier faceDetector = new CascadeClassifier(localPath(XML_PATH));
MatOfRect faceDetections = new MatOfRect();
faceDetector.detectMultiScale(image, faceDetections);
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));
}
String filename = "ouput.png";
Imgcodecs.imwrite(filename, image);
System.out.println("over");
}
public static final Mat openImage(String name) throws IOException {
// 不能读取含有中文的文件
// String path = Face.class.getResource(name).getPath().substring(1);
// Mat image = Imgcodecs.imread(path);
// 解决中文问题
InputStream input = Face.class.getResourceAsStream(name);
BufferedImage src = ImageIO.read(input);
Mat image = new Mat(src.getHeight(), src.getWidth(), CvType.CV_8UC3);
image.put(0, 0, ((DataBufferByte) src.getRaster().getDataBuffer()).getData());
return image;
}
public static final String localPath(String name) {
return Face.class.getResource(name).getPath().substring(1);
}
}
这里需要注意Imgcodecs.imread
这个方法不支持中文,所以这里使用BufferedImage
转化为Mat
。
人脸识别需要使用:EigenFaceRecognizer
、FisherFaceRecognizer
或者LBPHFaceRecognizer
。
但是opencv里面的代码测试时提示一下内容:
Exception in thread "main" java.lang.UnsatisfiedLinkError: org.opencv.face.EigenFaceRecognizer.create_1()J
at org.opencv.face.EigenFaceRecognizer.create_1(Native Method)
at org.opencv.face.EigenFaceRecognizer.create(EigenFaceRecognizer.java:36)
at com.acgist.face.FaceJava.main(FaceJava.java:46)
所以后来使用了JavaCV这个工具,代码如下:
package com.acgist.face;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.bytedeco.javacpp.opencv_core.Mat;
import org.bytedeco.javacpp.opencv_core.MatVector;
import org.bytedeco.javacpp.opencv_face.EigenFaceRecognizer;
import org.bytedeco.javacpp.opencv_face.LBPHFaceRecognizer;
import org.bytedeco.javacpp.opencv_imgcodecs;
import com.acgist.utils.LocalPath;
/**
* 人脸识别
*/
public class FaceID {
private static final String FACE_PATH = CreateFace.FACE_PATH;
private static final List<String> IMAGES = new ArrayList<>(); // 训练数据
private static final List<String> TEST_IMAGES = new ArrayList<>(); // 测试数据-训练时排除这些数据
static {
TEST_IMAGES.add(LocalPath.localPath("/image/meimei/face/face-0009.jpg"));
TEST_IMAGES.add(LocalPath.localPath("/image/meimei/face/face-0010.jpg"));
TEST_IMAGES.add(LocalPath.localPath("/image/meimei/face/face-0011.jpg"));
File floder = new File(FACE_PATH);
String path = null;
for (File image : floder.listFiles()) {
path = image.getAbsolutePath();
if(!TEST_IMAGES.contains(path)) {
IMAGES.add(path);
}
}
}
public static void main(String[] args) throws IOException {
// FaceID.train();
FaceID.label();
}
/**
* 人脸置信度
*/
public static final void train() throws IOException {
EigenFaceRecognizer eigenFaceRecognizer = EigenFaceRecognizer.create();
// FisherFaceRecognizer fisherFaceRecognizer = FisherFaceRecognizer.create(); // 训练时必须大于等于两个label
LBPHFaceRecognizer lbphFaceRecognizer = LBPHFaceRecognizer.create();
int index = 0;
int[] labes = new int[IMAGES.size()];
MatVector src = new MatVector();
for (String image : IMAGES) {
System.out.println("开始训练:" + image);
// src.push_back(opencv_imgcodecs.imread(image, opencv_imgcodecs.CV_LOAD_IMAGE_GRAYSCALE));
src.push_back(opencv_imgcodecs.imread(image, opencv_imgcodecs.CV_LOAD_IMAGE_GRAYSCALE));
labes[index++] = 1;
}
eigenFaceRecognizer.train(src, new Mat(labes));
// fisherFaceRecognizer.train(src, new Mat(labes));
lbphFaceRecognizer.train(src, new Mat(labes));
// 保存训练模型
eigenFaceRecognizer.save("eigenFace.xml");
lbphFaceRecognizer.save("lbphFace.xml");
// 加载训练模型
// eigenFaceRecognizer = EigenFaceRecognizer.create();
// eigenFaceRecognizer.read("eigenFace.xml");
// lbphFaceRecognizer = LBPHFaceRecognizer.create();
// lbphFaceRecognizer.read("lbphFace.xml");
// 图片识别
// IntBuffer label = IntBuffer.allocate(1);
// DoubleBuffer confidence = DoubleBuffer.allocate(1);
int [] label = new int[1];
double [] confidence = new double[1];
for (String path : TEST_IMAGES) {
eigenFaceRecognizer.predict(opencv_imgcodecs.imread(path, opencv_imgcodecs.CV_LOAD_IMAGE_GRAYSCALE), label, confidence);
System.out.print("测试图片:" + path);
System.out.print(",标签(label):" + label[0]);
System.out.println(",置信度(confidence):" + confidence[0]);
}
for (String path : TEST_IMAGES) {
lbphFaceRecognizer.predict(opencv_imgcodecs.imread(path, opencv_imgcodecs.CV_LOAD_IMAGE_GRAYSCALE), label, confidence);
System.out.print("测试图片:" + path);
System.out.print(",标签(label):" + label[0]);
System.out.println(",置信度(confidence):" + confidence[0]);
}
// System.out.println("label:" + eigenFaceRecognizer.predict_label(opencv_imgcodecs.imread("E://face85.jpg", opencv_imgcodecs.CV_LOAD_IMAGE_GRAYSCALE)));
}
/**
* 打标签
*/
public static final void label() {
EigenFaceRecognizer eigenFaceRecognizer = EigenFaceRecognizer.create();
// FisherFaceRecognizer fisherFaceRecognizer = FisherFaceRecognizer.create(); // 训练时必须大于等于两个label
LBPHFaceRecognizer lbphFaceRecognizer = LBPHFaceRecognizer.create();
int index = 0;
IMAGES.addAll(TEST_IMAGES); // 添加测试数据
int[] labes = new int[IMAGES.size()];
MatVector src = new MatVector();
for (String image : IMAGES) {
System.out.println("开始训练:" + image);
// src.push_back(opencv_imgcodecs.imread(image, opencv_imgcodecs.CV_LOAD_IMAGE_GRAYSCALE));
src.push_back(opencv_imgcodecs.imread(image, opencv_imgcodecs.CV_LOAD_IMAGE_GRAYSCALE));
if(image.contains("face-0010")) {
labes[index++] = 2;
} else if(image.contains("face-0011")) {
labes[index++] = 3;
} else {
labes[index++] = 1;
}
}
eigenFaceRecognizer.train(src, new Mat(labes));
// fisherFaceRecognizer.train(src, new Mat(labes));
lbphFaceRecognizer.train(src, new Mat(labes));
// 保存训练模型
eigenFaceRecognizer.save("eigenFace.xml");
lbphFaceRecognizer.save("lbphFace.xml");
// 加载训练模型
// eigenFaceRecognizer = EigenFaceRecognizer.create();
// eigenFaceRecognizer.read("eigenFace.xml");
// lbphFaceRecognizer = LBPHFaceRecognizer.create();
// lbphFaceRecognizer.read("lbphFace.xml");
// 图片识别
for (String path : TEST_IMAGES) {
System.out.println("label:" + eigenFaceRecognizer.predict_label(opencv_imgcodecs.imread(path, opencv_imgcodecs.CV_LOAD_IMAGE_GRAYSCALE)));
}
}
}
不过测试的时候发现置信度并不是0-1.0之间,而是一个非常夸张的数字。😤
完整代码:https://github.com/acgist/demo/tree/master/aimldl/opencv-face