| 名称 | 链接 | 备注 |
| :-- | :-- | :-- |
| 项目主页 | 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的版本:
<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”>
4.0.0
com.bolingcavalry
javacv-tutorials
pom
1.0-SNAPSHOT
face-detect-demo
<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.version>1.4.3</javacpp.version>
<opencv.version>3.4.3</opencv.version>
<ffmpeg.version>4.0.2</ffmpeg.version>
org.projectlombok
lombok
1.18.18
org.bytedeco
javacv-platform
${javacpp.version}
org.bytedeco
javacv
${javacpp.version}
org.bytedeco
javacpp
${javacpp.version}
org.bytedeco.javacpp-presets
ffmpeg-platform
f f m p e g . v e r s i o n − {ffmpeg.version}- ffmpeg.version−{javacpp.version}
org.bytedeco.javacpp-presets
ffmpeg
f f m p e g . v e r s i o n − {ffmpeg.version}- ffmpeg.version−{javacpp.version}
- 在javacv-tutorials下面新建名为face-detect-demo的子工程,这里面是咱们今天要开发的应用,其pom.xml如下:
<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”>
javacv-tutorials
com.bolingcavalry
1.0-SNAPSHOT
4.0.0
face-detect-demo
jar
org.springframework.boot
spring-boot-dependencies
${springboot.version}
pom
import
org.springframework.boot
spring-boot-starter-freemarker
org.springframework.boot
spring-boot-starter-web
org.projectlombok
lombok
org.springframework.boot
spring-boot-starter-test
test
org.bytedeco
javacv-platform
org.bytedeco
javacv
org.bytedeco
javacpp
org.bytedeco.javacpp-presets
ffmpeg-platform
org.bytedeco.javacpp-presets
ffmpeg
org.springframework.boot
spring-boot-maven-plugin
com.bolingcavalry.facedetect.FaceDetectApplication
repackage
- 配置文件如下,要重点关注前段模板、文件上传大小、模型文件目录等配置:
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,请原谅欣宸不入流的前端水平,前端只有一个页面,可以提交页面,同时也是展示处理结果的页面:
图片上传Demo
选择检测文件:
周围检测数量:
<#–判断是否上传文件–>
<#if msg??>
${msg}
<#else >
${msg!(“文件未上传”)}
</#if>
<#–显示图片,一定要在img中的src发请求给controller,否则直接跳转是乱码–>
<#if fileName??>
<#––>
<#else>
<#––>
</#if>
- 再来看后台代码,先是最常见的应用启动类:
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();
if (!upload(file, uploadPath, originalFileName)){
map.put(“msg”, “上传失败!”);
return “forward:/index”;
}
String realPath = uploadPath + “/” + originalFileName;
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Java开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
ath, originalFileName)){
map.put(“msg”, “上传失败!”);
return “forward:/index”;
}
String realPath = uploadPath + “/” + originalFileName;
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-TW4knKoa-1715756715327)]
[外链图片转存中…(img-61LneZMB-1715756715327)]
[外链图片转存中…(img-5vbMPKxY-1715756715327)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Java开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!