Implementación de código de reconocimiento facial y entrenamiento facial JavaCV

javacv

JavaCV es una biblioteca de desarrollo Java basada en OpenCV y FFmpeg para funciones de procesamiento de imágenes y visión por computadora. Proporciona una serie de clases y métodos que permiten a los desarrolladores utilizar fácilmente algoritmos y técnicas de visión por computadora en aplicaciones Java.

  1. Integración de OpenCV y FFmpeg: JavaCV integra estrechamente OpenCV y FFmpeg, dos importantes bibliotecas de procesamiento de video y visión por computadora. Los desarrolladores pueden llamar directamente a las funciones de OpenCV y FFmpeg en código Java sin utilizar otras herramientas o bibliotecas externas.

  2. Captura de imágenes y videos: JavaCV permite a los desarrolladores capturar imágenes y transmisiones de video desde cámaras y archivos de video. Con unas pocas líneas simples de código, puede introducir imágenes o videos en su aplicación Java para su procesamiento y análisis.

  3. Procesamiento y análisis de imágenes: JavaCV proporciona varias funciones de análisis y procesamiento de imágenes, incluido el filtrado de imágenes, la detección de bordes, la ecualización de histogramas, etc. Los desarrolladores pueden utilizar estas funciones para mejorar y optimizar imágenes, así como extraer características de las imágenes.

  4. Detección de características y descriptores: JavaCV admite varios algoritmos de detección y descriptores de características, como SIFT (Transformación de características invariantes de escala), SURF (Características robustas aceleradas) y ORB (Binario invariante de rotación). Estos algoritmos se pueden utilizar en aplicaciones como reconocimiento de objetos, comparación de imágenes y unión de imágenes.

  5. Detección y reconocimiento de rostros: JavaCV proporciona funciones de detección y reconocimiento de rostros, lo que permite a los desarrolladores implementar aplicaciones relacionadas con rostros en aplicaciones Java. Puede utilizar JavaCV para detectar rostros, marcar puntos de referencia faciales y realizar reconocimiento facial.

  6. Soporte de aprendizaje automático: JavaCV está integrado con el marco de aprendizaje profundo OpenCV DNN, lo que permite a los desarrolladores utilizar modelos de redes neuronales previamente entrenados en Java. Esto permite a los desarrolladores realizar fácilmente tareas de visión por computadora, como clasificación de imágenes, detección de objetos y segmentación de imágenes.

  7. Procesamiento multimedia: JavaCV también es muy potente para procesar archivos de audio y vídeo. Puede leer, escribir y editar varios formatos de audio y video, y también admite el procesamiento de transmisiones de audio y video.

En resumen, JavaCV es una biblioteca de desarrollo Java potente y versátil para implementar tareas de procesamiento de imágenes y visión por computadora. Su integración y sus ricas funciones y aplicaciones facilitan a los desarrolladores procesar imágenes y vídeos y crear aplicaciones visuales excepcionales.

 

tutorial de código

1. Primero busque las fotos de avatar de los dos personajes y colóquelas por separado en archivos.

 En segundo lugar, utilice el entrenamiento de código Java para generar archivos modelo.

Primero, importe el paquete jar dependiente de javacv a maven

        <!-- https://mvnrepository.com/artifact/org.bytedeco/javacv-platform -->
        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>javacv-platform</artifactId>
            <version>1.5.5</version>
        </dependency>

El código java es el siguiente:



import org.bytedeco.opencv.global.opencv_imgcodecs;
import org.bytedeco.opencv.opencv_core.Mat;
import org.bytedeco.opencv.opencv_core.MatVector;
import org.bytedeco.opencv.opencv_core.Size;
import org.bytedeco.opencv.opencv_face.FaceRecognizer;
import org.bytedeco.opencv.opencv_face.FisherFaceRecognizer;

import java.io.File;
import java.io.IOException;
import java.nio.IntBuffer;
import java.util.LinkedList;
import java.util.List;

import static org.bytedeco.opencv.global.opencv_core.CV_32SC1;
import static org.bytedeco.opencv.global.opencv_imgcodecs.IMREAD_GRAYSCALE;
import static org.bytedeco.opencv.global.opencv_imgproc.resize;

/**
 * @author willzhao
 * @version 1.0
 * @description 训练
 * @date 2021/12/12 18:26
 */
public class FaceTrainDemo {

    /**
     * 从指定目录下
     * @param dirs
     * @param outputPath
     */
    private void train(String[] dirs, String outputPath) {
        int totalImageNums = 0;

        // 统计每个路径下的照片数,加在一起就是照片总数
        for(String dir : dirs) {
            List<String> files = getAllFilePath(dir);
            totalImageNums += files.size();
        }
        //todo截取人脸

        System.out.println("total : " + totalImageNums);

        // 这里用来保存每一张照片的序号,和照片的Mat对象
        MatVector imageIndexMatMap = new MatVector(totalImageNums);

        Mat lables = new Mat(totalImageNums, 1, CV_32SC1);

        // 这里用来保存每一张照片的序号,和照片的类别
        IntBuffer lablesBuf = lables.createBuffer();

        // 类别序号,从1开始,dirs中的每个目录就是一个类别
        int kindIndex = 1;

        // 照片序号,从0开始
        int imageIndex = 0;

        // 每个目录下的照片都遍历
        for(String dir : dirs) {
            // 得到当前目录下所有照片的绝对路径
            List<String> files = getAllFilePath(dir);

            // 处理一个目录下的每张照片,它们的序号不同,类别相同
            for(String file : files) {
                // imageIndexMatMap放的是照片的序号和Mat对象
                imageIndexMatMap.put(imageIndex, read(file));
                // bablesBuf放的是照片序号和类别
                lablesBuf.put(imageIndex, kindIndex);
                // 照片序号加一
                imageIndex++;
            }

            // 每当遍历完一个目录,才会将类别加一
            kindIndex++;
        }

        // 实例化人脸识别类
        FaceRecognizer faceRecognizer = FisherFaceRecognizer.create();
        // 训练,入参就是图片集合和分类集合
        faceRecognizer.train(imageIndexMatMap, lables);
        // 训练完成后,模型保存在指定位置
        faceRecognizer.save(outputPath);
        //释放资源
        faceRecognizer.close();
    }

    /**
     * 读取指定图片的灰度图,调整为指定大小
     * @param path
     * @return
     */
    private static Mat read(String path) {
        Mat faceMat = opencv_imgcodecs.imread(path,IMREAD_GRAYSCALE);
        resize(faceMat, faceMat, new Size(164, 164));
        return faceMat;
    }

    /**
     * 把指定路径下所有文件的绝对路径放入list集合中返回
     * @param path
     * @return
     */
    public static List<String> getAllFilePath(String path) {
        List<String> paths = new LinkedList<>();

        File file = new File(path);

        if (file.exists()) {
            // 列出该目录下的所有文件
            File[] files = file.listFiles();

            for (File f : files) {
                if (!f.isDirectory()) {
                    // 把每个文件的绝对路径都放在list中
                    paths.add(f.getAbsolutePath());
                }
            }
        }

        return paths;
    }

    public static void main(String[] args) throws IOException {

        String base = "D:\\face_img\\";

        // 存储图片的两个目录
        // man目录下保存了群众演员A的所有人脸照片,
        // woman目录下保存了群众演员B的所有人脸照片
        String[] dirs = {base + "msk", base + "tlp"};

        // 开始训练,并指定模型输出位置
        new FaceTrainDemo().train(dirs, base + "faceRecognizer.xml");
    }
}

Tenga en cuenta que la matriz de directorios tiene al menos dos.

Haga clic derecho en el editor de ideas para ejecutarlo y se generará un archivo modelo de faceRecognizer.xml.

El código de identificación de Java es el siguiente :

La clave de kindNameMap es el orden de la matriz de directorios en el código de entrenamiento, la primera es msk, la segunda es tlp, etc.




import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.bytedeco.javacv.OpenCVFrameConverter;
import org.bytedeco.opencv.opencv_core.*;
import org.bytedeco.opencv.opencv_face.FaceRecognizer;
import org.bytedeco.opencv.opencv_face.FisherFaceRecognizer;
import org.bytedeco.opencv.opencv_objdetect.CascadeClassifier;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import static org.bytedeco.opencv.global.opencv_imgproc.*;

/**
 * @author tarzan
 */
public class FaceDemo {

    public static void main(String[] args) throws IOException {
        Map<Integer, String> kindNameMap=new HashMap<>(2);
        kindNameMap.put(1,"msk");
        kindNameMap.put(2,"tlp");
        faceRecognize("D:\\face_img\\test\\msk.jpg",kindNameMap);
    }


    /**
     * 调整后的文件宽度
     */
    public final static int RESIZE_WIDTH = 164;
    /**
     * 调整后的文件高度
     */
    public final static int RESIZE_HEIGHT = 164;
    /**
     * 超过这个置信度就明显有问题了
     */
    public final static double MAX_CONFIDENCE = 50d;

   public final static String frontalFaceModelPath="D:\\face_img\\lbpcascade_frontalface.xml";
   public final static String faceRecognizerPath="D:\\face_img\\faceRecognizer.xml";

