当今天知道java只需要调用opencv就可以实现高精度的人脸检测时,激动地我不得不写个文章把它记录下来。

csdn有位大神已经写好了它的python版本,大家可以去看看。我这里只是用java将它实现一下,方便我们java开发者使用。

首先,我们在java项目中引入opencv4.5.4及以上版本是必须的,然后下载yunet.onnx文件,我是放在项目根目录下的,大家可以根据需要放在某个目录下。然后就是具体代码实现:


import org.opencv.core.*;
import org.opencv.core.Point;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.FaceDetectorYN;
 
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.List;
 
public Mat faceDetect(BufferedImage bufferedImage) throws Exception{
        int backendId = 0;  //0: default, 1: Halide, 2: Intel's Inference Engine, 3: OpenCV, 4: VKCOM, 5: CUDA
        int targetId = 0;  //0: CPU, 1: OpenCL, 2: OpenCL FP16, 3: Myriad, 4: Vulkan, 5: FPGA, 6: CUDA, 7: CUDA FP16, 8: HDDL
        float scoreThreshold = 0.9f;
        float nmsThreshold = 0.3f;
        int topK = 5000;

        Mat srcImg = BufferedImageToMat(bufferedImage,"jpg");
        Mat faces=new Mat();
        FaceDetectorYN faceDetectorYN = FaceDetectorYN.create(System.getProperty("user.dir")+"/yunet.onnx","", new Size(320, 320),scoreThreshold, nmsThreshold, topK, backendId, targetId);
        faceDetectorYN.setInputSize(srcImg.size());
        faceDetectorYN.detect(srcImg,faces);
        for (int i = 0; i < faces.height(); i++)
        {
            // 画人脸框
            Imgproc.rectangle(srcImg, new Rect((int) (faces.get(i, 0)[0]), (int)(faces.get(i, 1)[0]), (int)(faces.get(i, 2)[0]), (int)(faces.get(i, 3)[0])), new Scalar(0, 255, 0), 2);
            // 画关键点
            Imgproc.circle(srcImg, new Point(faces.get(i, 4)[0], faces.get(i, 5)[0]), 2,new Scalar(255, 0, 0), 2);
            Imgproc.circle(srcImg, new Point(faces.get(i, 6)[0], faces.get(i, 7)[0]), 2, new Scalar(0, 0, 255), 2);
            Imgproc.circle(srcImg, new Point(faces.get(i, 8)[0], faces.get(i, 9)[0]), 2, new Scalar(0, 255, 0), 2);
            Imgproc.circle(srcImg, new Point(faces.get(i, 10)[0], faces.get(i, 11)[0]), 2, new Scalar(255, 0, 255), 2);
            Imgproc.circle(srcImg, new Point(faces.get(i, 12)[0], faces.get(i, 13)[0]), 2, new Scalar(0, 255, 255), 2);
            Imgcodecs.imwrite("result.jpg",srcImg);
        }
        return faces;
    }
 
private Mat BufferedImageToMat(BufferedImage bufferedImage, String formatName) throws Exception{
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    ImageIO.write(bufferedImage, formatName, byteArrayOutputStream);
    byteArrayOutputStream.flush();
    Mat mat =  Imgcodecs.imdecode(new MatOfByte(byteArrayOutputStream.toByteArray()), Imgcodecs.IMREAD_UNCHANGED);
    return mat;
}