Java + OpenCV 实现图片人脸检测

本文介绍如何使用Java和OpenCV进行人脸识别。通过将图片转换为灰度,然后使用预训练的分类器找到人脸,标出位置。文章提供详细步骤,包括pom.xml依赖,代码实现以及Windows环境下可能出现的UnsatisfiedLinkError和java.library.path问题的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、功能展示

识别一种图上的所有人的脸,并且标出人脸的位置,画出人眼以及嘴的位置,展示效果图如下: 

二、技术实现思路

图片转换成灰色(降低为一维的灰度,减低计算强度)

图片上画矩形

使用训练分类器查找人脸

三、pom引入的jar包说明

    <properties>
        <java.version>1.8</java.version>
        <!-- javacpp当前版本 -->
        <javacpp.version>1.4.3</javacpp.version>
        <!-- opencv版本 -->
        <opencv.version>3.4.3</opencv.version>
        <!-- ffmpeg版本 -->
        <ffmpeg.version>4.0.2</ffmpeg.version>
    </properties>

        <!-- javacv -->
        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>javacv-platform</artifactId>
            <version>${javacpp.version}</version>
        </dependency>
        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>javacv</artifactId>
            <version>${javacpp.version}</version>
        </dependency>
        <!-- javacpp -->
        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>javacpp</artifactId>
            <version>${javacpp.version}</version>
        </dependency>
        <!-- ffmpeg -->
        <dependency>
            <groupId>org.bytedeco.javacpp-presets</groupId>
            <artifactId>ffmpeg-platform</artifactId>
            <version>${ffmpeg.version}-${javacpp.version}</version>
        </dependency>
        <dependency>
            <groupId>org.bytedeco.javacpp-presets</groupId>
            <artifactId>ffmpeg</artifactId>
            <version>${ffmpeg.version}-${javacpp.version}</version>
        </dependency>

四、具体实现代码

(1)、图片转换成灰色

使用OpenCV的cvtColor()转换图片颜色,代码如下:

    /**
     * 图片转换成灰色(降低为一维的灰度,减低计算强度)
     * @param path
     * @return
     */
    private Mat transferToGray(String path) {
        // 读取图片
        Mat srcImg = Imgcodecs.imread(path);
        // 目标灰色图像
        Mat dstGrayImg = new Mat();
        // 转换灰色
        Imgproc.cvtColor(srcImg, dstGrayImg, Imgproc.COLOR_BGR2GRAY);

        return dstGrayImg;
    }

(2)图片上画矩形

使用OpenCV的rectangle()绘制矩形,代码如下:

    /**
     * 在图片上画矩形
     * @param path
     */
    private void drawRect(String path) {
        // 读取图片
        Mat srcImg = Imgcodecs.imread(path);
        // 目标灰色图像
        Mat dstGrayImg = new Mat();
        // 转换灰色
        Imgproc.cvtColor(srcImg, dstGrayImg, Imgproc.COLOR_BGR2GRAY);
        // 坐标
        double x = 10, y = 10;
        //  矩形大小(宽、高)
        double w = 100;
        // 定义绘制颜色
        Scalar color = new Scalar(0, 0, 255);
        Imgproc.rectangle(srcImg, new Point(x, y), new Point(x + w, y + w), color, 1);
        HighGui.imshow("预览", srcImg);
        // 显示图像
        HighGui.waitKey(0);
        // 释放所有的窗体资源
        HighGui.destroyAllWindows();

    }

(3)、使用训练分类器查找人脸

在使用OpenCV的人脸检测之前,需要一个人脸训练模型,格式是xml的,我们这里使用OpenCV提供好的人脸分类模型xml,

下载地址:https://github.com/opencv/opencv/tree/master/data/haarcascades 可全部下载到本地,

本人存放的路径是:D:\workspace\opencv\data\haarcascades\

五、完整实现代码:

package com.biubiu.example;


import org.opencv.core.*;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;

import java.math.BigDecimal;

import static org.bytedeco.javacpp.opencv_objdetect.CV_HAAR_DO_CANNY_PRUNING;

