溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

springboot集成opencv如何實現(xiàn)人臉識別功能

發(fā)布時間:2021-06-11 10:13:02 來源:億速云 閱讀:444 作者:小新 欄目:開發(fā)技術

這篇文章主要介紹springboot集成opencv如何實現(xiàn)人臉識別功能,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!

前言

項目中檢測人臉圖片是否合法的功能,之前用的是百度的人臉識別接口,由于成本高昂不得不尋求替代方案。

什么是opencv?

OpenCV是一個基于BSD許可(開源)發(fā)行的跨平臺計算機視覺和機器學習軟件庫,可以運行在Linux、Windows、Android和Mac OS操作系統(tǒng)上。輕量級而且高效——由一系列 C 函數(shù)和少量 C++ 類構成,同時提供了Python、Java、MATLAB等語言的接口,實現(xiàn)了圖像處理和計算機視覺方面的很多通用算法。

項目集成步驟

由于項目是放在Linux系統(tǒng)中跑的,開發(fā)環(huán)境是Windows10,所以項目中涉及到opencv的要分兩套。

準備工作

 Windows安裝opencv

opencv官網(wǎng)下載安裝包https://opencv.org/releases/

springboot集成opencv如何實現(xiàn)人臉識別功能

我這里選擇的是4.1.1版本
分別下載了Windows版本和源碼

springboot集成opencv如何實現(xiàn)人臉識別功能

Windows環(huán)境下集成

安裝opencv,沒什么說的,指定一個路徑安裝即可,注意安裝路徑不能是中文。
項目中集成的三個關鍵點

  • 引入jar依賴

  • 讀取OpenCV自帶的人臉識別特征XML文件

  • 配置opencv的庫文件地址

關鍵點1:引入jar包

jar包位置在安裝路徑下的java文件夾中

springboot集成opencv如何實現(xiàn)人臉識別功能

兩種方式引入

方式一:idea添加jar

springboot集成opencv如何實現(xiàn)人臉識別功能

或者直接在Libraries中添加二者皆可。

方式二:將jar上傳至私服,在maven中引入

我這里是將jar上傳至私服,然后引用的。
注意Windows版的jar和Linux中的jar不一樣,二者要區(qū)分開來
通過Maven配置在不同環(huán)境下加載不同的jar

<profiles>
    <profile>
        <id>dev</id>
        <dependencies>
<!--            本地引用-->
<!--                <dependency>-->
<!--                    <groupId>op</groupId>-->
<!--                    <artifactId>opencv</artifactId>-->
<!--                    <version>411</version>-->
<!--                    <scope>system</scope>-->
<!--                    <systemPath>-->
<!--                        ${project.basedir}/src/main/resources/opencv/windows/opencv-411.jar-->
<!--                    </systemPath>-->
<!--                </dependency>-->
            
<!--            倉庫引用-->
            <dependency>
            <!--                這里改成自己的倉庫地址-->
                <groupId>com.***.cloud.resource</groupId>
                <artifactId>opencv-window</artifactId>
                <version>411</version>
            </dependency>
        </dependencies>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
    </profile>
    <profile>
        <id>test</id>
        <dependencies>
            <dependency>
            <!--                這里改成自己的倉庫地址-->
                <groupId>com.***.cloud.resource</groupId>
                <artifactId>opencv-linux</artifactId>
                <version>411</version>
            </dependency>
        </dependencies>
    </profile>
</profiles>

關鍵點2:配置人臉識別特征XML文件的地址

在bootstrap.yml添加如下參數(shù)

#  函數(shù)庫地址 在 vm optionis中 配置
#  windows地址: -Djava.library.path=D:\software\opencv\build\java\x64
#  linux地址:   -Djava.library.path=/usr/local/opencv-4.1.1/build/lib/
opencv:
  lib:
    linuxxmlpath: /usr/local/share/opencv4/haarcascades/haarcascade_frontalface_alt.xml
    windowxmlpath: D:\software\opencv\sources\data\haarcascades\haarcascade_frontalface_alt.xml

測試的方法中就直接寫死了

 /**
     * 初始化人臉探測器
     */
    static CascadeClassifier faceDetector;

    static {
        String systemProperties = String.valueOf(System.getProperties());
        log.info(systemProperties);
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        faceDetector = new CascadeClassifier("D:\\software\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml");
    }

注意路徑?。?/p>

關鍵點3:配置opencv的庫文件地址

springboot集成opencv如何實現(xiàn)人臉識別功能

-Djava.library.path=D:\software\opencv\build\java\x64

這里其實指向的就是 該目錄下的 opencv_java411.dll 文件
(linux的配置見下文)

代碼

測試方法

package com.example.opencvdemo.test;

import lombok.extern.slf4j.Slf4j;
import org.opencv.core.*;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;

/**
 * @author aaron
 * @since 2021-06-07
 */
@Slf4j
public class FaceVideo {
    /**
     * 初始化人臉探測器
     */
    static CascadeClassifier faceDetector;

    static {
        String systemProperties = String.valueOf(System.getProperties());
        log.info(systemProperties);
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        faceDetector = new CascadeClassifier("D:\\software\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml");
    }

    public static void main(String[] args){
        // 3- 本地圖片人臉識別,識別成功并保存人臉圖片到本地
        String imgPath = "C:\\Users\\Administrator\\Pictures\\wang.jpg";
        face(imgPath);
    }

    /**
     * OpenCV-4.1.1 圖片人臉識別
     *
     * @return: void
     * @date: 2019年5月7日12:16:55
     */
    public static void face(String imgPath) {
        /**
         * 讀取本地
         */
        Mat image = Imgcodecs.imread(imgPath);
        if (image.empty()) {
            System.out.println("image 內(nèi)容不存在!");
            return;
        }
        // 3 特征匹配
        MatOfRect face = new MatOfRect();
        faceDetector.detectMultiScale(image, face);
        // 4 匹配 Rect 矩陣 數(shù)組
        Rect[] rects = face.toArray();
        System.out.println("匹配到 " + rects.length + " 個人臉");
        // 5 為每張識別到的人臉畫一個圈
        int i = 1;
        for (Rect rect : face.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), 3);
            imageCut(imgPath, "D:\\pictures\\" + i + ".jpg", rect.x, rect.y, rect.width, rect.height);// 進行圖片裁剪
            i++;
        }
        // 6 展示圖片
        HighGui.imshow("人臉識別", image);
        HighGui.waitKey(0);
    }
    /**
     * 裁剪人臉
     *
     * @param imagePath
     * @param outFile
     * @param posX
     * @param posY
     * @param width
     * @param height
     */
    public static void imageCut(String imagePath, String outFile, int posX, int posY, int width, int height) {
        // 原始圖像
        Mat image = Imgcodecs.imread(imagePath);
        // 截取的區(qū)域:參數(shù),坐標X,坐標Y,截圖寬度,截圖長度
        Rect rect = new Rect(posX, posY, width, height);
        // 兩句效果一樣
        Mat sub = image.submat(rect); // Mat sub = new Mat(image,rect);
        Mat mat = new Mat();
        Size size = new Size(width, height);
        Imgproc.resize(sub, mat, size);// 將人臉進行截圖并保存
        Imgcodecs.imwrite(outFile, mat);
        System.out.println(String.format("圖片裁切成功,裁切后圖片文件為: %s", outFile));

    }
}

注意!Mat image = Imgcodecs.imread(imgPath);
imgPath中不能帶有中文!
opencv安裝路徑中如果有中文的話就會報錯。

集成到Springboot

package com.example.opencvdemo.util;

import com.example.opencvdemo.exception.PublicException;
import com.example.opencvdemo.result.ErrorCode;
import com.google.common.primitives.Bytes;
import lombok.extern.slf4j.Slf4j;
import org.opencv.core.*;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.objdetect.CascadeClassifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;

/**
 * @author aaron
 * @since 2021-06-07
 */
@Component
@Slf4j
public class OpenCvUtils implements CommandLineRunner {

    @Value("${opencv.lib.linuxxmlpath}")
    private String linuxXmlPath;
    @Value("${opencv.lib.windowxmlpath}")
    private String windowXmlPath;

    /**
     * 人臉探測器對象
     */
    static CascadeClassifier faceDetector;

    /**
     * 判斷是否是Windows系統(tǒng)
     */
    private static final boolean IS_WINDOWS = System.getProperty("os.name").toLowerCase().contains("win");

