前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用摄像头+JavaCV做人脸识别

使用摄像头+JavaCV做人脸识别

作者头像
灬沙师弟
发布2023-09-06 08:17:18
8190
发布2023-09-06 08:17:18
举报
文章被收录于专栏:Java面试教程

使用JavaCV做人脸识别

上一文,我们讲到的是使用JavaCV拉取笔记本摄像头画面,这次,我们基于上一次的基础,加工人脸识别功能。

原理很简单,拉取摄像头每一帧,然后对每一帧的画面进行识别,看里面是否有人脸在里面,有的话就对人脸进行绘框,把红框绘制在画面上,然后返回给前面进行展示。

开始向ChatGPT提问

人脸识别功能,需要借助一个叫haarcascade_frontalface_alt.xml的文件,它是OpenCV中已经训练好的人脸分类器文件,也叫正脸识别分类器,我们把它下载到本地,放在resource下,然后使用CascadeClassifier进行加载。

然后各种崩溃的问题来了,不是xml文件加载问题,就是chatgpt给的方法包装有问题。

有haarcascade_frontalface_alt.xml加载错误问题

也有Mat转换问题

好在我这么问,它也能自己去检测问题

各种兜兜转转,花了一天的时间,终于把它矫正了,如果是去百度找一份别人写好的案例,或许五分钟都不需要,但是那样很难的去真正学到什么。

步骤

接下来讲一下人脸识别的步骤吧!

使用OpenCVFrameGrabber对象获取本机摄像头,指定分辨率

代码语言:javascript
复制
//获取本地摄像头,一般是0
OpenCVFrameGrabber grabber = new OpenCVFrameGrabber(0);
// 摄像头有可能有多个分辨率,这里指定
// 可以指定宽高,也可以不指定反而调用grabber.getImageWidth去获取,
grabber.setImageWidth(1280);
grabber.setImageHeight(720);
// 开启抓取器
grabber.start();

使用CanvasFrame对象创建一个窗口用来展示视频流

代码语言:javascript
复制
//创建一个Frame窗口
CanvasFrame previewCanvas = new CanvasFrame("摄像头预览", CanvasFrame.getDefaultGamma() / grabber.getGamma());
previewCanvas.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
previewCanvas.setAlwaysOnTop(true);

使用CascadeClassifier对象加载人脸识别模型

代码语言:javascript
复制
// 下载模型文件
CascadeClassifier cascadeClassifier = new CascadeClassifier("D:\\IDEA_Work\\LinkCV\\src\\main\\resources\\haarcascade_frontalface_alt.xml");

遍历每一帧,将帧对象转为IplImage对象,然后转成Mat对象

代码语言:javascript
复制
// 遍历每一帧
while ((captureFrame = grabber.grab()) != null) {
 // 将帧对象转为IplImage对象
    IplImage img = openCVConverter.convert(captureFrame);
    // 镜像翻转
    cvFlip(img, img, 1);

    // IplImage转mat
    Mat mat1 = new Mat(img);
    ......
}

将图片转成灰度图片,原因是灰度图片更适合识别人脸,所消耗的性能比较低

代码语言:javascript
复制
// 将图像转为灰度图像
Mat grayMat = new Mat();
// 当前图片转为灰度图片
cvtColor(mat1, grayMat, CV_BGR2GRAY);

创建检测结果的容器,然后开始检测

代码语言:javascript
复制
// 存放检测结果的容器
RectVector objects = new RectVector();

// 开始检测
if (cascadeClassifier.empty()) {
    System.out.println("Failed to load cascade classifier.");
}
cascadeClassifier.detectMultiScale(grayMat, objects);

获取检测结果,并且为其绘画红框

代码语言:javascript
复制
// 检测结果总数
long total = objects.size();
// 如果有检测结果,就根据结果的数据构造矩形框,画在原图上
for (long i = 0; i < total; i++) {
    Rect r = objects.get(i);
    int x = r.x(), y = r.y(), w = r.width(), h = r.height();
    rectangle(mat1, new Point(x, y), new Point(x + w, y + h), Scalar.RED, 1, CV_AA, 0);
}

释放资源,将绘好红框的画面返回给前面

代码语言:javascript
复制
// 释放检测结果资源
objects.close();
// 将标注过的图片转为帧,返回
Frame convert = openCVConverter.convert(mat1);
// 显示图像
previewCanvas.showImage(convert);

人脸识别就到此结束了。

完整代码

第一步肯定是引入maven依赖

一个是JavaCV依赖,一个是lombok依赖,因为打算使用@Slf4j

代码语言:javascript
复制
<!-- javacv相关依赖,一个就够了 -->
<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>javacv-platform</artifactId>
    <version>1.5.6</version>
</dependency>
 <dependency>
     <groupId>org.projectlombok</groupId>
     <artifactId>lombok</artifactId>
     <version>1.18.12</version>
 </dependency>

然后是人脸识别代码

代码语言:javascript
复制
package com.gateway.link.cv.local;

import lombok.extern.slf4j.Slf4j;
import org.bytedeco.ffmpeg.global.avutil;
import org.bytedeco.javacv.*;
import org.bytedeco.opencv.global.opencv_imgproc;
import org.bytedeco.opencv.opencv_core.*;
import org.bytedeco.opencv.opencv_objdetect.CascadeClassifier;

import javax.swing.*;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;

import static cn.hutool.core.util.ClassUtil.getClassLoader;
import static org.bytedeco.opencv.global.opencv_core.cvFlip;
import static org.bytedeco.opencv.global.opencv_imgproc.*;

/**
 * @author YESIJIE
 * @date 2023-07-16 16:16
 */
@Slf4j
public class localVideFace {

    /**
     * 输出帧率
     */
    private static final double frameRate = 30;
    /**
     * 摄像头视频的宽
     */
    private static final int cameraImageWidth = 1280;

    /**
     * 摄像头视频的高
     */
    private static final int cameraImageHeight = 720;

    /**
     * 转换器
     */
    private static final OpenCVFrameConverter.ToIplImage openCVConverter = new OpenCVFrameConverter.ToIplImage();



    public static void main(String[] args) throws Exception
    {
        long startTime = System.currentTimeMillis();

        // 设置ffmepg日志级别
        avutil.av_log_set_level(avutil.AV_LOG_INFO);
        FFmpegLogCallback.set();
        //获取本地摄像头,一般是0
        OpenCVFrameGrabber grabber = new OpenCVFrameGrabber(0);
        // 摄像头有可能有多个分辨率,这里指定
        // 可以指定宽高,也可以不指定反而调用grabber.getImageWidth去获取,
        grabber.setImageWidth(1280);
        grabber.setImageHeight(720);

        // 开启抓取器
        grabber.start();

        //创建一个Frame窗口
        CanvasFrame previewCanvas = new CanvasFrame("摄像头预览", CanvasFrame.getDefaultGamma() / grabber.getGamma());
        previewCanvas.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        previewCanvas.setAlwaysOnTop(true);


        log.info("初始化完成,耗时[{}]毫秒,帧率[{}],图像宽度[{}],图像高度[{}]",
                System.currentTimeMillis()-startTime,
                frameRate,
                cameraImageWidth,
                cameraImageHeight);

        // 添加水印时用到的时间工具
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        // 水印在图片上的位置
        org.bytedeco.opencv.opencv_core.Point point = new org.bytedeco.opencv.opencv_core.Point(15, 35);

        Frame captureFrame;

        // 下载模型文件
        CascadeClassifier cascadeClassifier = new CascadeClassifier("D:\\IDEA_Work\\LinkCV\\src\\main\\resources\\haarcascade_frontalface_alt.xml");

        // 遍历每一帧
        while ((captureFrame = grabber.grab()) != null) {

            // 将帧对象转为IplImage对象
            IplImage img = openCVConverter.convert(captureFrame);
            // 镜像翻转
            cvFlip(img, img, 1);

            // IplImage转mat
            Mat mat1 = new Mat(img);
            // 在图片上添加水印,水印内容是当前时间,位置是左上角
            opencv_imgproc.putText(mat1,
                    simpleDateFormat.format(new Date()),
                    point,
                    opencv_imgproc.CV_FONT_VECTOR0,
                    0.8,
                    new Scalar(0, 200, 255, 0),
                    1,
                    0,
                    false);

            // 将图像转为灰度图像
            Mat grayMat = new Mat();
            // 当前图片转为灰度图片
            cvtColor(mat1, grayMat, CV_BGR2GRAY);

            // 存放检测结果的容器
            RectVector objects = new RectVector();

            // 开始检测
            if (cascadeClassifier.empty()) {
                System.out.println("Failed to load cascade classifier.");
            }
            cascadeClassifier.detectMultiScale(grayMat, objects);

            // 检测结果总数
            long total = objects.size();


            // 如果有检测结果,就根据结果的数据构造矩形框,画在原图上
            for (long i = 0; i < total; i++) {
                Rect r = objects.get(i);
                int x = r.x(), y = r.y(), w = r.width(), h = r.height();
                rectangle(mat1, new Point(x, y), new Point(x + w, y + h), Scalar.RED, 1, CV_AA, 0);
            }

            // 释放检测结果资源
            objects.close();

            // 将标注过的图片转为帧,返回
            Frame convert = openCVConverter.convert(mat1);

            // 显示图像
            previewCanvas.showImage(convert);

        }
        log.info("输出结束");
        if (null!= previewCanvas) {
            previewCanvas.dispose();
        }
        if (null!=grabber) {
            try {
                grabber.close();
            } catch (Exception exception) {
                log.error("close grabber error", exception);
            }
        }
    }

}

效果

效果大概是下面这样的,会在视频帧上面对于识别到的脸部部位绘画一个框,然后推送出去展示。由于本人没颜值,所以给自己打码了。

关于haarcascade_frontalface_alt模型,可以去github直接下载

代码语言:javascript
复制
https://github.com/opencv/opencv/tree/master/data/haarcascades
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-08-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java面试教程 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 使用JavaCV做人脸识别
  • 开始向ChatGPT提问
  • 步骤
  • 完整代码
  • 效果
相关产品与服务
人脸识别
腾讯云神图·人脸识别(Face Recognition)基于腾讯优图强大的面部分析技术,提供包括人脸检测与分析、比对、搜索、验证、五官定位、活体检测等多种功能,为开发者和企业提供高性能高可用的人脸识别服务。 可应用于在线娱乐、在线身份认证等多种应用场景,充分满足各行业客户的人脸属性识别及用户身份确认等需求。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档