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
本篇概览
- 如果您看过《三分钟极速体验:Java版人脸检测》一文,甚至动手实际操作过,您应该会对背后的技术细节感兴趣,开发这样一个应用,咱们总共要做以下三件事:
- 准备好docker基础镜像
- 开发java应用
- 将java应用打包成package文件,集成到基础镜像中,得到最终的java应用镜像
- 对于准备好docker基础镜像这项工作,咱们在前文《Java版人脸检测详解上篇:运行环境的Docker镜像(CentOS+JDK+OpenCV)》已经完成了,接下来要做的就是开发java应用并将其做成docker镜像
版本信息
- 这个java应用的涉及的版本信息如下:
- springboot:2.4.8
- javacpp:1.4.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)的主要内容,如果未能解决你的问题,请参考以下文章
Docker容器 - windows版docker的安装与运行环境检测