    /**
     * 監(jiān)測圖片是否合法,是否只有一張臉
     */
    public static void checkFace(String pictureUrl) throws Exception {
//        //將在線圖片保存為本地圖片
//        String imgPath = saveLocal(pictureUrl);
//        //本地圖片
//        File file  = new File(imgPath);
//        FileInputStream fileInputStream = new FileInputStream(file);
//        ByteArrayOutputStream out = new ByteArrayOutputStream();
//        byte[] localBuff = new byte[fileInputStream.available()];
//        fileInputStream.read(localBuff);
//        out.write(localBuff);
//        log.info("本地圖片:"+localBuff.length);

        //在線圖片
        URL url = new URL(pictureUrl);
        URLConnection uc = url.openConnection();
        InputStream inputStream = uc.getInputStream();
        ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
        byte[] buff = new byte[1024];
        int rc;
        while ((rc = inputStream.read(buff, 0, 1024)) > 0) {
            swapStream.write(buff, 0, rc);
        }
        byte[] urlBuff = swapStream.toByteArray();

        log.info("在線圖片:"+urlBuff.length);

        List<Byte> bs = new ArrayList<>();
        bs.addAll(Bytes.asList(urlBuff));
        log.info("buffer長度"+bs.size());
        /**
         * 不好使
         */
//        Mat image =  Converters.vector_char_to_Mat(bs);
//        Mat image  =  Converters.vector_uchar_to_Mat(bs);
        /**
         * 讀取本地
         */
//        Mat image = Imgcodecs.imread(imgPath);
        /**
         * 讀數(shù)據(jù)流
         */
        Mat image  = Imgcodecs.imdecode(new MatOfByte(urlBuff), Imgcodecs.IMREAD_UNCHANGED);

        if (image.empty()) {
            log.error("image 內(nèi)容不存在!");
            return;
        }
        // 3 特征匹配
        MatOfRect face = new MatOfRect();
        faceDetector.detectMultiScale(image, face);
        // 4 匹配 Rect 矩陣 數(shù)組
        Rect[] rects = face.toArray();
        System.out.println("匹配到 " + rects.length + " 個人臉");
//        delFile(imgPath);
        if (rects.length == 0) {
            throw new PublicException(ErrorCode.A0430.getCode(), "沒有監(jiān)測到人臉");
        } else if (rects.length > 1) {
            throw new PublicException(ErrorCode.A0430.getCode(), "檢測到圖片有多張人臉,請重新上傳");
        }
    }

    public static String saveLocal(String pictureUrl) throws IOException {
        URL url = new URL(pictureUrl);
        URLConnection uc = url.openConnection();
        InputStream inputStream = uc.getInputStream();
        String[] value = pictureUrl.split("/");
        String firstFilePath = "D:\\pictures\\";
        if (!IS_WINDOWS) {
            firstFilePath = "/tmp/tmp-picture/";
        }
        String fileName = firstFilePath + value[value.length - 1];
        FileOutputStream out = new FileOutputStream(fileName);
        int j = 0;
        while ((j = inputStream.read()) != -1) {
            out.write(j);
        }
        inputStream.close();
        return fileName;
    }

    /**
     * Callback used to run the bean.
     *
     * @param args incoming main method arguments
     * @throws Exception on error
     */
    @Override
    public void run(String... args){
        String systemProperties = String.valueOf(System.getProperties());
        log.info(systemProperties);
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        String path = "";
        //如果是window系統(tǒng)取出路徑開頭的/
        if (IS_WINDOWS) {
            path = windowXmlPath;
        }else{
            path = linuxXmlPath;
        }
        /**
         * 初始化人臉探測器
         */
        faceDetector = new CascadeClassifier(path);
        log.info("==========初始化人臉探測器成功===========");
    }
}

OpenCV 提供的 API 是直接根據(jù)路徑讀取圖片的,所以最開始的時候我是把圖片保存到本地在讀取才成功的,但是這種方式太憨了點,在實際生產(chǎn)環(huán)境中,大部分情況下都是直接讀取網(wǎng)絡圖片。在內(nèi)存就完成圖片和 opencv 的 Mat 對象的轉(zhuǎn)換。這里代碼中已經(jīng)解決了url地址圖片轉(zhuǎn)化的問題。
這里附上解決該問題的博客 傳送門

Linux安裝opencv

Linux平臺須要咱們手動編譯,下載opencv-4.1.1.zip,解壓到/user/local目錄下,而后編譯

yum  install   ant    gcc  gtk2-devel   pkgconfig  zlib-devel

安裝unzip命令

yum install -y unzip zip

解壓命令

unzip opencv-4.1.1.zip
yum   groupinstall "Development Tools"

安裝cmake

查看cmake當前版本

cmake --version
yum -y install wget

下載獲得cmake-3.9.2源碼

wget https://cmake.org/files/v3.9/cmake-3.9.2.tar.gz

解壓、安裝新版本

tar -xvf cmake-3.9.2.tar.gz

cd cmake-3.9.2

./configure

sudo make && make install
cd /usr/local/opencv-4.1.1
mkdir build
cd build
cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -DBUILD_TESTS=OFF ..
make -j8
sudo make install

對應的jar和.so文件在

/usr/local/share/java/opencv4/

springboot集成opencv如何實現(xiàn)人臉識別功能

人臉識別特征XML文件的地址

/usr/local/share/opencv4/haarcascades/haarcascade_frontalface_alt.xml

Linux啟動

jar 啟動命令添加Vm options

nohup java -jar -Djava.library.path=/usr/local/opencv-4.1.1/build/lib/ opencv-demo-1.0.jar  > logs/opencv-demo-1.0.log 2>&1 &

github直接白嫖

項目代碼已上傳至github,可通過web接口測試,也可用main方法測試。

以上是“springboot集成opencv如何實現(xiàn)人臉識別功能”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對大家有幫助,更多相關知識,歡迎關注億速云行業(yè)資訊頻道!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI