parent
b007381a2c
commit
b8e7422a60
|
@ -1,9 +1,378 @@
|
|||
# 视频模块接口文档
|
||||
\# 视频模块接口文档
|
||||
|
||||
\## 基础信息
|
||||
|
||||
## 基础信息
|
||||
- 基础路径: `/api/videos`
|
||||
- 请求头: 需要携带 `Authorization: Bearer {token}` (除了获取视频列表和视频详情)
|
||||
|
||||
## 接口列表
|
||||
\## 接口列表
|
||||
|
||||
### 1. 上传视频
|
||||
\### 1. 上传视频
|
||||
|
||||
POST /api/videos/upload
|
||||
|
||||
// 请求参数 (multipart/form-data)
|
||||
|
||||
{
|
||||
|
||||
file: File, // 视频文件
|
||||
|
||||
title: string, // 视频标题
|
||||
|
||||
description: string, // 视频描述
|
||||
|
||||
tags?: string // 视频标签,可选,多个标签用逗号分隔
|
||||
|
||||
}
|
||||
|
||||
// 响应
|
||||
|
||||
{
|
||||
|
||||
code: number, // 200表示成功
|
||||
|
||||
message: string, // 响应消息
|
||||
|
||||
data: {
|
||||
|
||||
id: number, // 视频ID
|
||||
|
||||
title: string, // 视频标题
|
||||
|
||||
description: string, // 视频描述
|
||||
|
||||
url: string, // 视频URL
|
||||
|
||||
coverUrl: string, // 封面URL
|
||||
|
||||
duration: number, // 视频时长(秒)
|
||||
|
||||
size: number, // 文件大小(字节)
|
||||
|
||||
status: string, // 状态:DRAFT-草稿,PUBLISHED-已发布,DELETED-已删除
|
||||
|
||||
userId: number, // 上传用户ID
|
||||
|
||||
username: string, // 上传用户名
|
||||
|
||||
createdTime: string, // 创建时间
|
||||
|
||||
updatedTime: string, // 更新时间
|
||||
|
||||
viewCount: number, // 观看次数
|
||||
|
||||
likeCount: number, // 点赞次数
|
||||
|
||||
tags: string, // 标签
|
||||
|
||||
hasLiked: boolean // 当前用户是否已点赞
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
\### 2. 获取视频列表
|
||||
|
||||
GET /api/videos?pageNum=1&pageSize=10&keyword=xxx
|
||||
|
||||
// 请求参数 (query)
|
||||
|
||||
{
|
||||
|
||||
pageNum?: number, // 页码,默认1
|
||||
|
||||
pageSize?: number, // 每页条数,默认10
|
||||
|
||||
keyword?: string // 搜索关键词,可选
|
||||
|
||||
}
|
||||
|
||||
// 响应
|
||||
|
||||
{
|
||||
|
||||
code: number,
|
||||
|
||||
message: string,
|
||||
|
||||
data: {
|
||||
|
||||
records: Array<{ // 视频列表
|
||||
|
||||
id: number,
|
||||
|
||||
title: string,
|
||||
|
||||
description: string,
|
||||
|
||||
url: string,
|
||||
|
||||
coverUrl: string,
|
||||
|
||||
duration: number,
|
||||
|
||||
size: number,
|
||||
|
||||
status: string,
|
||||
|
||||
userId: number,
|
||||
|
||||
username: string,
|
||||
|
||||
createdTime: string,
|
||||
|
||||
updatedTime: string,
|
||||
|
||||
viewCount: number,
|
||||
|
||||
likeCount: number,
|
||||
|
||||
tags: string,
|
||||
|
||||
hasLiked: boolean
|
||||
|
||||
}>,
|
||||
|
||||
total: number, // 总记录数
|
||||
|
||||
size: number, // 每页条数
|
||||
|
||||
current: number, // 当前页码
|
||||
|
||||
pages: number // 总页数
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
\### 3. 获取视频详情
|
||||
|
||||
GET /api/videos/{id}
|
||||
|
||||
// 响应
|
||||
|
||||
{
|
||||
|
||||
code: number,
|
||||
|
||||
message: string,
|
||||
|
||||
data: {
|
||||
|
||||
id: number,
|
||||
|
||||
title: string,
|
||||
|
||||
description: string,
|
||||
|
||||
url: string,
|
||||
|
||||
coverUrl: string,
|
||||
|
||||
duration: number,
|
||||
|
||||
size: number,
|
||||
|
||||
status: string,
|
||||
|
||||
userId: number,
|
||||
|
||||
username: string,
|
||||
|
||||
createdTime: string,
|
||||
|
||||
updatedTime: string,
|
||||
|
||||
viewCount: number,
|
||||
|
||||
likeCount: number,
|
||||
|
||||
tags: string,
|
||||
|
||||
hasLiked: boolean
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
\### 4. 更新视频信息
|
||||
|
||||
PUT /api/videos/{id}
|
||||
|
||||
// 请求体
|
||||
|
||||
{
|
||||
|
||||
title: string,
|
||||
|
||||
description: string,
|
||||
|
||||
tags?: string
|
||||
|
||||
}
|
||||
|
||||
// 响应
|
||||
|
||||
{
|
||||
|
||||
code: number,
|
||||
|
||||
message: string,
|
||||
|
||||
data: VideoDTO // 同上面的视频详情
|
||||
|
||||
}
|
||||
|
||||
\### 5. 删除视频
|
||||
|
||||
DELETE /api/videos/{id}
|
||||
|
||||
// 响应
|
||||
|
||||
{
|
||||
|
||||
code: number,
|
||||
|
||||
message: string,
|
||||
|
||||
data: null
|
||||
|
||||
}
|
||||
|
||||
\### 6. 视频点赞/取消点赞
|
||||
|
||||
POST /api/videos/{id}/like
|
||||
|
||||
// 响应
|
||||
|
||||
{
|
||||
|
||||
code: number,
|
||||
|
||||
message: string,
|
||||
|
||||
data: null
|
||||
|
||||
}
|
||||
|
||||
\### 7. 增加观看次数
|
||||
|
||||
POST /api/videos/{id}/view
|
||||
|
||||
// 响应
|
||||
|
||||
{
|
||||
|
||||
code: number,
|
||||
|
||||
message: string,
|
||||
|
||||
data: null
|
||||
|
||||
}
|
||||
|
||||
\### 8. 获取推荐视频
|
||||
|
||||
GET /api/videos/recommend?limit=10
|
||||
|
||||
// 请求参数 (query)
|
||||
|
||||
{
|
||||
|
||||
limit?: number // 返回数量,默认10
|
||||
|
||||
}
|
||||
|
||||
// 响应
|
||||
|
||||
{
|
||||
|
||||
code: number,
|
||||
|
||||
message: string,
|
||||
|
||||
data: Array<VideoDTO> // 视频列表
|
||||
|
||||
}
|
||||
|
||||
\### 9. 获取相似视频
|
||||
|
||||
GET /api/videos/{id}/similar?limit=10
|
||||
|
||||
// 请求参数 (query)
|
||||
|
||||
{
|
||||
|
||||
limit?: number // 返回数量,默认10
|
||||
|
||||
}
|
||||
|
||||
// 响应
|
||||
|
||||
{
|
||||
|
||||
code: number,
|
||||
|
||||
message: string,
|
||||
|
||||
data: Array<VideoDTO> // 视频列表
|
||||
|
||||
}
|
||||
|
||||
\## 错误码说明
|
||||
|
||||
{
|
||||
|
||||
200: "操作成功",
|
||||
|
||||
400: "请求参数错误",
|
||||
|
||||
401: "未登录或token已过期",
|
||||
|
||||
403: "无权限执行此操作",
|
||||
|
||||
404: "资源不存在",
|
||||
|
||||
500: "服务器内部错误"
|
||||
|
||||
}
|
||||
|
||||
\## 数据结构
|
||||
|
||||
\### VideoDTO
|
||||
|
||||
{
|
||||
|
||||
id: number; // 视频ID
|
||||
|
||||
title: string; // 视频标题
|
||||
|
||||
description: string; // 视频描述
|
||||
|
||||
url: string; // 视频URL
|
||||
|
||||
coverUrl: string; // 封面URL
|
||||
|
||||
duration: number; // 视频时长(秒)
|
||||
|
||||
size: number; // 文件大小(字节)
|
||||
|
||||
status: string; // 状态:DRAFT-草稿,PUBLISHED-已发布,DELETED-已删除
|
||||
|
||||
userId: number; // 上传用户ID
|
||||
|
||||
username: string; // 上传用户名
|
||||
|
||||
createdTime: string; // 创建时间
|
||||
|
||||
updatedTime: string; // 更新时间
|
||||
|
||||
viewCount: number; // 观看次数
|
||||
|
||||
likeCount: number; // 点赞次数
|
||||
|
||||
tags: string; // 标签,多个用逗号分隔
|
||||
|
||||
hasLiked: boolean; // 当前用户是否已点赞
|
||||
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
## 基础信息
|
||||
- 基础路径: `/api/videos`
|
||||
- 请求头: 需要携带 `Authorization: Bearer {token}` (除了获取视频列表和视频详情)
|
||||
- 请求头: 需要携带 `Authorization: Bearer {token}` (除了获取视频列表和视频详情)
|
||||
|
||||
## 接口列表
|
||||
|
||||
|
|
9
pom.xml
9
pom.xml
|
@ -214,6 +214,15 @@
|
|||
<version>2.3.0</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.arcsoft.face</groupId>
|
||||
<artifactId>arcsoft-sdk-face</artifactId>
|
||||
<version>4.1.1.0</version>
|
||||
<!-- <scope>system</scope>-->
|
||||
<!-- <systemPath>${project.basedir}/libs/arcsoft-sdk-face-3.0.0.0.jar</systemPath>-->
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
import torch
|
||||
import torch.nn as nn
|
||||
import torch.optim as optim
|
||||
import pandas as pd
|
||||
from sklearn.preprocessing import StandardScaler
|
||||
|
||||
class RecommendModel(nn.Module):
|
||||
def __init__(self, input_size, embedding_size):
|
||||
super().__init__()
|
||||
self.encoder = nn.Sequential(
|
||||
nn.Linear(input_size, 256),
|
||||
nn.ReLU(),
|
||||
nn.Dropout(0.3),
|
||||
nn.Linear(256, 128),
|
||||
nn.ReLU(),
|
||||
nn.Linear(128, embedding_size)
|
||||
)
|
||||
|
||||
def forward(self, x):
|
||||
return self.encoder(x)
|
||||
|
||||
def train_model():
|
||||
# 加载数据
|
||||
videos_df = pd.read_csv('videos.csv')
|
||||
behaviors_df = pd.read_csv('behaviors.csv')
|
||||
|
||||
# 数据预处理
|
||||
scaler = StandardScaler()
|
||||
features = scaler.fit_transform(videos_df[['duration', 'view_count', 'like_count']])
|
||||
|
||||
# 创建模型
|
||||
model = RecommendModel(input_size=features.shape[1], embedding_size=128)
|
||||
criterion = nn.CosineEmbeddingLoss()
|
||||
optimizer = optim.Adam(model.parameters())
|
||||
|
||||
# 训练模型
|
||||
for epoch in range(100):
|
||||
# ... 训练代码
|
||||
|
||||
# 保存模型
|
||||
torch.save(model.state_dict(), '../src/main/resources/models/recommend_model.pt')
|
||||
|
||||
if __name__ == '__main__':
|
||||
train_model()
|
|
@ -2,15 +2,15 @@ package com.guwan.backend.Handler;
|
|||
|
||||
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
||||
import org.apache.ibatis.reflection.MetaObject;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
public class MyMetaObjectHandler implements MetaObjectHandler {
|
||||
@Override
|
||||
public void insertFill(MetaObject metaObject) {
|
||||
this.strictInsertFill(metaObject, "createdTime", LocalDateTime.class, LocalDateTime.now());
|
||||
this.strictInsertFill(metaObject, "updatedTime", LocalDateTime.class, LocalDateTime.now());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
package com.guwan.backend;
|
||||
|
||||
import io.jsonwebtoken.security.Keys;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
public class JwtExample {
|
||||
public static void main(String[] args) {
|
||||
// 选择您的 HMAC-SHA 算法
|
||||
SignatureAlgorithm algorithm = SignatureAlgorithm.HS256;
|
||||
|
||||
// 使用推荐的密钥生成方法生成密钥
|
||||
SecretKey key = Keys.secretKeyFor(algorithm);
|
||||
|
||||
System.out.println("key = " + key);
|
||||
|
||||
SecretKey key2 = Keys.secretKeyFor(SignatureAlgorithm.HS512);
|
||||
System.out.println("key2 = " + key2);
|
||||
|
||||
// 现在 key 是一个足够安全的密钥,可以用于 JWT 签名
|
||||
// 您可以使用这个密钥来创建和验证 JWT
|
||||
}
|
||||
}
|
|
@ -1,15 +1,15 @@
|
|||
package com.guwan.backend.config;
|
||||
|
||||
import io.swagger.v3.oas.models.Components;
|
||||
import io.swagger.v3.oas.models.OpenAPI;
|
||||
import io.swagger.v3.oas.models.info.Info;
|
||||
import io.swagger.v3.oas.models.info.License;
|
||||
import io.swagger.v3.oas.models.Components;
|
||||
import io.swagger.v3.oas.models.security.SecurityScheme;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import javax.annotation.PostConstruct;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Configuration
|
||||
|
|
|
@ -31,7 +31,7 @@ public class SecurityConstants {
|
|||
public static final List<String> STATIC_RESOURCES = List.of(
|
||||
"/static/**", // 静态资源目录
|
||||
"/public/**", // 公共资源目录
|
||||
"/error", // 错误页面
|
||||
"/swagger-ui.html"
|
||||
"/error" // 错误页面
|
||||
|
||||
);
|
||||
}
|
|
@ -1,18 +1,33 @@
|
|||
package com.guwan.backend.controller;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import com.arcsoft.face.ActiveDeviceInfo;
|
||||
import com.arcsoft.face.ActiveFileInfo;
|
||||
import com.arcsoft.face.FaceEngine;
|
||||
import com.arcsoft.face.FaceInfo;
|
||||
import com.arcsoft.face.enums.ExtractType;
|
||||
import com.arcsoft.face.toolkit.ImageFactory;
|
||||
import com.arcsoft.face.toolkit.ImageInfo;
|
||||
import com.guwan.backend.common.Result;
|
||||
import com.guwan.backend.service.EmailService;
|
||||
import com.guwan.backend.util.RedisUtils;
|
||||
import com.guwan.backend.util.SmsUtils;
|
||||
import com.guwan.backend.face.dto.FaceRecognitionResDTO;
|
||||
import com.guwan.backend.face.service.FaceEngineService;
|
||||
import com.guwan.backend.util.MinioUtil;
|
||||
import io.minio.GetObjectArgs;
|
||||
import io.minio.MinioClient;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.thymeleaf.context.Context;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
|
@ -21,6 +36,160 @@ import org.thymeleaf.context.Context;
|
|||
@Validated
|
||||
public class DemoController {
|
||||
|
||||
@Autowired
|
||||
private FaceEngineService faceEngineService;
|
||||
|
||||
@Autowired
|
||||
private MinioClient minioClient;
|
||||
|
||||
@Autowired
|
||||
private MinioUtil minioUtil;
|
||||
|
||||
@PostMapping("/uploadFile")
|
||||
public Result<String> uploadFile(String bucketName, MultipartFile file){
|
||||
return Result.success(minioUtil.getUrl(minioUtil.getFileUrl
|
||||
(bucketName, minioUtil.uploadFile(bucketName, file))));
|
||||
}
|
||||
|
||||
|
||||
public int saveTenPerson() {
|
||||
|
||||
try {
|
||||
|
||||
try {
|
||||
GetObjectArgs args = GetObjectArgs.builder()
|
||||
.bucket("images")
|
||||
.object("test/webwxgetmsgimg.jpg")
|
||||
.build();
|
||||
|
||||
//判断人脸照片是否合格
|
||||
//1.保存到本地
|
||||
InputStream tempInputStream = minioClient.getObject(args);
|
||||
//----------------算法检测----------------------------------------------
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
|
||||
byte[] buffer = new byte[1024];
|
||||
int length;
|
||||
while ((length = tempInputStream.read(buffer)) != -1) {
|
||||
outputStream.write(buffer, 0, length);
|
||||
}
|
||||
|
||||
byte[] bytes = outputStream.toByteArray();
|
||||
outputStream.close();
|
||||
tempInputStream.close();
|
||||
|
||||
ImageInfo rgbData = ImageFactory.getRGBData(bytes);
|
||||
List<FaceInfo> faceInfoList = faceEngineService.detectFaces(rgbData);
|
||||
if (CollectionUtil.isNotEmpty(faceInfoList)) {
|
||||
FaceInfo faceInfo = faceInfoList.get(0);
|
||||
FaceRecognitionResDTO faceRecognitionResDTO = new FaceRecognitionResDTO();
|
||||
faceRecognitionResDTO.setRect(faceInfo.getRect());
|
||||
byte[] featureBytes = faceEngineService.extractFaceFeature(rgbData, faceInfo, ExtractType.REGISTER);
|
||||
if (featureBytes != null) {
|
||||
System.out.println("featureBytes = " + featureBytes);
|
||||
}else{
|
||||
log.error("图片不合格,未检测到人脸");
|
||||
return 2;
|
||||
}
|
||||
}else{
|
||||
log.error("图片不合格,未检测到人脸");
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
|
||||
e.printStackTrace();
|
||||
return 10;
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/offline")
|
||||
public Result activeOffline() {
|
||||
FaceEngine faceEngine;
|
||||
String USER_HOME = System.getProperty("user.home");
|
||||
System.out.println(USER_HOME);
|
||||
String jvmName = System.getProperty("java.vm.name", "").toLowerCase();
|
||||
String osName = System.getProperty("os.name", "").toLowerCase();
|
||||
String osArch = System.getProperty("os.arch", "").toLowerCase();
|
||||
String abiType = System.getProperty("sun.arch.abi", "").toLowerCase();
|
||||
String libPath = System.getProperty("sun.boot.library.path", "").toLowerCase();
|
||||
USER_HOME = System.getProperty("user.home");
|
||||
if (jvmName.startsWith("dalvik") && osName.startsWith("linux")) {
|
||||
osName = "android";
|
||||
} else if (jvmName.startsWith("robovm") && osName.startsWith("darwin")) {
|
||||
osName = "ios";
|
||||
osArch = "arm";
|
||||
} else if (osName.startsWith("mac os x") || osName.startsWith("darwin")) {
|
||||
osName = "macosx";
|
||||
} else {
|
||||
int spaceIndex = osName.indexOf(' ');
|
||||
if (spaceIndex > 0) {
|
||||
osName = osName.substring(0, spaceIndex);
|
||||
}
|
||||
}
|
||||
if (osArch.equals("i386") || osArch.equals("i486") || osArch.equals("i586") || osArch.equals("i686")) {
|
||||
osArch = "x86";
|
||||
} else if (osArch.equals("amd64") || osArch.equals("x86-64") || osArch.equals("x64")) {
|
||||
osArch = "x86_64";
|
||||
} else if (osArch.startsWith("aarch64") || osArch.startsWith("armv8") || osArch.startsWith("arm64")) {
|
||||
osArch = "arm64";
|
||||
} else if ((osArch.startsWith("arm")) && ((abiType.equals("gnueabihf")) || (libPath.contains("openjdk-armhf")))) {
|
||||
osArch = "armhf";
|
||||
} else if (osArch.startsWith("arm")) {
|
||||
osArch = "arm";
|
||||
}
|
||||
String PLATFORM = osName + "-" + osArch;
|
||||
|
||||
System.out.println("PLATFORM = " + PLATFORM);
|
||||
|
||||
String CACHE_LIB_FOLDER = USER_HOME + "/.arcface/cache/" + "4.1" + "/" + PLATFORM + "/";
|
||||
|
||||
System.out.println("CACHE_LIB_FOLDER = " + CACHE_LIB_FOLDER);
|
||||
|
||||
if (Pattern.matches("windows.*", osName)) {
|
||||
|
||||
System.out.println("osName = " + osName);
|
||||
faceEngine = new FaceEngine(CACHE_LIB_FOLDER);
|
||||
}else{
|
||||
// faceEngine = new FaceEngine("D:\\00_桌面\\ArcSoft_ArcFacePro_windows_x64_java_V4.1\\libs\\WIN64");
|
||||
faceEngine = new FaceEngine(CACHE_LIB_FOLDER);
|
||||
}
|
||||
|
||||
|
||||
ActiveDeviceInfo activeDeviceInfo = new ActiveDeviceInfo();
|
||||
int code = faceEngine.getActiveDeviceInfo(activeDeviceInfo);
|
||||
|
||||
// System.out.println("\n设备信息:" + activeDeviceInfo.toString() + "\n"); // 这个(com.arcsoft.face.model.ActiveDeviceInfo@4ad9b7b)并不是设备信息
|
||||
System.out.println("设备信息:" + activeDeviceInfo.getDeviceInfo() + "\n"); // 这个的结果才是设备信息
|
||||
|
||||
|
||||
ActiveFileInfo activeFileInfo = new ActiveFileInfo();
|
||||
faceEngine.getActiveFileInfo(activeFileInfo);
|
||||
System.out.println("激活文件信息:" + activeFileInfo.toString());
|
||||
|
||||
System.out.println("activeFileInfo = " + activeFileInfo);
|
||||
|
||||
return Result.success(activeDeviceInfo.getDeviceInfo());
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ public class VideoController {
|
|||
|
||||
|
||||
@Operation(summary = "上传视频", description = "上传视频文件并返回视频信息")
|
||||
@SecurityRequirement(name = "bearer-jwt")
|
||||
// @SecurityRequirement(name = "bearer-jwt")
|
||||
@PostMapping("/upload")
|
||||
public Result<VideoDTO> uploadVideo(
|
||||
@Parameter(description = "视频文件") @RequestParam("file") MultipartFile file,
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
//package com.guwan.backend.face;
|
||||
//
|
||||
//import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
//import lombok.extern.slf4j.Slf4j;
|
||||
//import net.shapelight.common.config.GlobalValue;
|
||||
//import net.shapelight.modules.face.entity.UserCompareInfo;
|
||||
//import net.shapelight.modules.face.service.FaceEngineService;
|
||||
//import net.shapelight.modules.face.util.Base64Util;
|
||||
//import net.shapelight.modules.face.util.UserInfo;
|
||||
//import net.shapelight.modules.face.util.UserRamGroup;
|
||||
//import net.shapelight.modules.ten.entity.TenCellEntity;
|
||||
//import net.shapelight.modules.ten.entity.TenPersonEntity;
|
||||
//import net.shapelight.modules.ten.service.TenCellService;
|
||||
//import net.shapelight.modules.ten.service.TenPersonService;
|
||||
//import org.springframework.beans.factory.annotation.Autowired;
|
||||
//import org.springframework.boot.ApplicationArguments;
|
||||
//import org.springframework.boot.ApplicationRunner;
|
||||
//import org.springframework.core.annotation.Order;
|
||||
//import org.springframework.stereotype.Component;
|
||||
//
|
||||
//import java.util.List;
|
||||
//
|
||||
//@Component
|
||||
//@Order(1)
|
||||
//@Slf4j
|
||||
//public class FaceEngineAutoRun implements ApplicationRunner {
|
||||
// @Autowired
|
||||
// private FaceEngineService faceEngineService;
|
||||
// @Autowired
|
||||
// private TenPersonService tenPersonService;
|
||||
// @Autowired
|
||||
// private TenCellService tenCellService;
|
||||
// @Autowired
|
||||
// private GlobalValue globalValue;
|
||||
//
|
||||
// @Override
|
||||
// public void run(ApplicationArguments args) throws Exception {
|
||||
// // 任务初始化
|
||||
// log.debug("服务启动。。。。。初始化人脸库");
|
||||
//// Map<String, String> fileMap = Maps.newHashMap();
|
||||
//// fileMap.put("zhao1", "赵丽颖");
|
||||
//// fileMap.put("yang1", "杨紫");
|
||||
//// fileMap.put("baixue", "白雪");
|
||||
//// fileMap.put("chenchuang", "陈创");
|
||||
//// for (String f : fileMap.keySet()) {
|
||||
//// ClassPathResource resource = new ClassPathResource("static/images/" + f + ".jpg");
|
||||
//// InputStream inputStream = resource.getInputStream();
|
||||
//// ImageInfo rgbData = ImageFactory.getRGBData(inputStream);
|
||||
//// List<FaceInfo> faceInfoList = faceEngineService.detectFaces(rgbData);
|
||||
//// if (CollectionUtil.isNotEmpty(faceInfoList)) {
|
||||
//// byte[] feature = faceEngineService.extractFaceFeature(rgbData, faceInfoList.get(0), ExtractType.REGISTER);
|
||||
//// UserRamCache.UserInfo userInfo = new UserCompareInfo();
|
||||
//// userInfo.setFaceId(f);
|
||||
//// userInfo.setName(fileMap.get(f));
|
||||
//// userInfo.setFaceFeature(feature);
|
||||
//// //这边注册到内存缓存中,也可以根据业务,注册到数据库中
|
||||
//// UserRamCache.addUser(userInfo);
|
||||
//// }
|
||||
//// }
|
||||
//
|
||||
//// int count = tenPersonService.findCount();
|
||||
//// int pageSize = 1000;
|
||||
//// int page = count/pageSize;
|
||||
//// if(count%1000!=0){
|
||||
//// page = page+1;
|
||||
//// }
|
||||
//// int faceCount = 0;
|
||||
//// for (int i = 0; i < page; i++) {
|
||||
//// int start = i*1000;
|
||||
//// List<TenPersonEntity> listPage = tenPersonService.listPage(start,1000);
|
||||
//// for(TenPersonEntity personEntity: listPage){
|
||||
//// if(personEntity.getFeature()!=null && personEntity.getFeature().length()>0){
|
||||
//// UserRamCache.UserInfo userInfo = new UserCompareInfo();
|
||||
//// userInfo.setFaceId(personEntity.getPersonId()+"");
|
||||
//// userInfo.setName(personEntity.getName());
|
||||
//// userInfo.setFaceFeature(Base64Util.base64ToBytes(personEntity.getFeature()));
|
||||
//// //这边注册到内存缓存中
|
||||
//// UserRamCache.addUser(userInfo);
|
||||
//// faceCount++;
|
||||
//// }
|
||||
//// }
|
||||
//// }
|
||||
//
|
||||
// System.out.println(globalValue.getTenantId());
|
||||
//
|
||||
// List<TenCellEntity> cellList = tenCellService.list(new QueryWrapper<TenCellEntity>()
|
||||
// .eq("tenant_id",globalValue.getTenantId())
|
||||
// .eq("delete_flag",0));
|
||||
// for(TenCellEntity cellEntity: cellList){
|
||||
// String cellId = cellEntity.getCellId()+"";
|
||||
// System.out.println("cellId = " + cellId);
|
||||
// System.out.println("UserRamGroup = " + UserRamGroup.class);
|
||||
// UserRamGroup.addCell(cellId);
|
||||
// UserRamGroup.addOrgId(cellEntity.getOrgId(),cellId);
|
||||
// int count = tenPersonService.findCount(cellId);
|
||||
// int pageSize = 1000;
|
||||
// int page = count/pageSize;
|
||||
// if(count%1000!=0){
|
||||
// page = page+1;
|
||||
// }
|
||||
// int faceCount = 0;
|
||||
// for (int i = 0; i < page; i++) {
|
||||
// int start = i*1000;
|
||||
// List<TenPersonEntity> listPage = tenPersonService.listPage(start,1000, cellId);
|
||||
// for(TenPersonEntity personEntity: listPage){
|
||||
// if(personEntity.getFeature()!=null && personEntity.getFeature().length()>0){
|
||||
// UserInfo userInfo = new UserCompareInfo();
|
||||
// userInfo.setFaceId(personEntity.getPersonId()+"");
|
||||
// userInfo.setName(personEntity.getName());
|
||||
// userInfo.setFaceFeature(Base64Util.base64ToBytes(personEntity.getFeature()));
|
||||
// //这边注册到内存缓存中
|
||||
// UserRamGroup.addUser(userInfo,cellId);
|
||||
// faceCount++;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// log.debug(cellEntity.getName()+":初始化人脸库完成,共 "+faceCount+" 人");
|
||||
// }
|
||||
// }
|
||||
//}
|
|
@ -0,0 +1,133 @@
|
|||
package com.guwan.backend.face.config;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@Configuration
|
||||
public class ArcFaceAutoConfiguration implements InitializingBean, DisposableBean {
|
||||
|
||||
|
||||
private static final String PLATFORM;
|
||||
|
||||
private static final String USER_HOME;
|
||||
|
||||
public static String CACHE_LIB_FOLDER;
|
||||
|
||||
@Value("${config.arcface-sdk.version}")
|
||||
public String ARC_FACE_VERSION;
|
||||
|
||||
static {
|
||||
String jvmName = System.getProperty("java.vm.name", "").toLowerCase();
|
||||
String osName = System.getProperty("os.name", "").toLowerCase();
|
||||
String osArch = System.getProperty("os.arch", "").toLowerCase();
|
||||
String abiType = System.getProperty("sun.arch.abi", "").toLowerCase();
|
||||
String libPath = System.getProperty("sun.boot.library.path", "").toLowerCase();
|
||||
USER_HOME = System.getProperty("user.home");
|
||||
if (jvmName.startsWith("dalvik") && osName.startsWith("linux")) {
|
||||
osName = "android";
|
||||
} else if (jvmName.startsWith("robovm") && osName.startsWith("darwin")) {
|
||||
osName = "ios";
|
||||
osArch = "arm";
|
||||
} else if (osName.startsWith("mac os x") || osName.startsWith("darwin")) {
|
||||
osName = "macosx";
|
||||
} else {
|
||||
int spaceIndex = osName.indexOf(' ');
|
||||
if (spaceIndex > 0) {
|
||||
osName = osName.substring(0, spaceIndex);
|
||||
}
|
||||
}
|
||||
if (osArch.equals("i386") || osArch.equals("i486") || osArch.equals("i586") || osArch.equals("i686")) {
|
||||
osArch = "x86";
|
||||
} else if (osArch.equals("amd64") || osArch.equals("x86-64") || osArch.equals("x64")) {
|
||||
osArch = "x86_64";
|
||||
} else if (osArch.startsWith("aarch64") || osArch.startsWith("armv8") || osArch.startsWith("arm64")) {
|
||||
osArch = "arm64";
|
||||
} else if ((osArch.startsWith("arm")) && ((abiType.equals("gnueabihf")) || (libPath.contains("openjdk-armhf")))) {
|
||||
osArch = "armhf";
|
||||
} else if (osArch.startsWith("arm")) {
|
||||
osArch = "arm";
|
||||
}
|
||||
PLATFORM = osName + "-" + osArch;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws IOException {
|
||||
CACHE_LIB_FOLDER = USER_HOME + "/.arcface/cache/" + ARC_FACE_VERSION + "/" + PLATFORM + "/";
|
||||
loadLibrary();
|
||||
}
|
||||
|
||||
public void loadLibrary() throws IOException {
|
||||
String baseFolder = "";
|
||||
String suffix = ".dll";
|
||||
if ("windows-x86_64".equals(PLATFORM)) {
|
||||
baseFolder = "WIN64";
|
||||
} else if ("windows-x86".equals(PLATFORM)) {
|
||||
baseFolder = "WIN32";
|
||||
} else if ("linux-x86_64".equals(PLATFORM)) {
|
||||
baseFolder = "LINUX64";
|
||||
suffix = ".so";
|
||||
}
|
||||
|
||||
if ("".equals(baseFolder)) {
|
||||
throw new RuntimeException("ArcFace不支持该操作系统");
|
||||
}
|
||||
|
||||
|
||||
File file = new File(CACHE_LIB_FOLDER);
|
||||
if (!file.exists()) {
|
||||
file.mkdirs();
|
||||
}
|
||||
|
||||
List<String> libList = new LinkedList<>();
|
||||
libList.add("libarcsoft_face");
|
||||
libList.add("libarcsoft_face_engine");
|
||||
libList.add("libarcsoft_face_engine_jni");
|
||||
|
||||
for (String lib : libList) {
|
||||
ClassPathResource resource = new ClassPathResource("libs/" + ARC_FACE_VERSION + "/" + baseFolder + "/" + lib + suffix);
|
||||
InputStream inputStream = resource.getInputStream();
|
||||
int faceLength = inputStream.available();
|
||||
File facePath = new File(CACHE_LIB_FOLDER + lib + suffix);
|
||||
if (facePath.exists()) {
|
||||
if (facePath.length() == faceLength) {
|
||||
continue;
|
||||
}
|
||||
facePath.delete();
|
||||
}
|
||||
writeToLocal(CACHE_LIB_FOLDER + lib + suffix, inputStream);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeToLocal(String destination, InputStream input)
|
||||
throws IOException {
|
||||
int index;
|
||||
byte[] bytes = new byte[1024 * 100];
|
||||
FileOutputStream fileOutputStream = new FileOutputStream(destination);
|
||||
while ((index = input.read(bytes)) != -1) {
|
||||
fileOutputStream.write(bytes, 0, index);
|
||||
}
|
||||
fileOutputStream.flush();
|
||||
fileOutputStream.close();
|
||||
input.close();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.guwan.backend.face.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author shentao
|
||||
* @desc
|
||||
* @date 2022/3/30
|
||||
*/
|
||||
@Data
|
||||
public class CompareFacesReqDTO {
|
||||
private String image1;
|
||||
private String image2;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package com.guwan.backend.face.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class FaceAddReqDTO {
|
||||
|
||||
private String name;
|
||||
|
||||
private String image;
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package com.guwan.backend.face.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class FaceDetectReqDTO {
|
||||
|
||||
private String image;
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.guwan.backend.face.dto;
|
||||
|
||||
import com.arcsoft.face.Rect;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class FaceDetectResDTO {
|
||||
private Rect rect;
|
||||
private int orient;
|
||||
private int faceId = -1;
|
||||
private int age = -1;
|
||||
private int gender = -1;
|
||||
private int liveness = -1;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package com.guwan.backend.face.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class FaceRecognitionReqDTO {
|
||||
|
||||
private String image;
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.guwan.backend.face.dto;
|
||||
|
||||
|
||||
import com.arcsoft.face.Rect;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class FaceRecognitionResDTO {
|
||||
|
||||
private Rect rect;
|
||||
private String personId;
|
||||
private String name;
|
||||
private float similar;
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.guwan.backend.face.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class GetFaceListResDTO {
|
||||
|
||||
private String id;
|
||||
|
||||
private String name;
|
||||
|
||||
private String url;
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package com.guwan.backend.face.entity;
|
||||
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ProcessInfo {
|
||||
private int age;
|
||||
private int gender;
|
||||
private int liveness;
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package com.guwan.backend.face.entity;
|
||||
|
||||
|
||||
import com.guwan.backend.face.util.UserInfo;
|
||||
import lombok.Data;
|
||||
|
||||
|
||||
@Data
|
||||
public class UserCompareInfo extends UserInfo {
|
||||
private Float similar;
|
||||
private Integer isHeadOnView; //0否1是
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package com.guwan.backend.face.enums;
|
||||
|
||||
|
||||
import com.guwan.backend.face.rpc.ErrorCode;
|
||||
import lombok.Getter;
|
||||
|
||||
|
||||
@Getter
|
||||
public enum ErrorCodeEnum implements ErrorCode {
|
||||
|
||||
/**
|
||||
* 成功
|
||||
*/
|
||||
SUCCESS(0, "success", "成功"),
|
||||
FAIL(1, "fail", "失败"),
|
||||
PARAM_ERROR(2, "param error", "参数错误"),
|
||||
SYSTEM_ERROR(999, "system error", "系统错误"),
|
||||
|
||||
;
|
||||
private Integer code;
|
||||
private String desc;
|
||||
private String descCN;
|
||||
|
||||
ErrorCodeEnum(Integer code, String desc) {
|
||||
this.code = code;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
ErrorCodeEnum(Integer code, String desc, String descCN) {
|
||||
this.code = code;
|
||||
this.desc = desc;
|
||||
this.descCN = descCN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDesc() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescCN() {
|
||||
return descCN;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package com.guwan.backend.face.face;
|
||||
|
||||
import com.arcsoft.face.FaceInfo;
|
||||
|
||||
public class FacePreviewInfo {
|
||||
private FaceInfo faceInfo;
|
||||
private int trackId;
|
||||
private int gender = -1;
|
||||
|
||||
public FacePreviewInfo(FaceInfo faceInfo, int trackId) {
|
||||
this.faceInfo = faceInfo;
|
||||
this.trackId = trackId;
|
||||
}
|
||||
|
||||
public FacePreviewInfo(FaceInfo faceInfo, int trackId, int gender) {
|
||||
this.faceInfo = faceInfo;
|
||||
this.trackId = trackId;
|
||||
this.gender = gender;
|
||||
}
|
||||
|
||||
public int getGender() {
|
||||
return gender;
|
||||
}
|
||||
|
||||
public void setGender(int gender) {
|
||||
this.gender = gender;
|
||||
}
|
||||
|
||||
public FaceInfo getFaceInfo() {
|
||||
return faceInfo;
|
||||
}
|
||||
|
||||
public void setFaceInfo(FaceInfo faceInfo) {
|
||||
this.faceInfo = faceInfo;
|
||||
}
|
||||
|
||||
|
||||
public int getTrackId() {
|
||||
return trackId;
|
||||
}
|
||||
|
||||
public void setTrackId(int trackId) {
|
||||
this.trackId = trackId;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,292 @@
|
|||
package com.guwan.backend.face.face;
|
||||
|
||||
import com.arcsoft.face.*;
|
||||
import com.arcsoft.face.enums.DetectMode;
|
||||
import com.arcsoft.face.enums.ErrorInfo;
|
||||
import com.arcsoft.face.enums.ExtractType;
|
||||
import com.arcsoft.face.toolkit.ImageFactory;
|
||||
import com.arcsoft.face.toolkit.ImageInfo;
|
||||
import com.guwan.backend.face.config.ArcFaceAutoConfiguration;
|
||||
import com.guwan.backend.face.factory.FaceEngineFactory;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.pool2.impl.GenericObjectPool;
|
||||
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
@Slf4j
|
||||
public final class FaceRecognize {
|
||||
|
||||
/**
|
||||
* VIDEO模式人脸检测引擎,用于预览帧人脸追踪
|
||||
*/
|
||||
private static FaceEngine ftEngine;
|
||||
|
||||
/**
|
||||
* 人脸注册引擎
|
||||
*/
|
||||
private static FaceEngine regEngine;
|
||||
|
||||
/**
|
||||
* 用于人脸识别的引擎池
|
||||
*/
|
||||
private static GenericObjectPool<FaceEngine> frEnginePool;
|
||||
|
||||
|
||||
private static volatile ConcurrentHashMap<Integer, FaceResult> faceResultRegistry = new ConcurrentHashMap<>();
|
||||
|
||||
private static ExecutorService frService = Executors.newFixedThreadPool(20);
|
||||
|
||||
public static ConcurrentHashMap<String, byte[]> faceFeatureRegistry = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 初始化引擎
|
||||
*/
|
||||
public void initEngine(String appId, String sdkKey, String activeKey, String activeFile) {
|
||||
|
||||
//引擎配置
|
||||
ftEngine = new FaceEngine(ArcFaceAutoConfiguration.CACHE_LIB_FOLDER);
|
||||
int activeCode;
|
||||
if (StringUtils.isNotEmpty(activeFile)) {
|
||||
activeCode = ftEngine.activeOffline(activeFile);
|
||||
} else {
|
||||
activeCode = ftEngine.activeOnline(appId, sdkKey, activeKey);
|
||||
}
|
||||
|
||||
EngineConfiguration ftEngineCfg = new EngineConfiguration();
|
||||
ftEngineCfg.setDetectMode(DetectMode.ASF_DETECT_MODE_VIDEO);
|
||||
ftEngineCfg.setFunctionConfiguration(FunctionConfiguration.builder().supportFaceDetect(true).build());
|
||||
int ftInitCode = ftEngine.init(ftEngineCfg);
|
||||
|
||||
//引擎配置
|
||||
regEngine = new FaceEngine(ArcFaceAutoConfiguration.CACHE_LIB_FOLDER);
|
||||
|
||||
EngineConfiguration regEngineCfg = new EngineConfiguration();
|
||||
regEngineCfg.setDetectMode(DetectMode.ASF_DETECT_MODE_IMAGE);
|
||||
regEngineCfg.setFunctionConfiguration(FunctionConfiguration.builder().supportFaceDetect(true).supportFaceRecognition(true).build());
|
||||
int regInitCode = regEngine.init(regEngineCfg);
|
||||
|
||||
|
||||
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
|
||||
poolConfig.setMaxIdle(5);
|
||||
poolConfig.setMaxTotal(5);
|
||||
poolConfig.setMinIdle(5);
|
||||
poolConfig.setLifo(false);
|
||||
EngineConfiguration frEngineCfg = new EngineConfiguration();
|
||||
frEngineCfg.setFunctionConfiguration(FunctionConfiguration.builder().supportFaceRecognition(true).build());
|
||||
frEnginePool = new GenericObjectPool(new FaceEngineFactory(appId, sdkKey, activeKey,activeFile, frEngineCfg), poolConfig);//底层库算法对象池
|
||||
|
||||
|
||||
if (!(activeCode == ErrorInfo.MOK.getValue() || activeCode == ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue())) {
|
||||
log.error("activeCode: " + activeCode);
|
||||
throw new RuntimeException("activeCode: " + activeCode);
|
||||
}
|
||||
if (ftInitCode != ErrorInfo.MOK.getValue()) {
|
||||
log.error("ftInitEngine: " + ftInitCode);
|
||||
throw new RuntimeException("ftInitEngine: " + ftInitCode);
|
||||
}
|
||||
|
||||
if (regInitCode != ErrorInfo.MOK.getValue()) {
|
||||
log.error("regInitEngine: " + regInitCode);
|
||||
throw new RuntimeException("regInitEngine: " + regInitCode);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static void registerFace(String imagePath) {
|
||||
|
||||
log.info("正在注册人脸");
|
||||
|
||||
int count = 0;
|
||||
if (regEngine != null) {
|
||||
File file = new File(imagePath);
|
||||
File[] files = file.listFiles();
|
||||
|
||||
for (File file1 : files) {
|
||||
ImageInfo imageInfo = ImageFactory.getRGBData(file1);
|
||||
if (imageInfo != null) {
|
||||
List<FaceInfo> faceInfoList = new ArrayList<>();
|
||||
int code = regEngine.detectFaces(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(),
|
||||
imageInfo.getImageFormat(), faceInfoList);
|
||||
|
||||
if (code == 0 && faceInfoList.size() > 0) {
|
||||
FaceFeature faceFeature = new FaceFeature();
|
||||
int resCode = regEngine.extractFaceFeature(imageInfo, faceInfoList.get(0), ExtractType.REGISTER, 0, faceFeature);
|
||||
if (resCode == 0) {
|
||||
int lastIndexOf = file1.getName().lastIndexOf(".");
|
||||
String name = file1.getName().substring(0, file1.getName().length() - lastIndexOf - 1);
|
||||
faceFeatureRegistry.put(name, faceFeature.getFeatureData());
|
||||
log.info("成功注册人脸:" + name);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
log.info("人脸注册完成,共注册:" + count + "张人脸");
|
||||
} else {
|
||||
throw new RuntimeException("注册失败,引擎未初始化或初始化失败");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static void registerFace(Map<String, byte[]> face) {
|
||||
face.forEach((k, v) -> {
|
||||
faceFeatureRegistry.put(k, v.clone());
|
||||
});
|
||||
}
|
||||
|
||||
public static void removeFace(String name) {
|
||||
faceFeatureRegistry.remove(name);
|
||||
}
|
||||
|
||||
public static void clearFace() {
|
||||
faceFeatureRegistry.clear();
|
||||
}
|
||||
|
||||
public static FaceResult getFaceResult(FaceInfo faceInfo, ImageInfo imageInfo) {
|
||||
FaceResult faceResult = faceResultRegistry.get(faceInfo.getFaceId());
|
||||
if (faceResult == null) {
|
||||
faceResult = new FaceResult();
|
||||
faceResultRegistry.put(faceInfo.getFaceId(), faceResult);
|
||||
frService.submit(new FaceInfoRunnable(faceInfo, imageInfo, faceResult));
|
||||
} else if (faceResult.isFlag()) {
|
||||
return faceResult;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<FacePreviewInfo> detectFaces(ImageInfo imageInfo) {
|
||||
if (ftEngine != null) {
|
||||
List<FaceInfo> faceInfoList = new ArrayList<>();
|
||||
int code = ftEngine.detectFaces(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(),
|
||||
imageInfo.getImageFormat(), faceInfoList);
|
||||
|
||||
List<FacePreviewInfo> previewInfoList = new LinkedList<>();
|
||||
for (FaceInfo faceInfo : faceInfoList) {
|
||||
FacePreviewInfo facePreviewInfo = new FacePreviewInfo();
|
||||
facePreviewInfo.setFaceInfo(faceInfo);
|
||||
previewInfoList.add(facePreviewInfo);
|
||||
}
|
||||
|
||||
clearFaceResultRegistry(faceInfoList);
|
||||
return previewInfoList;
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private long lastClearTime = System.currentTimeMillis();
|
||||
|
||||
//清理过时的人脸
|
||||
private void clearFaceResultRegistry(List<FaceInfo> faceInfoList) {
|
||||
if (System.currentTimeMillis() - lastClearTime > 5000) {
|
||||
Iterator<Integer> iterator = faceResultRegistry.keySet().iterator();
|
||||
for (; iterator.hasNext(); ) {
|
||||
Integer next = iterator.next();
|
||||
boolean flag = false;
|
||||
for (FaceInfo faceInfo : faceInfoList) {
|
||||
if (next.equals(faceInfo.getFaceId())) {
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
if (!flag) {
|
||||
iterator.remove();
|
||||
}
|
||||
|
||||
}
|
||||
lastClearTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Data
|
||||
public static class FaceResult {
|
||||
private boolean flag = false;
|
||||
private String name;
|
||||
private float score;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Data
|
||||
public class FacePreviewInfo {
|
||||
|
||||
private FaceInfo faceInfo;
|
||||
private int age;
|
||||
private boolean liveness;
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static class FaceInfoRunnable implements Runnable {
|
||||
private FaceInfo faceInfo;
|
||||
private ImageInfo imageInfo;
|
||||
private FaceResult faceResult;
|
||||
|
||||
public FaceInfoRunnable(FaceInfo faceInfo, ImageInfo imageInfo, FaceResult faceResult) {
|
||||
this.faceInfo = faceInfo;
|
||||
this.imageInfo = imageInfo;
|
||||
this.faceResult = faceResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
FaceEngine frEngine = null;
|
||||
try {
|
||||
frEngine = frEnginePool.borrowObject();
|
||||
if (frEngine != null) {
|
||||
FaceFeature faceFeature = new FaceFeature();
|
||||
int resCode = frEngine.extractFaceFeature(imageInfo, faceInfo, ExtractType.RECOGNIZE, 0, faceFeature);
|
||||
if (resCode == 0) {
|
||||
|
||||
float score = 0.0F;
|
||||
Iterator<Map.Entry<String, byte[]>> iterator = faceFeatureRegistry.entrySet().iterator();
|
||||
for (; iterator.hasNext(); ) {
|
||||
Map.Entry<String, byte[]> next = iterator.next();
|
||||
FaceFeature faceFeatureTarget = new FaceFeature();
|
||||
faceFeatureTarget.setFeatureData(next.getValue());
|
||||
|
||||
FaceSimilar faceSimilar = new FaceSimilar();
|
||||
frEngine.compareFaceFeature(faceFeatureTarget, faceFeature, faceSimilar);
|
||||
if (faceSimilar.getScore() > score) {
|
||||
score = faceSimilar.getScore();
|
||||
faceResult.setName(next.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
log.info("相似度:" + score);
|
||||
if (score >= 0.8f) {
|
||||
faceResult.setScore(score);
|
||||
faceResult.setFlag(true);
|
||||
faceResultRegistry.put(faceInfo.getFaceId(), faceResult);
|
||||
} else {
|
||||
faceResultRegistry.remove(faceInfo.getFaceId());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
||||
} finally {
|
||||
if (frEngine != null) {
|
||||
frEnginePool.returnObject(frEngine);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
package com.guwan.backend.face.factory;
|
||||
|
||||
import com.arcsoft.face.EngineConfiguration;
|
||||
import com.arcsoft.face.FaceEngine;
|
||||
import com.arcsoft.face.enums.ErrorInfo;
|
||||
import com.guwan.backend.face.config.ArcFaceAutoConfiguration;
|
||||
import com.guwan.backend.face.enums.ErrorCodeEnum;
|
||||
import com.guwan.backend.face.rpc.BusinessException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.pool2.BasePooledObjectFactory;
|
||||
import org.apache.commons.pool2.PooledObject;
|
||||
import org.apache.commons.pool2.impl.DefaultPooledObject;
|
||||
|
||||
@Slf4j
|
||||
public class FaceEngineFactory extends BasePooledObjectFactory<FaceEngine> {
|
||||
|
||||
private String appId;
|
||||
private String sdkKey;
|
||||
private String activeKey;
|
||||
private String activeFile;
|
||||
private EngineConfiguration engineConfiguration;
|
||||
|
||||
|
||||
public FaceEngineFactory(String appId, String sdkKey, String activeKey, String activeFile, EngineConfiguration engineConfiguration) {
|
||||
this.appId = appId;
|
||||
this.sdkKey = sdkKey;
|
||||
this.activeKey = activeKey;
|
||||
this.activeFile=activeFile;
|
||||
this.engineConfiguration = engineConfiguration;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public FaceEngine create() {
|
||||
FaceEngine faceEngine = new FaceEngine(ArcFaceAutoConfiguration.CACHE_LIB_FOLDER);
|
||||
/* FaceEngine faceEngine = new FaceEngine("/softTemp/jar/82K111TPM121XK4H.dat");*/
|
||||
// FaceEngine faceEngine = new FaceEngine("/home/huangyifang/gb/咸阳师范/ArcSoft_ArcFacePro_linux_java_V4.1/libs/LINUX64/");
|
||||
int activeCode;
|
||||
if (StringUtils.isNotEmpty(activeFile)) {
|
||||
activeCode = faceEngine.activeOffline(activeFile);
|
||||
} else {
|
||||
activeCode = faceEngine.activeOnline(appId, sdkKey, activeKey);
|
||||
}
|
||||
log.debug("引擎激活errorCode:" + activeCode);
|
||||
if (activeCode != ErrorInfo.MOK.getValue() && activeCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue()) {
|
||||
log.error("引擎激活失败" + activeCode);
|
||||
throw new BusinessException(ErrorCodeEnum.FAIL, "引擎激活失败" + activeCode);
|
||||
}
|
||||
int initCode = faceEngine.init(engineConfiguration);
|
||||
if (initCode != ErrorInfo.MOK.getValue()) {
|
||||
log.error("引擎初始化失败" + initCode);
|
||||
throw new BusinessException(ErrorCodeEnum.FAIL, "引擎初始化失败" + initCode);
|
||||
}
|
||||
log.debug("初始化引擎errorCode:" + initCode);
|
||||
return faceEngine;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PooledObject<FaceEngine> wrap(FaceEngine faceEngine) {
|
||||
return new DefaultPooledObject<>(faceEngine);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void destroyObject(PooledObject<FaceEngine> p) throws Exception {
|
||||
FaceEngine faceEngine = p.getObject();
|
||||
int result = faceEngine.unInit();
|
||||
super.destroyObject(p);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package com.guwan.backend.face.rpc;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Author: st7251
|
||||
* @Date: 2018/11/23 14:18
|
||||
*/
|
||||
@Data
|
||||
public class BusinessException extends RuntimeException {
|
||||
private ErrorCode errorCode;
|
||||
private String msg;
|
||||
private String msgCN;
|
||||
|
||||
public BusinessException(Response response) {
|
||||
this.errorCode = new ErrorCode() {
|
||||
@Override
|
||||
public Integer getCode() {
|
||||
return response.getCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDesc() {
|
||||
return response.getMsg();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescCN() {
|
||||
return response.getMsg();
|
||||
}
|
||||
};
|
||||
this.msg=response.getMsg();
|
||||
this.msgCN=response.getMsg();
|
||||
}
|
||||
|
||||
public BusinessException(ErrorCode errorCode) {
|
||||
super(errorCode.getDesc());
|
||||
this.errorCode = errorCode;
|
||||
this.msg= errorCode.getDesc();
|
||||
this.msgCN=errorCode.getDescCN();
|
||||
}
|
||||
|
||||
public BusinessException(ErrorCode errorCode, String msg) {
|
||||
super(errorCode.getDesc());
|
||||
this.errorCode = errorCode;
|
||||
this.msg = msg;
|
||||
this.msgCN=msg;
|
||||
}
|
||||
|
||||
public BusinessException(Throwable cause, ErrorCode errorCode) {
|
||||
super(cause);
|
||||
this.errorCode = errorCode;
|
||||
this.msg= errorCode.getDesc();
|
||||
this.msgCN=errorCode.getDescCN();
|
||||
}
|
||||
|
||||
|
||||
public BusinessException(Throwable cause, ErrorCode errorCode, String msg) {
|
||||
super(cause);
|
||||
this.errorCode = errorCode;
|
||||
this.msg = msg;
|
||||
this.msgCN=msg;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package com.guwan.backend.face.rpc;
|
||||
|
||||
public interface ErrorCode {
|
||||
|
||||
|
||||
Integer getCode();
|
||||
|
||||
String getDesc();
|
||||
|
||||
String getDescCN();
|
||||
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
//package com.guwan.backend.face.rpc;
|
||||
//
|
||||
//
|
||||
//import com.guwan.backend.face.enums.ErrorCodeEnum;
|
||||
//import lombok.extern.slf4j.Slf4j;
|
||||
//import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
//import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
//
|
||||
//@RestControllerAdvice
|
||||
//@Slf4j
|
||||
//public class GlobalExceptionHandler{
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * 自定义异常
|
||||
// */
|
||||
// @ExceptionHandler(BusinessException.class)
|
||||
// public Response businessException(BusinessException e) {
|
||||
// log.error(e.getMessage(), e);
|
||||
// Response response = new Response();
|
||||
// response.setCode(e.getErrorCode().getCode());
|
||||
// response.setMsg(e.getMsgCN());
|
||||
// return response;
|
||||
// }
|
||||
//
|
||||
// @ExceptionHandler(IllegalArgumentException.class)
|
||||
// public Response handleIllegalArgumentException(IllegalArgumentException e) {
|
||||
// log.error(e.getMessage(), e);
|
||||
// Response response = new Response();
|
||||
// response.setCode(ErrorCodeEnum.PARAM_ERROR.getCode());
|
||||
// response.setMsg(e.getMessage());
|
||||
// return response;
|
||||
// }
|
||||
//
|
||||
// @ExceptionHandler(Exception.class)
|
||||
// public Response handleException(Exception e) {
|
||||
// log.error(e.getMessage(), e);
|
||||
// Response response = new Response();
|
||||
// response.setCode(ErrorCodeEnum.SYSTEM_ERROR.getCode());
|
||||
// response.setMsg(ErrorCodeEnum.SYSTEM_ERROR.getDescCN());
|
||||
// return response;
|
||||
// }
|
||||
//
|
||||
//
|
||||
//
|
||||
//// @ExceptionHandler(InternalServerErrorException.class)
|
||||
//// @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
//// public ResponseEntity<String> handleInternalServerErrorException(InternalServerErrorException ex) {
|
||||
//// return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ex.getMessage());
|
||||
//// }
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//}
|
|
@ -0,0 +1,39 @@
|
|||
package com.guwan.backend.face.rpc;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class Response<T> {
|
||||
|
||||
private int code = -1;
|
||||
private String msg = "success";
|
||||
private T data;
|
||||
|
||||
public static <T> Response<T> newSuccessResponse(T data) {
|
||||
return newResponse(data, 0, "success");
|
||||
}
|
||||
|
||||
public static <T> Response<T> newFailedResponse(Integer code, String message) {
|
||||
return newResponse(null, code, message);
|
||||
}
|
||||
|
||||
public static <T> Response<T> newFailedResponse(ErrorCode ErrorCode) {
|
||||
return newResponse(null, ErrorCode.getCode(), ErrorCode.getDesc());
|
||||
}
|
||||
|
||||
public static <T> Response<T> newFailedResponse(ErrorCode ErrorCode, String message) {
|
||||
return newResponse(null, ErrorCode.getCode(), message);
|
||||
}
|
||||
|
||||
public static <T> Response<T> newResponse(T data, Integer code, String message) {
|
||||
Response<T> response = new Response<T>();
|
||||
response.setCode(code);
|
||||
response.setMsg(message);
|
||||
if (data != null && data instanceof String && "".equals(data)) {
|
||||
response.setData(null);
|
||||
} else {
|
||||
response.setData(data);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,483 @@
|
|||
//package com.guwan.backend.face.rtsp;
|
||||
//
|
||||
//import cn.hutool.core.collection.CollectionUtil;
|
||||
//import cn.hutool.json.JSONObject;
|
||||
//import com.arcsoft.face.FaceInfo;
|
||||
//import com.arcsoft.face.enums.ExtractType;
|
||||
//import com.arcsoft.face.toolkit.ImageFactory;
|
||||
//import com.arcsoft.face.toolkit.ImageInfo;
|
||||
//import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
//import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
//import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
//import io.minio.MinioClient;
|
||||
//import io.minio.PutObjectOptions;
|
||||
//import lombok.extern.slf4j.Slf4j;
|
||||
//import net.shapelight.common.config.GlobalValue;
|
||||
//import net.shapelight.common.config.MinioConfig;
|
||||
//import net.shapelight.common.utils.Constant;
|
||||
//import net.shapelight.common.utils.UUIDUtil;
|
||||
//import net.shapelight.modules.face.entity.UserCompareInfo;
|
||||
//import net.shapelight.modules.face.service.FaceEngineService;
|
||||
//import net.shapelight.modules.face.util.UserInfo;
|
||||
//import net.shapelight.modules.face.util.UserRamGroup;
|
||||
//import net.shapelight.modules.feignClient.CxFeignClient;
|
||||
//import net.shapelight.modules.iCq.controller.video.vo.FaceVideoVo;
|
||||
//import net.shapelight.modules.ten.dao.TenCellDao;
|
||||
//import net.shapelight.modules.ten.entity.TenCellEntity;
|
||||
//import net.shapelight.modules.ten.entity.TenPersonEntity;
|
||||
//import net.shapelight.modules.ten.service.TenPersonService;
|
||||
//import net.shapelight.modules.ten.service.impl.TenPersonServiceImpl;
|
||||
//import org.bytedeco.javacpp.avutil;
|
||||
//import org.bytedeco.javacv.FFmpegFrameGrabber;
|
||||
//import org.bytedeco.javacv.Frame;
|
||||
//import org.bytedeco.javacv.FrameGrabber;
|
||||
//import org.bytedeco.javacv.Java2DFrameConverter;
|
||||
//import org.springframework.beans.factory.annotation.Autowired;
|
||||
//import org.springframework.beans.factory.annotation.Value;
|
||||
//import org.springframework.stereotype.Component;
|
||||
//import org.springframework.web.multipart.MultipartFile;
|
||||
//
|
||||
//import javax.imageio.ImageIO;
|
||||
//import java.awt.image.BufferedImage;
|
||||
//import java.io.ByteArrayInputStream;
|
||||
//import java.io.ByteArrayOutputStream;
|
||||
//import java.io.IOException;
|
||||
//import java.io.InputStream;
|
||||
//import java.text.SimpleDateFormat;
|
||||
//import java.util.ArrayList;
|
||||
//import java.util.HashMap;
|
||||
//import java.util.List;
|
||||
//import java.util.Map;
|
||||
//import java.util.concurrent.ConcurrentHashMap;
|
||||
//
|
||||
//import static org.bytedeco.javacpp.avutil.AV_LOG_ERROR;
|
||||
//
|
||||
//@Component
|
||||
//@Slf4j
|
||||
//public class RtspFrameGrabber {
|
||||
//
|
||||
// @Autowired
|
||||
// private FaceEngineService faceEngineService;
|
||||
//
|
||||
// @Autowired
|
||||
// private TenPersonService personService;
|
||||
//
|
||||
// @Autowired
|
||||
// private GlobalValue globalValue;
|
||||
//
|
||||
// @Autowired
|
||||
// private CxFeignClient feignClient;
|
||||
// /**
|
||||
// * 用于记录人脸识别相关状态
|
||||
// */
|
||||
// public ConcurrentHashMap<Integer, Integer> requestFeatureStatusMap = new ConcurrentHashMap<>();
|
||||
// /**
|
||||
// * rtsp视频流url
|
||||
// */
|
||||
// @Value("${global.Url.rtspUrl}")
|
||||
// private String rtspUrl;
|
||||
// /**
|
||||
// * 帧抓取器
|
||||
// */
|
||||
// private FFmpegFrameGrabber grabber;
|
||||
// /**
|
||||
// * 视频帧率
|
||||
// */
|
||||
// private int frameRate = 25;
|
||||
// /**
|
||||
// * 视频码率
|
||||
// */
|
||||
//// private int bitRate = 2000000;
|
||||
// private int bitRate = 128000;
|
||||
// /**
|
||||
// * 视频宽度
|
||||
// */
|
||||
// private int frameWidth = 480;
|
||||
// /**
|
||||
// * 视频高度
|
||||
// */
|
||||
// private int frameHeight = 270;
|
||||
// @Autowired
|
||||
// private TenPersonServiceImpl tenPersonService;
|
||||
//
|
||||
// @Autowired
|
||||
// private TenCellDao tenCellDao;
|
||||
//
|
||||
// @Autowired
|
||||
// private MinioConfig minioConfig;
|
||||
// @Autowired
|
||||
// private MinioClient minioClient;
|
||||
//
|
||||
//
|
||||
// private void createGrabber() {
|
||||
// try {
|
||||
//
|
||||
// grabber = FFmpegFrameGrabber.createDefault(rtspUrl);
|
||||
// grabber.setOption("rtsp_transport", "tcp");
|
||||
//
|
||||
//// grabber.setOption("reconnect", "1");
|
||||
//// grabber.setOption("reconnect_at_eof", "1");
|
||||
//// grabber.setOption("reconnect_streamed", "1");
|
||||
//// grabber.setOption("reconnect_delay_max", "2");
|
||||
//// grabber.setOption("preset", "veryfast");
|
||||
//// grabber.setOption("probesize", "192");
|
||||
//// grabber.setOption("tune", "zerolatency");
|
||||
//// grabber.setFrameRate(30.0);
|
||||
//// grabber.setOption("buffer_size", "" + this.bufferSize);
|
||||
//// grabber.setOption("max_delay", "500000");
|
||||
//// grabber.setOption("stimeout", String.valueOf(20000));
|
||||
//// grabber.setOption("loglevel", "quiet");
|
||||
//
|
||||
//
|
||||
//// grabber.setOption("appkey", "****");//海康视频 appkey
|
||||
//// grabber.setOption("secret", byte2Base64);//海康视频 secret
|
||||
//// grabber.setOption("port", "446");//默认443
|
||||
//// grabber.setOption("enableHTTPS", "1"); //是否启用HTTPS协议,这里总是填1
|
||||
//// grabber.setOption("rtsp_flags", "prefer_tcp");
|
||||
// grabber.setOption("stimeout", "5000000");//5秒
|
||||
//
|
||||
//
|
||||
// //设置帧率
|
||||
// grabber.setFrameRate(frameRate);
|
||||
// //设置获取的视频宽度
|
||||
// grabber.setImageWidth(frameWidth);
|
||||
// //设置获取的视频高度
|
||||
// grabber.setImageHeight(frameHeight);
|
||||
// //设置视频bit率
|
||||
// grabber.setVideoBitrate(bitRate);
|
||||
// grabber.start();
|
||||
// } catch (Exception e) {
|
||||
// log.error(e.getMessage());
|
||||
// }
|
||||
// }
|
||||
// public List<FaceVideoVo> startGrabber(String cellId) {
|
||||
//
|
||||
// List<FaceVideoVo> faceVideoVos = new ArrayList<>();
|
||||
//
|
||||
// avutil.av_log_set_level(AV_LOG_ERROR);
|
||||
// Java2DFrameConverter java2DFrameConverter = new Java2DFrameConverter();
|
||||
// if (grabber == null) {
|
||||
// //log.info("连接rtsp:" + rstp + ",开始创建grabber");
|
||||
// createGrabber();
|
||||
// }
|
||||
// try {
|
||||
// Frame frame = grabber.grabImage();
|
||||
// if (frame != null) {
|
||||
//// logger.info("处理帧.............................................");
|
||||
// BufferedImage bi = java2DFrameConverter.getBufferedImage(frame);
|
||||
//
|
||||
// byte[] bytes = imageToBytes(bi, "jpg");
|
||||
//
|
||||
// /* InputStream frameInputStream = new ByteArrayInputStream(bytes);
|
||||
// String frameFileName = "temp/" + "frame_" + UUIDUtil.uuid()
|
||||
// + ".jpg";
|
||||
//
|
||||
// PutObjectOptions framePutObjectOptions = new PutObjectOptions(bytes.length, -1);
|
||||
// framePutObjectOptions.setContentType("image/jpeg");
|
||||
//
|
||||
// minioClient.putObject(
|
||||
// minioConfig.getBucketName(), frameFileName, frameInputStream, framePutObjectOptions);
|
||||
//
|
||||
// System.out.println("文件名 = " + globalValue.getMinioEndpoint() + "/" +
|
||||
// globalValue.getMinioBucketName() + "/" + frameFileName);*/
|
||||
// /* // 读取图片
|
||||
// BufferedImage image = ImageIO.read(new File("C:\\Users\\zhangbo\\OneDrive\\图片\\Camera Roll\\1寸相片.jpg"));
|
||||
//
|
||||
// // 创建字节输出流
|
||||
// ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
//
|
||||
// // 使用ImageIO将BufferedImage编码为byte[]
|
||||
// ImageIO.write(image, "jpg", baos);
|
||||
//
|
||||
// // 转换为byte数组
|
||||
// byte[] imageBytes = baos.toByteArray();*/
|
||||
// faceVideoVos = imageRecognition(bytes, cellId);
|
||||
// System.out.println("faceVideoVos = " + faceVideoVos);
|
||||
//
|
||||
// } else {
|
||||
// log.error("解码失败");
|
||||
// if (grabber != null) {
|
||||
// try {
|
||||
// grabber.stop();
|
||||
// } catch (FrameGrabber.Exception ex) {
|
||||
// log.error("grabber stop exception: " + ex.getMessage());
|
||||
// } finally {
|
||||
// grabber = null;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// } catch (Exception e) {
|
||||
// log.error(e.getMessage());
|
||||
//
|
||||
// if (grabber != null) {
|
||||
// try {
|
||||
// grabber.stop();
|
||||
// } catch (FrameGrabber.Exception ex) {
|
||||
// log.error("grabber stop exception: " + ex.getMessage());
|
||||
// } finally {
|
||||
// grabber = null;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// } finally {
|
||||
// grabber = null;
|
||||
// }
|
||||
//// try {
|
||||
//// Thread.sleep(100);
|
||||
//// } catch (InterruptedException e) {
|
||||
//// logger.error(e.getMessage());
|
||||
//// }
|
||||
//
|
||||
// return faceVideoVos;
|
||||
// }
|
||||
//
|
||||
// public List<FaceVideoVo> recognition(MultipartFile file,String cellId) {
|
||||
// try {
|
||||
// byte[] bytes = file.getBytes();
|
||||
// return imageRecognitionNew(bytes, cellId);
|
||||
//
|
||||
// } catch (IOException e) {
|
||||
// throw new RuntimeException(e);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private List<FaceVideoVo> imageRecognition(byte[] bytes,String cellId) {
|
||||
// List<FaceVideoVo> temp = new ArrayList<>();
|
||||
// if (bytes != null && bytes.length > 0) {
|
||||
// ImageInfo imageInfo = ImageFactory.getRGBData(bytes);
|
||||
// List<FaceInfo> faceInfoList = faceEngineService.detectFaces(imageInfo);
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
// if (CollectionUtil.isNotEmpty(faceInfoList)) {
|
||||
// faceInfoList.forEach(faceInfo -> {
|
||||
// /* FaceRecognitionResDTO faceRecognitionResDTO = new FaceRecognitionResDTO();
|
||||
// faceRecognitionResDTO.setRect(faceInfo.getRect());*/
|
||||
//
|
||||
// byte[] featureBytes = faceEngineService.extractFaceFeature(imageInfo,
|
||||
// faceInfo, ExtractType.REGISTER);
|
||||
// if (featureBytes != null) {
|
||||
// //底库
|
||||
// List<UserInfo> userInfoList = UserRamGroup.getUserList(cellId);
|
||||
// //人脸对比 这里长度永远为1
|
||||
// List<UserCompareInfo> userCompareInfoList = faceEngineService
|
||||
// .faceRecognition(featureBytes, userInfoList, Float.parseFloat(globalValue.getRecFaceThd()));
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
// FaceVideoVo faceVideoVo = new FaceVideoVo();
|
||||
//
|
||||
// //System.out.println("faceInfo = " + faceInfo.getRect());
|
||||
//
|
||||
// faceVideoVo.setRect(faceInfo.getRect());
|
||||
//
|
||||
// if (faceInfo.getFace3DAngle().getYaw() > 20 || faceInfo.getFace3DAngle().getYaw() < -20) {
|
||||
// faceVideoVo.setIsHeadOnView(0);
|
||||
// }else if (faceInfo.getFace3DAngle().getPitch() > 20 || faceInfo.getFace3DAngle().getPitch() < -20) {
|
||||
// faceVideoVo.setIsHeadOnView(0);
|
||||
// }else {
|
||||
// faceVideoVo.setIsHeadOnView(1);
|
||||
// }
|
||||
//
|
||||
// faceVideoVo.setPersonId(userCompareInfoList.get(0).getFaceId()).setName(userCompareInfoList.get(0).getName());
|
||||
//
|
||||
//
|
||||
//
|
||||
// InputStream frameInputStream = new ByteArrayInputStream(bytes);
|
||||
// String frameFileName = "temp/" + "frame_" + UUIDUtil.uuid()
|
||||
// + ".jpg";
|
||||
//
|
||||
// PutObjectOptions framePutObjectOptions = new PutObjectOptions(bytes.length, -1);
|
||||
// framePutObjectOptions.setContentType("image/jpeg");
|
||||
//
|
||||
// try {
|
||||
// frameInputStream.close();
|
||||
// } catch (IOException e) {
|
||||
// throw new RuntimeException(e);
|
||||
// }
|
||||
//
|
||||
// try {
|
||||
// minioClient.putObject(
|
||||
// minioConfig.getBucketName(), frameFileName, frameInputStream, framePutObjectOptions);
|
||||
// } catch (Exception e) {
|
||||
// throw new RuntimeException(e);
|
||||
// }
|
||||
//
|
||||
// System.out.println("文件名 = " + globalValue.getMinioEndpoint() + "/" +
|
||||
// globalValue.getMinioBucketName() + "/" + frameFileName);
|
||||
//
|
||||
//
|
||||
//
|
||||
// faceVideoVo.setImageUrl(frameFileName);
|
||||
//
|
||||
// temp.add(faceVideoVo);
|
||||
//
|
||||
//
|
||||
//
|
||||
// TenPersonEntity tenPerson = personService.getOne(new LambdaQueryWrapper<TenPersonEntity>()
|
||||
// .eq(TenPersonEntity::getPersonId, userCompareInfoList.get(0).getFaceId()));
|
||||
// Map<Integer, String> personnelTypeMap = new HashMap<>();
|
||||
// personnelTypeMap.put(Constant.PERSON_TYPE_OWNER, "2");//内部人员
|
||||
// personnelTypeMap.put(Constant.PERSON_TYPE_MEMBER, "1");//承包商
|
||||
// personnelTypeMap.put(Constant.PERSON_TYPE_TENANT, "3");//长期供应商
|
||||
// personnelTypeMap.put(Constant.PERSON_TYPE_GUEST, "4");//访客
|
||||
//
|
||||
// //
|
||||
// Map<String, Object> params = new HashMap<>();
|
||||
// params.put("pmWatchVideoRecordId", "");
|
||||
// params.put("orgId", tenPerson.getOrgId());
|
||||
// params.put("orgName", tenCellDao.selectOne(new QueryWrapper<TenCellEntity>().eq("cell_id", tenPerson.getCellId())).getName());
|
||||
// params.put("personnelName", tenPerson.getName());
|
||||
// params.put("personnelId", tenPerson.getOpenId());
|
||||
// params.put("personnelCardId", tenPerson.getIdCard());
|
||||
// params.put("personnelType", personnelTypeMap.get(tenPerson.getPersonType()));
|
||||
// params.put("dictSex", tenPerson.getGender() == 0 ? "男" : "女");
|
||||
// SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
|
||||
// params.put("watchVideoTime", sdf.format(System.currentTimeMillis()));
|
||||
//
|
||||
// if(tenPerson.getIsWatchSafeVideo() != 1){
|
||||
// tenPerson.setIsWatchSafeVideo(faceVideoVo.getIsHeadOnView() == 0 ? 2 : 1);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// //tenPerson.setIsWatchSafeVideo();
|
||||
//
|
||||
// tenPersonService.updateById(tenPerson);
|
||||
//
|
||||
// System.out.println("params = " + params);
|
||||
//
|
||||
// if(faceVideoVo.getIsHeadOnView() == 1){
|
||||
// JSONObject jsonObject = feignClient.savePmWatchVideoRecord(params);
|
||||
// if (jsonObject.getBool("success") != null && jsonObject.getBool("success")) {
|
||||
// personService.update(new LambdaUpdateWrapper<TenPersonEntity>()
|
||||
// .set(TenPersonEntity::getIsWatchSafeVideo, 1)
|
||||
// .eq(TenPersonEntity::getPersonId, userCompareInfoList.get(0).getFaceId()));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// } else {
|
||||
// log.error("图片不合格,未检测到人脸");
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// } else {
|
||||
// log.error("图片不合格,未检测到人脸");
|
||||
// }
|
||||
//
|
||||
// } else {
|
||||
// }
|
||||
// return temp;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// private List<FaceVideoVo> imageRecognitionNew(byte[] bytes,String cellId) {
|
||||
// List<FaceVideoVo> temp = new ArrayList<>();
|
||||
// if (bytes != null && bytes.length > 0) {
|
||||
// ImageInfo imageInfo = ImageFactory.getRGBData(bytes);
|
||||
// List<FaceInfo> faceInfoList = faceEngineService.detectFaces(imageInfo);
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
// if (CollectionUtil.isNotEmpty(faceInfoList)) {
|
||||
// faceInfoList.forEach(faceInfo -> {
|
||||
// /* FaceRecognitionResDTO faceRecognitionResDTO = new FaceRecognitionResDTO();
|
||||
// faceRecognitionResDTO.setRect(faceInfo.getRect());*/
|
||||
//
|
||||
// byte[] featureBytes = faceEngineService.extractFaceFeature(imageInfo,
|
||||
// faceInfo, ExtractType.REGISTER);
|
||||
// if (featureBytes != null) {
|
||||
// //底库
|
||||
// List<UserInfo> userInfoList = UserRamGroup.getUserList(cellId);
|
||||
// //人脸对比 这里长度永远为1
|
||||
// List<UserCompareInfo> userCompareInfoList = faceEngineService
|
||||
// .faceRecognition(featureBytes, userInfoList, Float.parseFloat(globalValue.getRecFaceThd()));
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
// FaceVideoVo faceVideoVo = new FaceVideoVo();
|
||||
//
|
||||
// //System.out.println("faceInfo = " + faceInfo.getRect());
|
||||
//
|
||||
// faceVideoVo.setRect(faceInfo.getRect());
|
||||
//
|
||||
// if (faceInfo.getFace3DAngle().getYaw() > 40 || faceInfo.getFace3DAngle().getYaw() < -40) {
|
||||
// faceVideoVo.setIsHeadOnView(0);
|
||||
// }else if (faceInfo.getFace3DAngle().getPitch() > 40 || faceInfo.getFace3DAngle().getPitch() < -40) {
|
||||
// faceVideoVo.setIsHeadOnView(0);
|
||||
// }else {
|
||||
// faceVideoVo.setIsHeadOnView(1);
|
||||
// }
|
||||
//
|
||||
// faceVideoVo.setPersonId(userCompareInfoList.get(0).getFaceId()).setName(userCompareInfoList.get(0).getName());
|
||||
//
|
||||
//
|
||||
//
|
||||
// InputStream frameInputStream = new ByteArrayInputStream(bytes);
|
||||
// String frameFileName = "temp/" + "frame_" + UUIDUtil.uuid()
|
||||
// + ".jpg";
|
||||
//
|
||||
// PutObjectOptions framePutObjectOptions = new PutObjectOptions(bytes.length, -1);
|
||||
// framePutObjectOptions.setContentType("image/jpeg");
|
||||
//
|
||||
// try {
|
||||
// frameInputStream.close();
|
||||
// } catch (IOException e) {
|
||||
// throw new RuntimeException(e);
|
||||
// }
|
||||
//
|
||||
// try {
|
||||
// minioClient.putObject(
|
||||
// minioConfig.getBucketName(), frameFileName, frameInputStream, framePutObjectOptions);
|
||||
// } catch (Exception e) {
|
||||
// throw new RuntimeException(e);
|
||||
// }
|
||||
//
|
||||
// System.out.println("文件名 = " + globalValue.getMinioEndpoint() + "/" +
|
||||
// globalValue.getMinioBucketName() + "/" + frameFileName);
|
||||
//
|
||||
//
|
||||
//
|
||||
// faceVideoVo.setImageUrl(frameFileName);
|
||||
//
|
||||
// temp.add(faceVideoVo);
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
// } else {
|
||||
// log.error("图片不合格,未检测到人脸");
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// } else {
|
||||
// log.error("图片不合格,未检测到人脸");
|
||||
// }
|
||||
//
|
||||
// }
|
||||
// return temp;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 图片转字节数组
|
||||
// *
|
||||
// * @param _bi 图片数据
|
||||
// * @return 图片字节码
|
||||
// */
|
||||
// private byte[] imageToBytes(BufferedImage _bi, String _format) {
|
||||
// ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
// try {
|
||||
// ImageIO.write(_bi, _format, baos);
|
||||
// } catch (IOException e) {
|
||||
// log.error(e.getMessage());
|
||||
// return null;
|
||||
// }
|
||||
// return baos.toByteArray();
|
||||
// }
|
||||
//
|
||||
//}
|
|
@ -0,0 +1,28 @@
|
|||
package com.guwan.backend.face.service;
|
||||
|
||||
|
||||
import com.arcsoft.face.FaceInfo;
|
||||
import com.arcsoft.face.enums.ExtractType;
|
||||
import com.arcsoft.face.toolkit.ImageInfo;
|
||||
import com.guwan.backend.face.entity.ProcessInfo;
|
||||
import com.guwan.backend.face.entity.UserCompareInfo;
|
||||
import com.guwan.backend.face.util.UserInfo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public interface FaceEngineService {
|
||||
|
||||
List<FaceInfo> detectFaces(ImageInfo imageInfo);
|
||||
|
||||
Float compareFace(ImageInfo imageInfo1, ImageInfo imageInfo2) ;
|
||||
|
||||
byte[] extractFaceFeature(ImageInfo imageInfo, FaceInfo faceInfo, ExtractType extractType);
|
||||
|
||||
List<UserCompareInfo> faceRecognition(byte[] faceFeature, List<UserInfo> userInfoList, float passRate) ;
|
||||
|
||||
List<ProcessInfo> process(ImageInfo imageInfo, List<FaceInfo> faceInfoList);
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,354 @@
|
|||
package com.guwan.backend.face.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import com.arcsoft.face.*;
|
||||
import com.arcsoft.face.enums.DetectMode;
|
||||
import com.arcsoft.face.enums.DetectOrient;
|
||||
import com.arcsoft.face.enums.ExtractType;
|
||||
import com.arcsoft.face.toolkit.ImageInfo;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.guwan.backend.face.entity.ProcessInfo;
|
||||
import com.guwan.backend.face.entity.UserCompareInfo;
|
||||
import com.guwan.backend.face.enums.ErrorCodeEnum;
|
||||
import com.guwan.backend.face.factory.FaceEngineFactory;
|
||||
import com.guwan.backend.face.rpc.BusinessException;
|
||||
import com.guwan.backend.face.service.FaceEngineService;
|
||||
import com.guwan.backend.face.util.UserInfo;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.pool2.impl.GenericObjectPool;
|
||||
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
|
||||
@Service("faceEngineService")
|
||||
@Slf4j
|
||||
public class FaceEngineServiceImpl implements FaceEngineService {
|
||||
|
||||
public final static Logger logger = LoggerFactory.getLogger(FaceEngineServiceImpl.class);
|
||||
|
||||
@Value("${config.arcface-sdk.app-id}")
|
||||
public String appId;
|
||||
|
||||
@Value("${config.arcface-sdk.sdk-key}")
|
||||
public String sdkKey;
|
||||
|
||||
@Value("${config.arcface-sdk.active-key}")
|
||||
public String activeKey;
|
||||
|
||||
@Value("${config.arcface-sdk.active-file}")
|
||||
public String activeFile;
|
||||
|
||||
@Value("${config.arcface-sdk.detect-pool-size}")
|
||||
public Integer detectPooSize;
|
||||
|
||||
@Value("${config.arcface-sdk.compare-pool-size}")
|
||||
public Integer comparePooSize;
|
||||
|
||||
private ExecutorService compareExecutorService;
|
||||
|
||||
//通用人脸识别引擎池
|
||||
private GenericObjectPool<FaceEngine> faceEngineGeneralPool;
|
||||
|
||||
//人脸比对引擎池
|
||||
private GenericObjectPool<FaceEngine> faceEngineComparePool;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
|
||||
|
||||
GenericObjectPoolConfig detectPoolConfig = new GenericObjectPoolConfig();
|
||||
detectPoolConfig.setMaxIdle(detectPooSize);
|
||||
detectPoolConfig.setMaxTotal(detectPooSize);
|
||||
detectPoolConfig.setMinIdle(detectPooSize);
|
||||
detectPoolConfig.setLifo(false);
|
||||
EngineConfiguration detectCfg = new EngineConfiguration();
|
||||
FunctionConfiguration detectFunctionCfg = new FunctionConfiguration();
|
||||
detectFunctionCfg.setSupportFaceDetect(true);//开启人脸检测功能
|
||||
detectFunctionCfg.setSupportFaceRecognition(true);//开启人脸识别功能
|
||||
detectFunctionCfg.setSupportAge(true);//开启年龄检测功能
|
||||
detectFunctionCfg.setSupportGender(true);//开启性别检测功能
|
||||
detectFunctionCfg.setSupportLiveness(true);//开启活体检测功能
|
||||
detectCfg.setFunctionConfiguration(detectFunctionCfg);
|
||||
detectCfg.setDetectMode(DetectMode.ASF_DETECT_MODE_IMAGE);//图片检测模式,如果是连续帧的视频流图片,那么改成VIDEO模式
|
||||
detectCfg.setDetectFaceOrientPriority(DetectOrient.ASF_OP_0_ONLY);//人脸旋转角度
|
||||
faceEngineGeneralPool = new GenericObjectPool(new FaceEngineFactory(appId, sdkKey, activeKey, activeFile, detectCfg), detectPoolConfig);//底层库算法对象池
|
||||
|
||||
|
||||
//初始化特征比较线程池
|
||||
GenericObjectPoolConfig comparePoolConfig = new GenericObjectPoolConfig();
|
||||
comparePoolConfig.setMaxIdle(comparePooSize);
|
||||
comparePoolConfig.setMaxTotal(comparePooSize);
|
||||
comparePoolConfig.setMinIdle(comparePooSize);
|
||||
comparePoolConfig.setLifo(false);
|
||||
EngineConfiguration compareCfg = new EngineConfiguration();
|
||||
FunctionConfiguration compareFunctionCfg = new FunctionConfiguration();
|
||||
compareFunctionCfg.setSupportFaceRecognition(true);//开启人脸识别功能
|
||||
compareCfg.setFunctionConfiguration(compareFunctionCfg);
|
||||
compareCfg.setDetectMode(DetectMode.ASF_DETECT_MODE_IMAGE);//图片检测模式,如果是连续帧的视频流图片,那么改成VIDEO模式
|
||||
compareCfg.setDetectFaceOrientPriority(DetectOrient.ASF_OP_0_ONLY);//人脸旋转角度
|
||||
faceEngineComparePool = new GenericObjectPool(new FaceEngineFactory(appId, sdkKey, activeKey, activeFile, compareCfg), comparePoolConfig);//底层库算法对象池
|
||||
compareExecutorService = Executors.newFixedThreadPool(comparePooSize);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<FaceInfo> detectFaces(ImageInfo imageInfo) {
|
||||
|
||||
FaceEngine faceEngine = null;
|
||||
try {
|
||||
faceEngine = faceEngineGeneralPool.borrowObject();
|
||||
if (faceEngine == null) {
|
||||
throw new BusinessException(ErrorCodeEnum.FAIL, "获取引擎失败");
|
||||
}
|
||||
|
||||
//人脸检测得到人脸列表
|
||||
List<FaceInfo> faceInfoList = new ArrayList<FaceInfo>();
|
||||
//人脸检测
|
||||
int errorCode = faceEngine.detectFaces(imageInfo.getImageData(),
|
||||
imageInfo.getWidth(), imageInfo.getHeight(),
|
||||
imageInfo.getImageFormat(), faceInfoList);
|
||||
if (errorCode == 0) {
|
||||
return faceInfoList;
|
||||
} else {
|
||||
log.error("人脸检测失败,errorCode:" + errorCode);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("", e);
|
||||
} finally {
|
||||
if (faceEngine != null) {
|
||||
//释放引擎对象
|
||||
faceEngineGeneralPool.returnObject(faceEngine);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float compareFace(ImageInfo imageInfo1, ImageInfo imageInfo2) {
|
||||
|
||||
List<FaceInfo> faceInfoList1 = detectFaces(imageInfo1);
|
||||
List<FaceInfo> faceInfoList2 = detectFaces(imageInfo2);
|
||||
|
||||
if (CollectionUtil.isEmpty(faceInfoList1)) {
|
||||
throw new BusinessException(ErrorCodeEnum.FAIL, "照片1未检测到人脸");
|
||||
}
|
||||
if (CollectionUtil.isEmpty(faceInfoList2)) {
|
||||
throw new BusinessException(ErrorCodeEnum.FAIL, "照片2未检测到人脸");
|
||||
}
|
||||
|
||||
byte[] feature1 = extractFaceFeature(imageInfo1, faceInfoList1.get(0), ExtractType.REGISTER);
|
||||
byte[] feature2 = extractFaceFeature(imageInfo2, faceInfoList2.get(0), ExtractType.RECOGNIZE);
|
||||
|
||||
FaceEngine faceEngine = null;
|
||||
try {
|
||||
faceEngine = faceEngineGeneralPool.borrowObject();
|
||||
if (faceEngine == null) {
|
||||
throw new BusinessException(ErrorCodeEnum.FAIL, "获取引擎失败");
|
||||
}
|
||||
|
||||
FaceFeature faceFeature1 = new FaceFeature();
|
||||
faceFeature1.setFeatureData(feature1);
|
||||
FaceFeature faceFeature2 = new FaceFeature();
|
||||
faceFeature2.setFeatureData(feature2);
|
||||
//提取人脸特征
|
||||
FaceSimilar faceSimilar = new FaceSimilar();
|
||||
int errorCode = faceEngine.compareFaceFeature(faceFeature1, faceFeature2, faceSimilar);
|
||||
if (errorCode == 0) {
|
||||
return faceSimilar.getScore();
|
||||
} else {
|
||||
log.error("特征提取失败,errorCode:" + errorCode);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("", e);
|
||||
} finally {
|
||||
if (faceEngine != null) {
|
||||
//释放引擎对象
|
||||
faceEngineGeneralPool.returnObject(faceEngine);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 人脸特征
|
||||
*
|
||||
* @param imageInfo
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public byte[] extractFaceFeature(ImageInfo imageInfo, FaceInfo faceInfo, ExtractType extractType) {
|
||||
|
||||
FaceEngine faceEngine = null;
|
||||
try {
|
||||
faceEngine = faceEngineGeneralPool.borrowObject();
|
||||
if (faceEngine == null) {
|
||||
throw new BusinessException(ErrorCodeEnum.FAIL, "获取引擎失败");
|
||||
}
|
||||
|
||||
FaceFeature faceFeature = new FaceFeature();
|
||||
//提取人脸特征
|
||||
int errorCode = faceEngine.extractFaceFeature(imageInfo, faceInfo, extractType, 0, faceFeature);
|
||||
if (errorCode == 0) {
|
||||
return faceFeature.getFeatureData();
|
||||
} else {
|
||||
log.error("特征提取失败,errorCode:" + errorCode);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("", e);
|
||||
} finally {
|
||||
if (faceEngine != null) {
|
||||
//释放引擎对象
|
||||
faceEngineGeneralPool.returnObject(faceEngine);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserCompareInfo> faceRecognition(byte[] faceFeature, List<UserInfo> userInfoList, float passRate) {
|
||||
List<UserCompareInfo> resultUserInfoList = Lists.newLinkedList();//识别到的人脸列表
|
||||
|
||||
FaceFeature targetFaceFeature = new FaceFeature();
|
||||
targetFaceFeature.setFeatureData(faceFeature);
|
||||
|
||||
List<List<UserInfo>> faceUserInfoPartList = Lists.partition(userInfoList, 1000);//分成1000一组,多线程处理
|
||||
CompletionService<List<UserCompareInfo>> completionService = new ExecutorCompletionService(compareExecutorService);
|
||||
for (List<UserInfo> part : faceUserInfoPartList) {
|
||||
completionService.submit(new CompareFaceTask(part, targetFaceFeature, passRate));
|
||||
}
|
||||
for (int i = 0; i < faceUserInfoPartList.size(); i++) {
|
||||
List<UserCompareInfo> faceUserInfoList = null;
|
||||
try {
|
||||
faceUserInfoList = completionService.take().get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
}
|
||||
if (CollectionUtil.isNotEmpty(userInfoList)) {
|
||||
resultUserInfoList.addAll(faceUserInfoList);
|
||||
}
|
||||
}
|
||||
|
||||
resultUserInfoList.sort((h1, h2) -> h2.getSimilar().compareTo(h1.getSimilar()));//从大到小排序
|
||||
|
||||
return resultUserInfoList;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public List<ProcessInfo> process(ImageInfo imageInfo, List<FaceInfo> faceInfoList) {
|
||||
FaceEngine faceEngine = null;
|
||||
try {
|
||||
//获取引擎对象
|
||||
faceEngine = faceEngineGeneralPool.borrowObject();
|
||||
if (faceEngine == null) {
|
||||
throw new BusinessException(ErrorCodeEnum.FAIL, "获取引擎失败");
|
||||
}
|
||||
|
||||
|
||||
int errorCode = faceEngine.process(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList, FunctionConfiguration.builder().supportAge(true).supportGender(true).supportLiveness(true).build());
|
||||
if (errorCode == 0) {
|
||||
List<ProcessInfo> processInfoList = Lists.newLinkedList();
|
||||
|
||||
//性别列表
|
||||
List<GenderInfo> genderInfoList = new ArrayList<GenderInfo>();
|
||||
faceEngine.getGender(genderInfoList);
|
||||
|
||||
//年龄列表
|
||||
List<AgeInfo> ageInfoList = new ArrayList<AgeInfo>();
|
||||
faceEngine.getAge(ageInfoList);
|
||||
//活体结果列表
|
||||
List<LivenessInfo> livenessInfoList = new ArrayList<LivenessInfo>();
|
||||
faceEngine.getLiveness(livenessInfoList);
|
||||
|
||||
|
||||
for (int i = 0; i < genderInfoList.size(); i++) {
|
||||
ProcessInfo processInfo = new ProcessInfo();
|
||||
processInfo.setGender(genderInfoList.get(i).getGender());
|
||||
processInfo.setAge(ageInfoList.get(i).getAge());
|
||||
processInfo.setLiveness(livenessInfoList.get(i).getLiveness());
|
||||
processInfoList.add(processInfo);
|
||||
}
|
||||
return processInfoList;
|
||||
|
||||
}
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("", e);
|
||||
} finally {
|
||||
if (faceEngine != null) {
|
||||
//释放引擎对象
|
||||
faceEngineGeneralPool.returnObject(faceEngine);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
|
||||
private class CompareFaceTask implements Callable<List<UserCompareInfo>> {
|
||||
|
||||
private List<UserInfo> userInfoList;
|
||||
private FaceFeature targetFaceFeature;
|
||||
private float passRate;
|
||||
|
||||
|
||||
public CompareFaceTask(List<UserInfo> userInfoList, FaceFeature targetFaceFeature, float passRate) {
|
||||
this.userInfoList = userInfoList;
|
||||
this.targetFaceFeature = targetFaceFeature;
|
||||
this.passRate = passRate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserCompareInfo> call() throws Exception {
|
||||
FaceEngine faceEngine = null;
|
||||
List<UserCompareInfo> resultUserInfoList = Lists.newLinkedList();//识别到的人脸列表
|
||||
try {
|
||||
faceEngine = faceEngineComparePool.borrowObject();
|
||||
for (UserInfo userInfo : userInfoList) {
|
||||
FaceFeature sourceFaceFeature = new FaceFeature();
|
||||
sourceFaceFeature.setFeatureData(userInfo.getFaceFeature());
|
||||
FaceSimilar faceSimilar = new FaceSimilar();
|
||||
faceEngine.compareFaceFeature(targetFaceFeature, sourceFaceFeature, faceSimilar);
|
||||
|
||||
System.out.println("faceSimilar.getScore() = " + faceSimilar.getScore());
|
||||
|
||||
if (faceSimilar.getScore() > passRate) {//相似值大于配置预期,加入到识别到人脸的列表
|
||||
UserCompareInfo info = new UserCompareInfo();
|
||||
info.setName(userInfo.getName());
|
||||
info.setFaceId(userInfo.getFaceId());
|
||||
info.setSimilar(faceSimilar.getScore());
|
||||
resultUserInfoList.add(info);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("", e);
|
||||
} finally {
|
||||
if (faceEngine != null) {
|
||||
faceEngineComparePool.returnObject(faceEngine);
|
||||
}
|
||||
}
|
||||
|
||||
return resultUserInfoList;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package com.guwan.backend.face.util;
|
||||
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import java.util.Base64;
|
||||
|
||||
public class Base64Util {
|
||||
public static String base64Process(String base64Str) {
|
||||
if (!ObjectUtils.isEmpty(base64Str)) {
|
||||
String photoBase64 = base64Str.substring(0, 30).toLowerCase();
|
||||
int indexOf = photoBase64.indexOf("base64,");
|
||||
if (indexOf > 0) {
|
||||
base64Str = base64Str.substring(indexOf + 7);
|
||||
}
|
||||
base64Str = base64Str.replaceAll(" ", "+");
|
||||
base64Str = base64Str.replaceAll("\r|\n", "");
|
||||
return base64Str;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public static byte[] base64ToBytes(String base64) {
|
||||
if (ObjectUtils.isEmpty(base64)) {
|
||||
return null;
|
||||
}
|
||||
String base64Process = base64Process(base64);
|
||||
|
||||
byte[] decode = Base64.getDecoder().decode(base64Process);
|
||||
return decode;
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,225 @@
|
|||
package com.guwan.backend.face.util;
|
||||
|
||||
import com.arcsoft.face.*;
|
||||
import com.arcsoft.face.enums.*;
|
||||
import com.arcsoft.face.toolkit.ImageFactory;
|
||||
import com.arcsoft.face.toolkit.ImageInfo;
|
||||
import com.arcsoft.face.toolkit.ImageInfoEx;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class FaceEngineTest {
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
//激活码,从官网获取
|
||||
String appId = "DEnAZa1bWXcaAxyWUg33QZaKCmMkNmrQxuKZJQGmZsHJ";
|
||||
String sdkKey = "vWbvUyStZeartSaM6QoTzPYWFpSaj4uhfDmRifSzCd6";
|
||||
String activeKey = "82G1-11QA-713Y-8NB4";
|
||||
|
||||
System.err.println("注意,如果返回的errorCode不为0,可查看com.arcsoft.face.enums.ErrorInfo类获取相应的错误信息");
|
||||
|
||||
//人脸识别引擎库存放路径
|
||||
FaceEngine faceEngine = new FaceEngine("/home/huangyifang/gb/咸阳师范/ArcSoft_ArcFacePro_linux_java_V4.1/libs/LINUX64");
|
||||
//激活引擎
|
||||
int errorCode = faceEngine.activeOnline(appId, sdkKey, activeKey);
|
||||
System.out.println("引擎激活errorCode:" + errorCode);
|
||||
|
||||
ActiveDeviceInfo activeDeviceInfo = new ActiveDeviceInfo();
|
||||
//采集设备信息(可离线)
|
||||
errorCode = faceEngine.getActiveDeviceInfo(activeDeviceInfo);
|
||||
System.out.println("采集设备信息errorCode:" + errorCode);
|
||||
System.out.println("设备信息:" + activeDeviceInfo.getDeviceInfo());
|
||||
|
||||
// faceEngine.activeOffline("d:\\ArcFacePro64.dat.offline");
|
||||
|
||||
ActiveFileInfo activeFileInfo = new ActiveFileInfo();
|
||||
errorCode = faceEngine.getActiveFileInfo(activeFileInfo);
|
||||
System.out.println("获取激活文件errorCode:" + errorCode);
|
||||
System.out.println("激活文件信息:" + activeFileInfo.toString());
|
||||
|
||||
//引擎配置
|
||||
EngineConfiguration engineConfiguration = new EngineConfiguration();
|
||||
engineConfiguration.setDetectMode(DetectMode.ASF_DETECT_MODE_IMAGE);
|
||||
engineConfiguration.setDetectFaceOrientPriority(DetectOrient.ASF_OP_ALL_OUT);
|
||||
engineConfiguration.setDetectFaceMaxNum(10);
|
||||
//功能配置
|
||||
FunctionConfiguration functionConfiguration = new FunctionConfiguration();
|
||||
functionConfiguration.setSupportAge(true);
|
||||
functionConfiguration.setSupportFaceDetect(true);
|
||||
functionConfiguration.setSupportFaceRecognition(true);
|
||||
functionConfiguration.setSupportGender(true);
|
||||
functionConfiguration.setSupportLiveness(true);
|
||||
functionConfiguration.setSupportIRLiveness(true);
|
||||
functionConfiguration.setSupportImageQuality(true);
|
||||
functionConfiguration.setSupportMaskDetect(true);
|
||||
functionConfiguration.setSupportUpdateFaceData(true);
|
||||
engineConfiguration.setFunctionConfiguration(functionConfiguration);
|
||||
|
||||
//初始化引擎
|
||||
errorCode = faceEngine.init(engineConfiguration);
|
||||
System.out.println("初始化引擎errorCode:" + errorCode);
|
||||
VersionInfo version = faceEngine.getVersion();
|
||||
System.out.println(version);
|
||||
|
||||
//人脸检测
|
||||
ImageInfo imageInfo = ImageFactory.getRGBData(new File("/home/huangyifang/gb/咸阳师范/10.jpg"));
|
||||
List<FaceInfo> faceInfoList = new ArrayList<FaceInfo>();
|
||||
errorCode = faceEngine.detectFaces(imageInfo, faceInfoList);
|
||||
System.out.println("人脸检测errorCode:" + errorCode);
|
||||
System.out.println("检测到人脸数:" + faceInfoList.size());
|
||||
|
||||
ImageQuality imageQuality = new ImageQuality();
|
||||
errorCode = faceEngine.imageQualityDetect(imageInfo, faceInfoList.get(0), 0, imageQuality);
|
||||
System.out.println("图像质量检测errorCode:" + errorCode);
|
||||
System.out.println("图像质量分数:" + imageQuality.getFaceQuality());
|
||||
|
||||
//特征提取
|
||||
FaceFeature faceFeature = new FaceFeature();
|
||||
errorCode = faceEngine.extractFaceFeature(imageInfo, faceInfoList.get(0), ExtractType.REGISTER, 0, faceFeature);
|
||||
System.out.println("特征提取errorCode:" + errorCode);
|
||||
|
||||
//人脸检测2
|
||||
ImageInfo imageInfo2 = ImageFactory.getRGBData(new File("/home/huangyifang/gb/咸阳师范/10.jpg"));
|
||||
List<FaceInfo> faceInfoList2 = new ArrayList<FaceInfo>();
|
||||
errorCode = faceEngine.detectFaces(imageInfo2, faceInfoList2);
|
||||
System.out.println("人脸检测errorCode:" + errorCode);
|
||||
System.out.println("检测到人脸数:" + faceInfoList.size());
|
||||
|
||||
//特征提取2
|
||||
FaceFeature faceFeature2 = new FaceFeature();
|
||||
errorCode = faceEngine.extractFaceFeature(imageInfo2, faceInfoList2.get(0), ExtractType.RECOGNIZE, 0, faceFeature2);
|
||||
System.out.println("特征提取errorCode:" + errorCode);
|
||||
|
||||
//特征比对
|
||||
FaceFeature targetFaceFeature = new FaceFeature();
|
||||
targetFaceFeature.setFeatureData(faceFeature.getFeatureData());
|
||||
FaceFeature sourceFaceFeature = new FaceFeature();
|
||||
sourceFaceFeature.setFeatureData(faceFeature2.getFeatureData());
|
||||
FaceSimilar faceSimilar = new FaceSimilar();
|
||||
|
||||
errorCode = faceEngine.compareFaceFeature(targetFaceFeature, sourceFaceFeature, faceSimilar);
|
||||
System.out.println("特征比对errorCode:" + errorCode);
|
||||
System.out.println("人脸相似度:" + faceSimilar.getScore());
|
||||
|
||||
|
||||
//人脸属性检测
|
||||
FunctionConfiguration configuration = new FunctionConfiguration();
|
||||
configuration.setSupportAge(true);
|
||||
configuration.setSupportGender(true);
|
||||
configuration.setSupportLiveness(true);
|
||||
configuration.setSupportMaskDetect(true);
|
||||
errorCode = faceEngine.process(imageInfo, faceInfoList, configuration);
|
||||
System.out.println("图像属性处理errorCode:" + errorCode);
|
||||
|
||||
//性别检测
|
||||
List<GenderInfo> genderInfoList = new ArrayList<GenderInfo>();
|
||||
errorCode = faceEngine.getGender(genderInfoList);
|
||||
System.out.println("性别:" + genderInfoList.get(0).getGender());
|
||||
|
||||
//年龄检测
|
||||
List<AgeInfo> ageInfoList = new ArrayList<AgeInfo>();
|
||||
errorCode = faceEngine.getAge(ageInfoList);
|
||||
System.out.println("年龄:" + ageInfoList.get(0).getAge());
|
||||
|
||||
//活体检测
|
||||
List<LivenessInfo> livenessInfoList = new ArrayList<LivenessInfo>();
|
||||
errorCode = faceEngine.getLiveness(livenessInfoList);
|
||||
System.out.println("活体:" + livenessInfoList.get(0).getLiveness());
|
||||
|
||||
//口罩检测
|
||||
List<MaskInfo> maskInfoList = new ArrayList<MaskInfo>();
|
||||
errorCode = faceEngine.getMask(maskInfoList);
|
||||
System.out.println("口罩:" + maskInfoList.get(0).getMask());
|
||||
|
||||
|
||||
//IR属性处理
|
||||
ImageInfo imageInfoGray = ImageFactory.getGrayData(new File("/home/huangyifang/gb/咸阳师范/10.jpg"));
|
||||
List<FaceInfo> faceInfoListGray = new ArrayList<FaceInfo>();
|
||||
errorCode = faceEngine.detectFaces(imageInfoGray, faceInfoListGray);
|
||||
|
||||
FunctionConfiguration configuration2 = new FunctionConfiguration();
|
||||
configuration2.setSupportIRLiveness(true);
|
||||
errorCode = faceEngine.processIr(imageInfoGray, faceInfoListGray, configuration2);
|
||||
//IR活体检测
|
||||
List<IrLivenessInfo> irLivenessInfo = new ArrayList<>();
|
||||
errorCode = faceEngine.getLivenessIr(irLivenessInfo);
|
||||
System.out.println("IR活体:" + irLivenessInfo.get(0).getLiveness());
|
||||
|
||||
//获取激活文件信息
|
||||
ActiveFileInfo activeFileInfo2 = new ActiveFileInfo();
|
||||
errorCode = faceEngine.getActiveFileInfo(activeFileInfo2);
|
||||
|
||||
//更新人脸数据
|
||||
errorCode = faceEngine.updateFaceData(imageInfo, faceInfoList);
|
||||
|
||||
//高级人脸图像处理接口
|
||||
ImageInfoEx imageInfoEx = new ImageInfoEx();
|
||||
imageInfoEx.setHeight(imageInfo.getHeight());
|
||||
imageInfoEx.setWidth(imageInfo.getWidth());
|
||||
imageInfoEx.setImageFormat(imageInfo.getImageFormat());
|
||||
imageInfoEx.setImageDataPlanes(new byte[][]{imageInfo.getImageData()});
|
||||
imageInfoEx.setImageStrides(new int[]{imageInfo.getWidth() * 3});
|
||||
List<FaceInfo> faceInfoList1 = new ArrayList<>();
|
||||
errorCode = faceEngine.detectFaces(imageInfoEx, DetectModel.ASF_DETECT_MODEL_RGB, faceInfoList1);
|
||||
ImageQuality imageQuality1 = new ImageQuality();
|
||||
errorCode = faceEngine.imageQualityDetect(imageInfoEx, faceInfoList1.get(0), 0, imageQuality1);
|
||||
FunctionConfiguration fun = new FunctionConfiguration();
|
||||
fun.setSupportAge(true);
|
||||
errorCode = faceEngine.process(imageInfoEx, faceInfoList1, fun);
|
||||
List<AgeInfo> ageInfoList1 = new ArrayList<>();
|
||||
int age = faceEngine.getAge(ageInfoList1);
|
||||
FaceFeature feature = new FaceFeature();
|
||||
errorCode = faceEngine.extractFaceFeature(imageInfoEx, faceInfoList1.get(0), ExtractType.REGISTER, 0, feature);
|
||||
errorCode = faceEngine.updateFaceData(imageInfoEx, faceInfoList1);
|
||||
|
||||
//设置活体测试
|
||||
errorCode = faceEngine.setLivenessParam(0.5f, 0.7f, 0.3f);
|
||||
System.out.println("设置活体活体阈值errorCode:" + errorCode);
|
||||
|
||||
LivenessParam livenessParam=new LivenessParam();
|
||||
errorCode = faceEngine.getLivenessParam(livenessParam);
|
||||
|
||||
//注册人脸信息1
|
||||
FaceFeatureInfo faceFeatureInfo = new FaceFeatureInfo();
|
||||
faceFeatureInfo.setSearchId(5);
|
||||
faceFeatureInfo.setFaceTag("FeatureData1");
|
||||
faceFeatureInfo.setFeatureData(faceFeature.getFeatureData());
|
||||
errorCode = faceEngine.registerFaceFeature(faceFeatureInfo);
|
||||
|
||||
//注册人脸信息2
|
||||
FaceFeatureInfo faceFeatureInfo2 = new FaceFeatureInfo();
|
||||
faceFeatureInfo2.setSearchId(6);
|
||||
faceFeatureInfo2.setFaceTag("FeatureData2");
|
||||
faceFeatureInfo2.setFeatureData(faceFeature2.getFeatureData());
|
||||
errorCode = faceEngine.registerFaceFeature(faceFeatureInfo2);
|
||||
|
||||
//获取注册人脸个数
|
||||
FaceSearchCount faceSearchCount = new FaceSearchCount();
|
||||
errorCode = faceEngine.getFaceCount(faceSearchCount);
|
||||
System.out.println("注册人脸个数:" + faceSearchCount.getCount());
|
||||
|
||||
//搜索最相似人脸
|
||||
SearchResult searchResult = new SearchResult();
|
||||
errorCode = faceEngine.searchFaceFeature(faceFeature, CompareModel.LIFE_PHOTO, searchResult);
|
||||
System.out.println("最相似人脸Id:" + searchResult.getFaceFeatureInfo().getSearchId());
|
||||
|
||||
//更新人脸信息
|
||||
FaceFeatureInfo faceFeatureInfo3 = new FaceFeatureInfo();
|
||||
faceFeatureInfo3.setSearchId(6);
|
||||
faceFeatureInfo3.setFaceTag("FeatureData2Update");
|
||||
faceFeatureInfo3.setFeatureData(faceFeature2.getFeatureData());
|
||||
errorCode = faceEngine.updateFaceFeature(faceFeatureInfo3);
|
||||
|
||||
//移除人脸信息
|
||||
errorCode = faceEngine.removeFaceFeature(6);
|
||||
|
||||
//引擎卸载
|
||||
errorCode = faceEngine.unInit();
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package com.guwan.backend.face.util;
|
||||
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class UserInfo {
|
||||
private String faceId;
|
||||
private String name;
|
||||
private byte[] faceFeature;
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package com.guwan.backend.face.util;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
public class UserRamCache {
|
||||
|
||||
private final ConcurrentHashMap<String, UserInfo> USER_INFO_MAP = new ConcurrentHashMap<>();
|
||||
|
||||
private final Set<Listener> REGISTER = new CopyOnWriteArraySet<>();
|
||||
|
||||
public void addUser(UserInfo userInfo) {
|
||||
USER_INFO_MAP.put(userInfo.getFaceId(), userInfo);
|
||||
for (Listener listener : REGISTER) {
|
||||
listener.onAdd(userInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeUser(String faceId) {
|
||||
UserInfo userInfo = USER_INFO_MAP.remove(faceId);
|
||||
for (Listener listener : REGISTER) {
|
||||
listener.onRemove(userInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public List<UserInfo> getUserList() {
|
||||
List<UserInfo> userInfoList = Lists.newLinkedList();
|
||||
userInfoList.addAll(USER_INFO_MAP.values());
|
||||
return userInfoList;
|
||||
}
|
||||
|
||||
public void clear(){
|
||||
USER_INFO_MAP.clear();
|
||||
REGISTER.clear();
|
||||
}
|
||||
|
||||
public void addListener(Listener listener) {
|
||||
REGISTER.add(listener);
|
||||
}
|
||||
|
||||
public void removeListener(Listener listener) {
|
||||
REGISTER.remove(listener);
|
||||
}
|
||||
|
||||
// @Data
|
||||
// public class UserInfo {
|
||||
//
|
||||
// private String faceId;
|
||||
// private String name;
|
||||
// private byte[] faceFeature;
|
||||
//
|
||||
// }
|
||||
|
||||
public interface Listener {
|
||||
default void onAdd(UserInfo userInfo) {
|
||||
}
|
||||
|
||||
default void onRemove(UserInfo userInfo) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package com.guwan.backend.face.util;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class UserRamGroup {
|
||||
|
||||
private static final ConcurrentHashMap<String, UserRamCache> USER_RAM_GROUP_MAP = new ConcurrentHashMap<>();
|
||||
private static final ConcurrentHashMap<String, String> ORG_CELL_MAP = new ConcurrentHashMap<>();
|
||||
|
||||
public static void addCell(String cellId){
|
||||
UserRamCache cell = new UserRamCache();
|
||||
USER_RAM_GROUP_MAP.put(cellId,cell);
|
||||
}
|
||||
|
||||
public static void removeCell(String cellId){
|
||||
USER_RAM_GROUP_MAP.remove(cellId);
|
||||
}
|
||||
|
||||
public static void addUser(UserInfo userInfo, String cellId) {
|
||||
USER_RAM_GROUP_MAP.get(cellId).addUser(userInfo);
|
||||
}
|
||||
|
||||
public static void removeUser(String faceId, String cellId) {
|
||||
USER_RAM_GROUP_MAP.get(cellId).removeUser(faceId);
|
||||
}
|
||||
|
||||
public static List<UserInfo> getUserList(String cellId) {
|
||||
return USER_RAM_GROUP_MAP.get(cellId).getUserList();
|
||||
}
|
||||
|
||||
public static void addOrgId(String orgId,String cellId){
|
||||
ORG_CELL_MAP.put(orgId,cellId);
|
||||
}
|
||||
public static String getOrgCellMap(String orgId) {
|
||||
return ORG_CELL_MAP.get(orgId);
|
||||
}
|
||||
|
||||
public static void clear(){
|
||||
USER_RAM_GROUP_MAP.clear();
|
||||
}
|
||||
}
|
|
@ -42,7 +42,7 @@ public class VideoServiceImpl implements VideoService {
|
|||
try {
|
||||
// 上传视频文件到MinIO
|
||||
String fileName = minioUtil.uploadFile("videos", file);
|
||||
String url = minioUtil.getFileUrl("videos", fileName);
|
||||
String url = minioUtil.getUrl(minioUtil.getFileUrl("videos", fileName));
|
||||
|
||||
// 创建视频记录
|
||||
Video video = new Video();
|
||||
|
@ -209,7 +209,7 @@ public class VideoServiceImpl implements VideoService {
|
|||
BeanUtils.copyProperties(video, dto);
|
||||
|
||||
// 设置是否已点赞
|
||||
dto.setHasLiked(hasLiked(video.getId()));
|
||||
// dto.setHasLiked(hasLiked(video.getId()));
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ public class MinioUtil {
|
|||
* 创建存储桶
|
||||
*/
|
||||
public void createBucket(String bucketName) {
|
||||
System.out.println("bucketName = " + bucketName);
|
||||
try {
|
||||
boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
|
||||
if (!found) {
|
||||
|
@ -46,6 +47,11 @@ public class MinioUtil {
|
|||
* 上传文件
|
||||
*/
|
||||
public String uploadFile(String bucketName, MultipartFile file) {
|
||||
|
||||
|
||||
|
||||
createBucket(bucketName);
|
||||
|
||||
try {
|
||||
String fileName = generateFileName(file.getOriginalFilename());
|
||||
InputStream inputStream = file.getInputStream();
|
||||
|
@ -153,6 +159,11 @@ public class MinioUtil {
|
|||
}
|
||||
}
|
||||
|
||||
public String getUrl(String url) {
|
||||
return url.substring(0, url.indexOf("?"));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 生成文件名
|
||||
*/
|
||||
|
|
|
@ -8,8 +8,8 @@ spring:
|
|||
# 视频上传配置
|
||||
servlet:
|
||||
multipart:
|
||||
max-file-size: 500MB
|
||||
max-request-size: 500MB
|
||||
max-file-size: 500MB
|
||||
max-request-size: 500MB
|
||||
# 数据库配置
|
||||
datasource:
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
|
@ -111,4 +111,17 @@ springdoc:
|
|||
group-configs:
|
||||
- group: '默认'
|
||||
paths-to-match: '/**'
|
||||
packages-to-scan: com.guwan.backend.controller
|
||||
packages-to-scan: com.guwan.backend.controller
|
||||
|
||||
|
||||
config:
|
||||
arcface-sdk:
|
||||
version: 4.1
|
||||
app-id: BYYPcPa3qQaAA88HZw7awne1BqZiePgT6axtALtK2qun
|
||||
sdk-key: 3eFAwSCMQRhoUoAaZ2Li9XUVDUubAWYksQtNPWD32UrX
|
||||
active-key: 82K1-11TQ-W11B-H7MU
|
||||
active-file: ArcFacePro64.dat
|
||||
detect-pool-size: 16
|
||||
compare-pool-size: 16
|
||||
rec-face-thd: 0.8
|
||||
rec-id-thd: 0.5
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue