|
|
@@ -0,0 +1,167 @@
|
|
|
+package com.ktg.common.utils;
|
|
|
+
|
|
|
+
|
|
|
+import cn.hutool.core.util.ObjectUtil;
|
|
|
+import com.google.common.collect.Lists;
|
|
|
+import com.ktg.common.vo.VerificationVO;
|
|
|
+import com.machinezoo.sourceafis.FingerprintImage;
|
|
|
+import com.machinezoo.sourceafis.FingerprintMatcher;
|
|
|
+import com.machinezoo.sourceafis.FingerprintTemplate;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.springframework.web.multipart.MultipartFile;
|
|
|
+
|
|
|
+import java.io.IOException;
|
|
|
+import java.nio.file.Files;
|
|
|
+import java.nio.file.Paths;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Comparator;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Set;
|
|
|
+import java.util.concurrent.CompletableFuture;
|
|
|
+import java.util.concurrent.ExecutionException;
|
|
|
+import java.util.concurrent.ExecutorService;
|
|
|
+import java.util.concurrent.Executors;
|
|
|
+
|
|
|
+/**
|
|
|
+ * <p>
|
|
|
+ * FingerprintComparison<br>
|
|
|
+ * 指纹比对算法(图片)
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @author CGJ
|
|
|
+ * @version 1.0
|
|
|
+ * @since 2025年03月07日 11:51
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+public class FingerprintComparisonByDat {
|
|
|
+
|
|
|
+ // 相似度门槛
|
|
|
+ private static final double THRESHOLD = 40; // 相当于错误率是0.01%,THRESHOLD越高,错误率越低
|
|
|
+ private static final ExecutorService THREAD_POOL_EXECUTOR = Executors.newFixedThreadPool(4); // 线程池
|
|
|
+
|
|
|
+ public static VerificationVO completableFutureComparison(final MultipartFile file, final Set<String> matcherDat) {
|
|
|
+ // 转成list
|
|
|
+ List<String> matcherImgList = new ArrayList<>(matcherDat);
|
|
|
+ // 切分四等份
|
|
|
+ int denominator = 1;
|
|
|
+ if (matcherImgList.size() >= 4) {
|
|
|
+ denominator = 4;
|
|
|
+ }
|
|
|
+ List<List<String>> averageMatcherImgList = Lists.partition(matcherImgList, matcherImgList.size() / denominator);
|
|
|
+ // 构建四个线程进行处理,防止人员过多对比速度太慢
|
|
|
+ CompletableFuture<VerificationVO>[] completableFutureArray = averageMatcherImgList.stream().map(
|
|
|
+ partitionFingerprint -> CompletableFuture.supplyAsync(
|
|
|
+ () -> comparison(file, new ArrayList<>(partitionFingerprint)), THREAD_POOL_EXECUTOR)
|
|
|
+ ).toArray(CompletableFuture[]::new);
|
|
|
+ // 等待所有任务执行完
|
|
|
+ CompletableFuture.allOf(completableFutureArray).join();
|
|
|
+ List<VerificationVO> verificationList = new ArrayList<>();
|
|
|
+ for (CompletableFuture<VerificationVO> completableFuture : completableFutureArray) {
|
|
|
+ try {
|
|
|
+ VerificationVO verification = completableFuture.get();
|
|
|
+ if (ObjectUtil.isNotEmpty(verification)) {
|
|
|
+ verificationList.add(verification);
|
|
|
+ }
|
|
|
+ } catch (InterruptedException | ExecutionException e) {
|
|
|
+ log.error(e.getMessage(), e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 找出最匹配的指纹(匹配度最高)
|
|
|
+ if (ObjectUtil.isNotEmpty(verificationList)) {
|
|
|
+ VerificationVO max = verificationList.stream().max(Comparator.comparing(VerificationVO::getScore)).get();
|
|
|
+ log.info("相似值最佳的的指纹:{},分数{}", max.getFingerprint(), max.getScore());
|
|
|
+ return max;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static VerificationVO comparison(final MultipartFile file, final List<String> matcherDatList) {
|
|
|
+ try {
|
|
|
+ // 开始解析输入的指纹到指纹模板
|
|
|
+ byte[] bytes = file.getBytes();
|
|
|
+ // 创建FingerprintImage对象
|
|
|
+ FingerprintImage fingerprintImage = new FingerprintImage()
|
|
|
+ .dpi(500) // 设置DPI,具体值取决于你的图像分辨率
|
|
|
+ .decode(bytes);
|
|
|
+ // 提取指纹特征值
|
|
|
+ FingerprintTemplate fingerprintTemplate = new FingerprintTemplate(fingerprintImage);
|
|
|
+ if (!matcherDatList.isEmpty()) {
|
|
|
+ // 输入的被验证指纹
|
|
|
+ FingerprintMatcher matcher = new FingerprintMatcher(fingerprintTemplate);
|
|
|
+ // 最匹配的指纹
|
|
|
+ String match = null;
|
|
|
+ // 峰值
|
|
|
+ double high = 0;
|
|
|
+ for (String matcherDat : matcherDatList) {
|
|
|
+ // 输入的指纹和指纹库中的指纹进行对比,找到当前线程中的分数最高的指纹
|
|
|
+ FingerprintTemplate matcherTemp = new FingerprintTemplate().deserialize(new String(Files.readAllBytes(Paths.get(matcherDat))));
|
|
|
+ double score = matcher.match(matcherTemp);
|
|
|
+ if (score > high) {
|
|
|
+ high = score;
|
|
|
+ match = matcherDat;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return high >= THRESHOLD ? new VerificationVO().setFingerprint(match).setScore(high) : null;
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("指纹比对异常:{}", e.getMessage());
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ public static void main(String[] args) throws IOException {
|
|
|
+ /*try {
|
|
|
+ String imagePath = "C:\\Users\\车车\\Desktop\\指纹\\finger(1)\\finger\\2\\image_2.bmp"; // 替换为你的指纹图片路径
|
|
|
+ byte[] fingerprintData = extractFingerprintTemplate(imagePath);
|
|
|
+
|
|
|
+ // 保存到文件
|
|
|
+ Files.write(Paths.get("C:\\Users\\车车\\Desktop\\指纹\\finger(1)\\finger\\2\\fingerprint_2.dat"), fingerprintData);
|
|
|
+ System.out.println("指纹特征值已保存!");
|
|
|
+ } catch (IOException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }*/
|
|
|
+
|
|
|
+ String aa = "C:/Users/车车/Desktop/指纹/finger(1)/finger/2/fingerprint_0.dat";
|
|
|
+ String bb = "C:/Users/车车/Desktop/指纹/finger(1)/finger/2/fingerprint_0.dat";
|
|
|
+ // 加载模板1(数据库或文件中加载)
|
|
|
+ byte[] templateData1 = Files.readAllBytes(Paths.get(aa));
|
|
|
+ String jsonString = new String(templateData1);
|
|
|
+ FingerprintTemplate template1 = new FingerprintTemplate().deserialize(jsonString);
|
|
|
+
|
|
|
+ // 加载模板2(待比对指纹)
|
|
|
+ byte[] templateData2 = Files.readAllBytes(Paths.get(bb));
|
|
|
+ String jsonString2 = new String(templateData2);
|
|
|
+ FingerprintTemplate template2 = new FingerprintTemplate().deserialize(jsonString2);
|
|
|
+
|
|
|
+ // 匹配
|
|
|
+ double score = new FingerprintMatcher().index(template1).match(template2);
|
|
|
+
|
|
|
+ System.out.println("匹配得分: " + score);
|
|
|
+ if (score >= 40) { // 经验阈值,一般为 40 分
|
|
|
+ System.out.println("指纹匹配!");
|
|
|
+ } else {
|
|
|
+ System.out.println("指纹不匹配!");
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ public static byte[] extractFingerprintTemplate(String imagePath) throws IOException {
|
|
|
+ // 读取图像文件(灰度图像 PNG, BMP, JPEG 等)
|
|
|
+ byte[] imageBytes = Files.readAllBytes(Paths.get(imagePath));
|
|
|
+
|
|
|
+ // 提取特征值
|
|
|
+ FingerprintTemplate template = new FingerprintTemplate()
|
|
|
+ .dpi(500) // 指定 DPI (重要,通常为 500)
|
|
|
+ .create(imageBytes);
|
|
|
+
|
|
|
+ // 导出为 byte[] 保存特征值
|
|
|
+ return template.serialize().getBytes();
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|