This commit is contained in:
砂糖
2025-09-26 11:55:38 +08:00
commit 7f07552ecc
628 changed files with 67849 additions and 0 deletions

View File

@@ -0,0 +1,286 @@
package com.ruoyi.video.utils;
import com.arcsoft.face.*;
import com.arcsoft.face.enums.DetectMode;
import com.arcsoft.face.enums.DetectOrient;
import com.arcsoft.face.enums.ErrorInfo;
import com.arcsoft.face.enums.ImageFormat;
import com.arcsoft.face.toolkit.ImageFactory;
import com.arcsoft.face.toolkit.ImageInfo;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.video.domain.VImage;
import com.ruoyi.video.service.IVImageService;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.bytedeco.javacv.Frame;
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.awt.image.DataBufferByte;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
/**
* @Author: orange
* @CreateTime: 2025-01-16
*/
@Slf4j
@Component
public class ArcFaceEngineUtil {
@Value("${arcFace.appId}")
public String appId;
@Value("${arcFace.sdkKey}")
public String sdkKey;
int errorCode;
String projectPath = System.getProperty("user.dir");
@Autowired
private IVImageService ivImageService;
FaceEngine faceEngine = new FaceEngine(projectPath+"\\ruoyi-video\\src\\main\\resources\\libs\\WIN64");
private final AtomicLong lastSaveTime = new AtomicLong(0); // 记录上次保存的时间戳
private static final long SAVE_INTERVAL = 10 * 1000; // 10 秒的间隔
/**
* 初始化
*/
@PostConstruct
public void init() {
this.errorCode = this.faceEngine.activeOnline(this.appId, this.sdkKey);
if (this.errorCode != ErrorInfo.MOK.getValue() && this.errorCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue()) {
log.error("引擎激活失败");
}
ActiveFileInfo activeFileInfo = new ActiveFileInfo();
this.errorCode = this.faceEngine.getActiveFileInfo(activeFileInfo);
if (this.errorCode != ErrorInfo.MOK.getValue() && this.errorCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue()) {
log.error("获取激活文件信息失败");
}
EngineConfiguration engineConfiguration = new EngineConfiguration();
engineConfiguration.setDetectMode(DetectMode.ASF_DETECT_MODE_IMAGE);
engineConfiguration.setDetectFaceOrientPriority(DetectOrient.ASF_OP_ALL_OUT);
engineConfiguration.setDetectFaceMaxNum(10);
engineConfiguration.setDetectFaceScaleVal(16);
FunctionConfiguration functionConfiguration = new FunctionConfiguration();
functionConfiguration.setSupportAge(true);
functionConfiguration.setSupportFace3dAngle(true);
functionConfiguration.setSupportFaceDetect(true);
functionConfiguration.setSupportFaceRecognition(true);
functionConfiguration.setSupportGender(true);
functionConfiguration.setSupportLiveness(true);
functionConfiguration.setSupportIRLiveness(true);
engineConfiguration.setFunctionConfiguration(functionConfiguration);
this.errorCode = this.faceEngine.init(engineConfiguration);
if (this.errorCode != ErrorInfo.MOK.getValue()) {
log.error("初始化引擎失败");
}
log.info("------------------------");
log.info("ruoyi-video初始化引擎成功");
log.info("微信: chenbai0511");
log.info("请我喝杯咖啡吧qwq");
log.info("------------------------");
}
/**
* Frame对象转换为ImageInfo对象
* @param frame
* @return
*/
public ImageInfo frameToImageInfo(Frame frame) {
if (frame == null || frame.image == null) {
log.error("Frame是空或非图像帧------");
return null;
} else {
Java2DFrameConverter converter = new Java2DFrameConverter();
BufferedImage image = converter.convert(frame);
if (image == null) {
log.error("Converted image is null");
return null;
} else {
int width = image.getWidth();
int height = image.getHeight();
byte[] imageData = ((DataBufferByte)image.getRaster().getDataBuffer()).getData();
ImageInfo imageInfo = new ImageInfo();
imageInfo.setWidth(width);
imageInfo.setHeight(height);
imageInfo.setImageFormat(ImageFormat.CP_PAF_BGR24);
imageInfo.setImageData(imageData);
return imageInfo;
}
}
}
/**
* 虹软检测代码
* @param imageInfo
* @return
*/
public HashMap<String, Object> getUserInfo(ImageInfo imageInfo) {
ImageInfo imageInfoFc = ImageFactory.getRGBData(new File("D:\\cat\\fc.jpg"));
List<FaceInfo> faceInfoListFc = new ArrayList();
this.faceEngine.detectFaces(imageInfoFc.getImageData(), imageInfoFc.getWidth(), imageInfoFc.getHeight(), imageInfoFc.getImageFormat(), faceInfoListFc);
if (faceInfoListFc.isEmpty()) {
log.error("未检测到人脸faceInfoListFc");
return null;
} else {
FaceFeature faceFeatureFc = new FaceFeature();
this.faceEngine.extractFaceFeature(imageInfoFc.getImageData(), imageInfoFc.getWidth(), imageInfoFc.getHeight(), imageInfoFc.getImageFormat(), (FaceInfo)faceInfoListFc.get(0), faceFeatureFc);
List<FaceInfo> faceInfoList = new ArrayList();
this.errorCode = this.faceEngine.detectFaces(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList);
if (faceInfoList.isEmpty()) {
log.error("未检测到人脸faceInfoList");
return null;
} else {
FaceFeature faceFeature = new FaceFeature();
this.faceEngine.extractFaceFeature(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), (FaceInfo)faceInfoList.get(0), faceFeature);
FaceFeature targetFaceFeature = new FaceFeature();
targetFaceFeature.setFeatureData(faceFeatureFc.getFeatureData());
FaceFeature sourceFaceFeature = new FaceFeature();
sourceFaceFeature.setFeatureData(faceFeature.getFeatureData());
FaceSimilar faceSimilar = new FaceSimilar();
this.faceEngine.compareFaceFeature(targetFaceFeature, sourceFaceFeature, faceSimilar);
System.out.println("相似度:" + faceSimilar.getScore());
if (faceSimilar.getScore() < 0.8F) {
this.saveImage(imageInfo);
}
this.errorCode = this.faceEngine.setLivenessParam(0.5F, 0.7F);
FunctionConfiguration configuration = new FunctionConfiguration();
configuration.setSupportAge(true);
configuration.setSupportFace3dAngle(true);
configuration.setSupportGender(true);
configuration.setSupportLiveness(true);
this.errorCode = this.faceEngine.process(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList, configuration);
HashMap<String, Object> map = new HashMap();
List<GenderInfo> genderInfoList = new ArrayList();
this.errorCode = this.faceEngine.getGender(genderInfoList);
if (!genderInfoList.isEmpty()) {
System.out.println("性别:" + ((GenderInfo)genderInfoList.get(0)).getGender());
map.put("gender", ((GenderInfo)genderInfoList.get(0)).getGender());
} else {
log.error("未获取到性别信息");
}
List<AgeInfo> ageInfoList = new ArrayList();
this.errorCode = this.faceEngine.getAge(ageInfoList);
if (!ageInfoList.isEmpty()) {
System.out.println("年龄:" + ((AgeInfo)ageInfoList.get(0)).getAge());
map.put("age", ((AgeInfo)ageInfoList.get(0)).getAge());
} else {
log.error("未获取到年龄信息");
}
List<Face3DAngle> face3DAngleList = new ArrayList();
this.errorCode = this.faceEngine.getFace3DAngle(face3DAngleList);
if (!face3DAngleList.isEmpty()) {
PrintStream var10000 = System.out;
float var10001 = ((Face3DAngle)face3DAngleList.get(0)).getPitch();
var10000.println("3D角度" + var10001 + "," + ((Face3DAngle)face3DAngleList.get(0)).getRoll() + "," + ((Face3DAngle)face3DAngleList.get(0)).getYaw());
map.put("3DAngle", face3DAngleList.get(0));
} else {
log.error("未获取到3D角度信息");
}
List<LivenessInfo> livenessInfoList = new ArrayList();
this.errorCode = this.faceEngine.getLiveness(livenessInfoList);
if (!livenessInfoList.isEmpty()) {
System.out.println("活体:" + ((LivenessInfo)livenessInfoList.get(0)).getLiveness());
map.put("liveness", ((LivenessInfo)livenessInfoList.get(0)).getLiveness());
} else {
log.error("未获取到活体信息");
}
return map;
}
}
}
/**
* 保存图片
* @param imageInfo
*/
private void saveImage(ImageInfo imageInfo) {
long currentTime = System.currentTimeMillis();
long lastTime = lastSaveTime.get();
if (currentTime - lastTime < SAVE_INTERVAL) {
log.info("10 秒内已保存过照片,跳过本次保存");
return;
}
if (!lastSaveTime.compareAndSet(lastTime, currentTime)) {
return;
}
try {
File dir = new File("D:\\cat");
if (!dir.exists()) {
dir.mkdirs();
}
String fileName = "image_" + currentTime + ".jpg";
File outputFile = new File(dir, fileName);
BufferedImage bufferedImage = this.convertImageInfoToBufferedImage(imageInfo);
if (bufferedImage != null) {
ImageIO.write(bufferedImage, "jpg", outputFile);
log.info("图片已保存:{}", outputFile.getAbsolutePath());
String filePath = RuoYiConfig.getUploadPath();
MultipartFile multipartFile = new CustomMultipartFile(outputFile, "image/jpeg");
String file_name = FileUploadUtils.upload(filePath, multipartFile);
VImage vImage = new VImage();
vImage.setImageName(file_name);
vImage.setImageData(fileName);
this.ivImageService.insertVImage(vImage);
} else {
log.error("无法转换 ImageInfo 为 BufferedImage");
}
} catch (IOException var16) {
log.error("保存图片失败:{}", var16.getMessage(), var16);
}
}
/**
* 将ImageInfo转换为BufferedImage
* @param imageInfo
* @return
*/
private BufferedImage convertImageInfoToBufferedImage(ImageInfo imageInfo) {
if (imageInfo != null && imageInfo.getImageData() != null) {
if (imageInfo.getImageFormat() == ImageFormat.CP_PAF_BGR24) {
int width = imageInfo.getWidth();
int height = imageInfo.getHeight();
byte[] imageData = imageInfo.getImageData();
BufferedImage bufferedImage = new BufferedImage(width, height, 5);
byte[] targetPixels = ((DataBufferByte)bufferedImage.getRaster().getDataBuffer()).getData();
System.arraycopy(imageData, 0, targetPixels, 0, imageData.length);
return bufferedImage;
} else {
log.error("不支持的图像格式:{}", imageInfo.getImageFormat());
return null;
}
} else {
log.error("ImageInfo 或 imageData 为空");
return null;
}
}
}

View File

@@ -0,0 +1,131 @@
package com.ruoyi.video.utils;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
/**
* File包装成MultipartFile
* @Author: orange
* @CreateTime: 2025-01-16
*/
public class CustomMultipartFile implements MultipartFile {
// 定义一个File类型的变量file
private final File file;
// 定义一个String类型的变量contentType
private final String contentType;
// 构造方法传入一个File类型的变量file和一个String类型的变量contentType
public CustomMultipartFile(File file, String contentType) {
this.file = file;
this.contentType = contentType;
}
// 获取文件名
public String getName() {
return this.file.getName();
}
// 获取原始文件名
public String getOriginalFilename() {
return this.file.getName();
}
// 获取文件类型
public String getContentType() {
return this.contentType;
}
// 判断文件是否为空
public boolean isEmpty() {
return this.file.length() == 0L;
}
// 获取文件大小
public long getSize() {
return this.file.length();
}
// 获取文件的字节数组
public byte[] getBytes() throws IOException {
// 创建一个FileInputStream对象传入file
InputStream inputStream = new FileInputStream(this.file);
byte[] var2;
try {
// 读取所有字节数组
var2 = inputStream.readAllBytes();
} catch (Throwable var5) {
try {
// 关闭输入流
inputStream.close();
} catch (Throwable var4) {
var5.addSuppressed(var4);
}
throw var5;
}
// 关闭输入流
inputStream.close();
return var2;
}
// 获取文件的输入流
public InputStream getInputStream() throws IOException {
return new FileInputStream(this.file);
}
// 将文件传输到指定的文件
public void transferTo(File dest) throws IOException, IllegalStateException {
// 如果目标文件不存在,则创建
if (!dest.exists()) {
dest.createNewFile();
}
// 创建一个FileInputStream对象传入file
InputStream inputStream = new FileInputStream(this.file);
try {
// 创建一个FileOutputStream对象传入dest
OutputStream outputStream = new FileOutputStream(dest);
try {
// 创建一个字节数组大小为1024
byte[] buffer = new byte[1024];
int bytesRead;
// 循环读取文件,直到读取完毕
while((bytesRead = inputStream.read(buffer)) != -1) {
// 将读取的字节数组写入目标文件
outputStream.write(buffer, 0, bytesRead);
}
} catch (Throwable var8) {
try {
// 关闭输出流
outputStream.close();
} catch (Throwable var7) {
var8.addSuppressed(var7);
}
throw var8;
}
// 关闭输出流
outputStream.close();
} catch (Throwable var9) {
try {
// 关闭输入流
inputStream.close();
} catch (Throwable var6) {
var9.addSuppressed(var6);
}
throw var9;
}
// 关闭输入流
inputStream.close();
}
}