Java版人脸检测详解上篇:运行环境的Docker镜像(CentOS+JDK+OpenCV)

Posted qiusuo1024com

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java版人脸检测详解上篇:运行环境的Docker镜像(CentOS+JDK+OpenCV)相关的知识,希望对你有一定的参考价值。

gpg --batch --keyserver keyserver.ubuntu.com --recv-keys EAC843EBD3EFDB98CC772FADA5CD6035332FA671; \\

TODO find a good link for users to verify this key is right (https://mail.openjdk.java.net/pipermail/jdk-updates-dev/2019-April/000951.html is one of the only mentions of it I can find); perhaps a note added to https://adoptopenjdk.net/upstream.html would make sense?

no-self-sigs-only: https://salsa.debian.org/debian/gnupg2/commit/c93ca04a53569916308b369c8b218dad5ae8fe07

gpg --batch --keyserver keyserver.ubuntu.com --keyserver-options no-self-sigs-only --recv-keys CA5F11C6CE22644D42C6AC4492EF8D39DC13168F; \\

gpg --batch --list-sigs --keyid-format 0xLONG CA5F11C6CE22644D42C6AC4492EF8D39DC13168F \\

| tee /dev/stderr \\

| grep ‘0xA5CD6035332FA671’ \\

| grep ‘Andrew Haley’; \\

gpg --batch --verify openjdk.tgz.asc openjdk.tgz; \\

rm -rf “$GNUPGHOME”; \\

\\

mkdir -p “$JAVA_HOME”; \\

tar --extract \\

–file openjdk.tgz \\

–directory “$JAVA_HOME” \\

–strip-components 1 \\

–no-same-owner \\

; \\

rm openjdk.tgz*; \\

\\

rm -rf “$JAVA_HOME/jre/lib/security/cacerts”; \\

see “update-ca-trust” script which creates/maintains this cacerts bundle

ln -sT /etc/pki/ca-trust/extracted/java/cacerts “$JAVA_HOME/jre/lib/security/cacerts”; \\

\\

https://github.com/oracle/docker-images/blob/a56e0d1ed968ff669d2e2ba8a1483d0f3acc80c0/OracleJava/java-8/Dockerfile#L17-L19

ln -sfT “$JAVA_HOME” /usr/java/default; \\

ln -sfT “$JAVA_HOME” /usr/java/latest; \\

for bin in “$JAVA_HOME/bin/”*; do \\

base=“ ( b a s e n a m e " (basename " (basename"bin”)"; \\

[ ! -e “/usr/bin/$base” ]; \\

alternatives --install “/usr/bin/ b a s e " " base" " base""base” “$bin” 20000; \\

done; \\

\\

basic smoke test

javac -version; \\

java -version

  • 写完之后执行docker build -t bolingcavalry/centos7.6-jdk8:0.0.1 .即可生成镜像,如果您有hub.docker.com的账号,还可以将其推送到中央仓库,给更多人使用

  • 用history命令看看镜像内容,详情如下,合计五百多兆,已经不小了:

CN0014009475M:~ will$ docker history bolingcavalry/centos7.6-jdk8:0.0.1

IMAGE CREATED CREATED BY SIZE COMMENT

a5dead4a6505 2 days ago /bin/sh -c set -eux; arch="$(objdump… 209MB

2 days ago /bin/sh -c #(nop) ENV LANG=C.UTF-8 0B

2 days ago /bin/sh -c #(nop) ENV PATH=/usr/java/openjd… 0B

2 days ago /bin/sh -c #(nop) ENV JAVA_HOME=/usr/java/o… 0B

2 days ago /bin/sh -c set -eux; yum install -y … 144MB

2 years ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B

2 years ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B

2 years ago /bin/sh -c #(nop) ADD file:54b004357379717df… 202MB

  • 我这里已经推送到hub.docker.com上去了,执行以下命令即可下载到本地:

docker pull bolingcavalry/centos7.6-jdk8:0.0.3

CentOS+JDK+OpenCV镜像

  • 接下来可以集成OpenCV了,Dockerfile内容如下所示,基础镜像是刚刚做好的bolingcavalry/centos7.6-jdk8:0.0.1,先是安装一大堆编译所需的应用,然后下载OpenCV-3.4.3版本的源码,然后编译,就这么简单(但其间的调试工作还是不少的,不说了,说多了都是泪):

FROM bolingcavalry/centos7.6-jdk8:0.0.1

RUN echo “export LC_ALL=en_US.UTF-8” >> /etc/profile \\

&& source /etc/profile

RUN set -eux; \\

yum install -y \\

make \\

cmake \\

gcc \\

gcc-c++ \\

gtk±devel \\

gimp-devel \\

gimp-devel-tools \\

gimp-help-browser \\

zlib-devel \\

libtiff-devel \\

libjpeg-devel \\

libpng-devel \\

gstreamer-devel \\

libavc1394-devel \\

libraw1394-devel \\

libdc1394-devel \\

jasper-devel \\

jasper-utils \\

swig \\

python \\

libtool \\

nasm \\

build-essential \\

ant \\

unzip \\

;

RUN set -eux; \\

curl -fL -o opencv-3.4.3.zip https://codeload.github.com/opencv/opencv/zip/3.4.3; \\

unzip opencv-3.4.3.zip; \\

rm -rf opencv-3.4.3.zip; \\

cd opencv-3.4.3; \\

mkdir build; \\

cd build; \\

cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local …; \\

make; \\

make install; \\

cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -DBUILD_TESTS=OFF …;\\

make -j8; \\

make install

  • 写完之后执行docker build -t bolingcavalry/opencv3.4.3:0.0.3 .即可生成镜像,如果您有hub.docker.com的账号,还可以将其推送到中央仓库,给更多人使用

  • 用history命令看看镜像内容,详情如下,倒吸一口凉气,这么大的体积,亲爱的读者们会不会打死我…:

CN0014009475M:~ will$ docker history bolingcavalry/opencv3.4.3:0.0.3

IMAGE CREATED CREATED BY SIZE COMMENT

f0306d7a2594 2 days ago /bin/sh -c set -eux; curl -fL -o opencv-… 2.99GB

2 days ago /bin/sh -c set -eux; yum install -y … 638MB

2 days ago /bin/sh -c echo “export LC_ALL=en_US.UTF-8” … 1.84kB

2 days ago /bin/sh -c set -eux; arch="$(objdump… 209MB

2 days ago /bin/sh -c #(nop) ENV LANG=C.UTF-8 0B

2 days ago /bin/sh -c #(nop) ENV PATH=/usr/java/openjd… 0B

2 days ago /bin/sh -c #(nop) ENV JAVA_HOME=/usr/java/o… 0B

2 days ago /bin/sh -c set -eux; yum install -y … 144MB

2 years ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B

2 years ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B

2 years ago /bin/sh -c #(nop) ADD file:54b004357379717df… 202MB

  • 我这里已经推送到hub.docker.com上去了,执行以下命令即可下载到本地:

Java版人脸检测详解下篇:编码

欢迎访问我的GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos

本篇概览

  1. 准备好docker基础镜像
  2. 开发java应用
  3. 将java应用打包成package文件,集成到基础镜像中,得到最终的java应用镜像

版本信息

  • 这个java应用的涉及的版本信息如下:
  1. springboot:2.4.8
  2. javacpp:1.4.3
  3. javacv:1.4.3

源码下载

  • 本篇实战中的完整源码可在GitHub下载到,地址和链接信息如下表所示(https://github.com/zq2599/blog_demos):
名称链接备注
项目主页https://github.com/zq2599/blog_demos该项目在GitHub上的主页
git仓库地址(https)https://github.com/zq2599/blog_demos.git该项目源码的仓库地址,https协议
git仓库地址(ssh)git@github.com:zq2599/blog_demos.git该项目源码的仓库地址,ssh协议
  • 这个git项目中有多个文件夹,本篇的源码在javacv-tutorials文件夹下,如下图红框所示:

编码

  • 为了统一管理源码和jar依赖,项目采用了maven父子结构,父工程名为javacv-tutorials,其pom.xml如下,可见主要是定义了一些jar的版本:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.bolingcavalry</groupId>
    <artifactId>javacv-tutorials</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>face-detect-demo</module>
    </modules>

    <properties>
        <java.version>1.8</java.version>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <maven-compiler-plugin.version>3.6.1</maven-compiler-plugin.version>
        <springboot.version>2.4.8</springboot.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>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.18</version>
            </dependency>

            <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>
        </dependencies>

    </dependencyManagement>
</project>
  • javacv-tutorials下面新建名为face-detect-demo的子工程,这里面是咱们今天要开发的应用,其pom.xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>javacv-tutorials</artifactId>
        <groupId>com.bolingcavalry</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>face-detect-demo</artifactId>
    <packaging>jar</packaging>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${springboot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <!--FreeMarker模板视图依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>javacv-platform</artifactId>
        </dependency>
        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>javacv</artifactId>
        </dependency>
        <!-- javacpp -->
        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>javacpp</artifactId>
        </dependency>
        <!-- ffmpeg -->
        <dependency>
            <groupId>org.bytedeco.javacpp-presets</groupId>
            <artifactId>ffmpeg-platform</artifactId>
        </dependency>
        <dependency>
            <groupId>org.bytedeco.javacpp-presets</groupId>
            <artifactId>ffmpeg</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <!-- 如果父工程不是springboot,就要用以下方式使用插件,才能生成正常的jar -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <mainClass>com.bolingcavalry.facedetect.FaceDetectApplication</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>
  • 配置文件如下,要重点关注前段模板、文件上传大小、模型文件目录等配置:
### FreeMarker 配置
spring.freemarker.allow-request-override=false
#Enable template caching.启用模板缓存。
spring.freemarker.cache=false
spring.freemarker.check-template-location=true
spring.freemarker.charset=UTF-8
spring.freemarker.content-type=text/html
spring.freemarker.expose-request-attributes=false
spring.freemarker.expose-session-attributes=false
spring.freemarker.expose-spring-macro-helpers=false
#设置面板后缀
spring.freemarker.suffix=.ftl

# 设置单个文件最大内存
spring.servlet.multipart.max-file-size=100MB
# 设置所有文件最大内存
spring.servlet.multipart.max-request-size=1000MB
# 自定义文件上传路径
web.upload-path=/app/images
# 模型路径
opencv.model-path=/app/model/haarcascade_frontalface_default.xml
  • 前端页面文件只有一个index.ftl,请原谅欣宸不入流的前端水平,前端只有一个页面,可以提交页面,同时也是展示处理结果的页面:
<!DOCTYPE html>
<head>
    <meta charset="UTF-8" />
    <title>图片上传Demo</title>
</head>
<body>
<h1 >图片上传Demo</h1>
<form action="fileUpload" method="post" enctype="multipart/form-data">
    <p>选择检测文件: <input type="file" name="fileName"/></p>
    <p>周围检测数量: <input type="number" value="32" name="minneighbors"/></p>
    <p><input type="submit" value="提交"/></p>
</form>
<#--判断是否上传文件-->
<#if msg??>
    <span>${msg}</span><br><br>
<#else >
    <span>${msg!("文件未上传")}</span><br>
</#if>
<#--显示图片,一定要在img中的src发请求给controller,否则直接跳转是乱码-->
<#if fileName??>
<#--<img src="/show?fileName=${fileName}" style="width: 100px"/>-->
<img src="/show?fileName=${fileName}"/>
<#else>
<#--<img src="/show" style="width: 200px"/>-->
</#if>
</body>
</html>
  • 再来看后台代码,先是最常见的应用启动类:
package com.bolingcavalry.facedetect;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class FaceDetectApplication {

    public static void main(String[] args) {
        SpringApplication.run(FaceDetectApplication.class, args);
    }
}
  • 前端上传图片后,后端要做哪些处理呢?先不贴代码,咱们把后端要做的事情捋一遍,如下图:

  • 接下来是最核心的业务类UploadController.java,web接口和业务逻辑处理都在这里面,是按照上图的流程顺序执行的,有几处要注意的地方稍后会提到:

package com.bolingcavalry.facedetect.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ResourceLoader;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.Map;
import org.opencv.core.*;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;

import java.util.UUID;

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

@Controller
@Slf4j
public class UploadController {

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

    private final ResourceLoader resourceLoader;

    @Autowired
    public UploadController(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    @Value("${web.upload-path}")
    private String uploadPath;

    @Value("${opencv.model-path}")
    private String modelPath;

    /**
     * 跳转到文件上传页面
     * @return
     */
    @RequestMapping("index")
    public String toUpload(){
        return "index";
    }

    /**
     * 上次文件到指定目录
     * @param file 文件
     * @param path 文件存放路径
     * @param fileName 源文件名
     * @return
     */
    private static boolean upload(MultipartFile file, String path, String fileName){
        //使用原文件名
        String realPath = path + "/" + fileName;

        File dest = new File(realPath);

        //判断文件父目录是否存在
        if(!dest.getParentFile().exists()){
            dest.getParentFile().mkdir();
        }

        try {
            //保存文件
            file.transferTo(dest);
            return true;
        } catch (IllegalStateException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return false;
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return false;
        }
    }

    /**
     *
     * @param file 要上传的文件
     * @return
     */
    @RequestMapping("fileUpload")
    public String upload(@RequestParam("fileName") MultipartFile file, @RequestParam("minneighbors") int minneighbors, Map<String, Object> map){
        log.info("file [{}], size [{}], minneighbors [{}]", file.getOriginalFilename(), file.getSize(), minneighbors);

        String originalFileName = file.getOriginalFilename以上是关于Java版人脸检测详解上篇:运行环境的Docker镜像(CentOS+JDK+OpenCV)的主要内容,如果未能解决你的问题,请参考以下文章

Java版人脸检测详解下篇:编码

Java版人脸检测详解下篇:编码

Docker容器 - windows版docker的安装与运行环境检测

Docker容器 - windows版docker的安装与运行环境检测

视频人脸检测——Dlib版

三分钟极速体验:Java版人脸检测