/**
 * 人脸检测
 */
public class FaceDetect {

    static {
        // 加载 动态链接库
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
    }

    public static void main(String[] args) {

        String filepath = "/home/yinyue/opencv/test.JPG";
        Mat srcImg = Imgcodecs.imread(filepath);
        // 目标灰色图像
        Mat dstGrayImg = new Mat();
        // 转换灰色
        Imgproc.cvtColor(srcImg, dstGrayImg, Imgproc.COLOR_BGR2GRAY);
        // OpenCv人脸识别分类器
        CascadeClassifier classifier = new CascadeClassifier("D:\workspace\opencv\data\haarcascades\haarcascade_frontalface_default.xml");
        // 用来存放人脸矩形
        MatOfRect faceRect = new MatOfRect();
        // 特征检测点的最小尺寸
        Size minSize = new Size(32, 32);
        // 图像缩放比例,可以理解为相机的X倍镜
        double scaleFactor = 1.2;
        // 对特征检测点周边多少有效检测点同时检测,这样可以避免选取的特征检测点大小而导致遗漏
        int minNeighbors = 3;
        // 执行人脸检测
        classifier.detectMultiScale(dstGrayImg, faceRect, scaleFactor, minNeighbors, CV_HAAR_DO_CANNY_PRUNING, minSize);
        //遍历矩形,画到原图上面
        // 定义绘制颜色
        Scalar color = new Scalar(0, 0, 255);
        for(Rect rect: faceRect.toArray()) {
            int x = rect.x;
            int y = rect.y;
            int w = rect.width;
            int h = rect.height;
            // 单独框出每一张人脸
            Imgproc.rectangle(srcImg, new Point(x, y), new Point(x + w, y + w), color, 2);
            // 左眼
            Imgproc.circle(srcImg, new Point(x + Math.floor(getDivideDouble(w, 4)), y + Math.floor(getDivideDouble(h, 4)) + 15), Math.min(getDivideInt(h, 8), getDivideInt(w, 8)), color);
            // 右眼
            Imgproc.circle(srcImg, new Point(x + 3 * Math.floor(getDivideDouble(w, 4)), y + Math.floor(getDivideDouble(h, 4)) + 15), Math.min(getDivideInt(h, 8), getDivideInt(w, 8)), color);
            // 嘴巴
            Imgproc.rectangle(srcImg, new Point(x + 3 * Math.floor(getDivideDouble(w, 8)), y + 3 * Math.floor(getDivideDouble(h, 4)) - 5), new Point(x + 5 * Math.floor(getDivideDouble(w, 8)) + 10, y + 7 * Math.floor(getDivideDouble(h, 8))), color, 2);
        }
        HighGui.imshow("预览", srcImg);
        // 显示图像
        HighGui.waitKey(0) ;
        // 释放所有的窗体资源
        HighGui.destroyAllWindows();

    }


    /**
     * 图片转换成灰色(降低为一维的灰度,减低计算强度)
     * @param path
     * @return
     */
    private static Mat transferToGray(String path) {
        // 读取图片
        Mat srcImg = Imgcodecs.imread(path);
        // 目标灰色图像
        Mat dstGrayImg = new Mat();
        // 转换灰色
        Imgproc.cvtColor(srcImg, dstGrayImg, Imgproc.COLOR_BGR2GRAY);

        return dstGrayImg;
    }

    /**
     * 在图片上画矩形
     * @param path
     */
    private static void drawRect(String path) {
        // 读取图片
        Mat srcImg = Imgcodecs.imread(path);
        // 目标灰色图像
        Mat dstGrayImg = new Mat();
        // 转换灰色
        Imgproc.cvtColor(srcImg, dstGrayImg, Imgproc.COLOR_BGR2GRAY);
        // 坐标
        double x = 10, y = 10;
        //  矩形大小(宽、高)
        double w = 100;
        // 定义绘制颜色
        Scalar color = new Scalar(0, 0, 255);
        Imgproc.rectangle(srcImg, new Point(x, y), new Point(x + w, y + w), color, 1);
        HighGui.imshow("预览", srcImg);
        // 显示图像
        HighGui.waitKey(0);
        // 释放所有的窗体资源
        HighGui.destroyAllWindows();

    }


    /**
     * 计算除法
     * @param a
     * @param b
     * @return
     */
    private static double getDivideDouble(int a, int b) {
        return new BigDecimal(a).divide(new BigDecimal(b), 2, BigDecimal.ROUND_HALF_UP).doubleValue();
    }


    /**
     * 计算除法
     * @param a
     * @param b
     * @return
     */
    private static int getDivideInt(int a, int b) {
        return new BigDecimal(a).divide(new BigDecimal(b), 2, BigDecimal.ROUND_HALF_UP).intValue();
    }



}

如果想检测身体其他部位,则选择其他的xml文件

OpenCv人脸识别分类器 classifier.detectMultiScale(dstGrayImg, faceRect, scaleFactor, minNeighbors, CV_HAAR_DO_CANNY_PRUNING, minSize); 参数说明:

gray:转换的灰图

scaleFactor:图像缩放比例,可理解为相机的X倍镜

minNeighbors:对特征检测点周边多少有效点同时检测,这样可避免因选取的特征检测点太小而导致遗漏

minSize:特征检测点的最小尺寸

flags:操作方式。

分为 :

CV_HAAR_DO_CANNY_PRUNING(CANNY边缘检测)

CV_HAAR_SCALE_IMAGE(缩放图像检测)

CV_HAAR_FIND_BIGGEST_OBJECT(寻找最大的目标)

CV_HAAR_DO_ROUGH_SEARCH(做粗略搜索)

如果CV_HAAR_DO_CANNY_PRUNING被设定,函数利用Canny边缘检测器来排除一些边缘很少或者很多的图像区域,因为这样的区域一般不含被检目标。人脸检测中通过设定阈值使用了这种方法,并因此提高了检测速度。当然该标记是在没有定义CV_HAAR_SCALE_IMAGE下使用的,也就是说使用缩放检测窗口的形式定义的

如果CV_HAAR_SCALE_IMAGE被设定则在每一个scale上缩放图像检测,如果没有定义则缩放检测窗口进行检测,当缩放检测窗口检测的时候是不能返回rejectLevels和levelWeights的。

如果CV_HAAR_FIND_BIGGEST_OBJECT被设定,如果没有设定CV_HAAR_SCALE_IMAGE,保存当前检测窗口中面积最大的矩形,不管设定没有设定CV_HAAR_SCALE_IMAGE,最后都输出一个面积最大的矩形(如果检测结果不为空的话),详细分析可以参考cvHaarDetectObjectsForROC

如果CV_HAAR_DO_ROUGH_SEARCH设定了,则最小的缩放比例为0.6,否则为0.4,仅在缩放检测窗口中有效

六、windows下报错问题解决

(1) 、UnsatisfiedLinkError异常

在程序运行前 加载 动态链接库

(2) 、no opencv_java343 in java.library.path

解决办法

如果你的版本和我的不一致,可去下载你自己对应的版本.

windows下载opencv-3.4.3-vc14_vc15.exe 并安装,下载地址:  

https://nchc.dl.sourceforge.net/project/opencvlibrary/opencv-win/3.4.3/opencv-3.4.3-vc14_vc15.exe

我的安装地址是 D:\workstation\opencv\opencv 

在idea中配置 -Djava.library.path=D:\workstation\opencv\opencv\build\java\x64

Linux下载opencv-3.4.3.zip 下载地址:  https://udomain.dl.sourceforge.net/project/opencvlibrary/opencv-unix/3.4.3/opencv-3.4.3.zip
同样配置,或追加运行参数

在linux环境下的安装可参考

重要的事情说三遍,注意版本号,注意版本号,注意版本号

Linux编译安装opencv - _任重 - 博客园

linux下安装opencv并生成opencv-java,即linux下用java调用opencv_麻花-CSDN博客

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张音乐

请我喝杯咖啡吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值