    /**
     * 人脸检测
     *
     * @param filePath 图片路径
     */
    public static RectVector faceDetect(Mat grayImg) throws IOException {
        // 读取opencv人脸检测器
        CascadeClassifier cascade = new CascadeClassifier(frontalFaceModelPath);
        // 检测到的人脸
        RectVector faces = new RectVector();
        //多人脸检测
        cascade.detectMultiScale(grayImg, faces);
        return faces;

    }
    /**
     * 人脸识别
     *
     * @param kindNameMap 人物名称集合
     */
    public static void faceRecognize(String filePath,Map<Integer, String> kindNameMap) throws IOException {
        File file=new File(filePath);
        BufferedImage image = ImageIO.read(file);
        Java2DFrameConverter imageConverter = new Java2DFrameConverter();
        Frame frame = imageConverter.convert(image);
        //类型转换
        OpenCVFrameConverter.ToMat converter = new OpenCVFrameConverter.ToMat();
        Mat original = converter.convertToMat(frame);
        //存放灰度图
        Mat grayImg = new Mat();
        //模式设置成ImageMode.Gray下不需要再做灰度 摄像头获取的是彩色图像,所以先灰度化下
        cvtColor(original, grayImg, COLOR_BGRA2GRAY);
        // 均衡化直方图
        equalizeHist(grayImg, grayImg);
        RectVector faces=faceDetect(grayImg);
        // 遍历人脸
        for (int i = 0; i < faces.size(); i++) {
            Rect face_i = faces.get(i);
            //绘制人脸矩形区域,scalar色彩顺序:BGR(蓝绿红)
            rectangle(original, face_i, new Scalar(0, 255, 0, 1));
            int pos_x = Math.max(face_i.tl().x() - 10, 0);
            int pos_y = Math.max(face_i.tl().y() - 10, 0);
            oneFaceRecognize(grayImg,face_i,kindNameMap);
            // 在人脸矩形上方绘制提示文字(中文会乱码)
            putText(original, "people face", new Point(pos_x, pos_y), FONT_HERSHEY_COMPLEX, 1.0, new Scalar(0, 0, 255, 2.0));
        }
        frame = converter.convert(original);
        image = imageConverter.convert(frame);
        String fileName=file.getName();
        String extension=fileName.substring(fileName.lastIndexOf(".")+1);
        String newFileName=fileName.substring(0,fileName.lastIndexOf("."))+"_result."+extension;
        ImageIO.write(image, extension, new File(file.getParent()+File.separator+newFileName));
    }

    /**
     * 人脸识别
     *
     * @param kindNameMap 人物名称集合
     */
    public static String oneFaceRecognize(Mat grayImg,Rect face,Map<Integer, String> kindNameMap){
        String kindName=null;
        Mat mat=new Mat(grayImg, face);
        Size size= new Size(RESIZE_WIDTH, RESIZE_HEIGHT);
        // 核心代码,把检测到的人脸拿去识别
        // 调整到和训练一致的尺寸
        resize(mat, mat, size);

        // 推理结果的标签
         int[] labels = new int[1];
        // 推理结果的置信度
         double[] confidences = new double[1];
        try {
            // 推理(这一行可能抛出RuntimeException异常,因此要补货,否则会导致程序退出)
            FaceRecognizer faceRecognizer= FisherFaceRecognizer.create();
            // 加载的是训练时生成的模型
            faceRecognizer.read(faceRecognizerPath);
            // 设置门限,这个可以根据您自身的情况不断调整
            faceRecognizer.setThreshold(MAX_CONFIDENCE);
            //人脸检测
            faceRecognizer.predict(mat, labels, confidences);
        } catch (RuntimeException runtimeException) {
            runtimeException.printStackTrace();
        }
        // 得到分类编号后,从map中取得名字,用来显示
        if (kindNameMap.containsKey(labels[0])) {
            kindName = String.format("%s, confidence : %.4f", kindNameMap.get(labels[0]), confidences[0]);
        } else {
            // 取不到名字的时候,就显示unknown
            kindName = "unknown(" + labels[0] + ")";
        }
        System.out.println(kindName);
        return kindName;
    }

}

Haga clic derecho y ejecute.

Precauciones:

1. Es mejor no utilizar chino para la ruta del archivo.

2. No cambie el sufijo del formato de la imagen usted mismo; de lo contrario, es posible que la imagen no se pueda leer.

Artículos relacionados recomendados

JavaCV realiza el tutorial de código completo para la detección de rostros en imágenes_blog-CSDN blog_javacv de coincidencia de rostros de Luoyang Taishan

Supongo que te gusta

Origin blog.csdn.net/weixin_40986713/article/details/128071047
Recomendado
Clasificación