基于中科视拓的seetaface6封装的免费人脸识别项目后端接口
shentao
2025-09-22 4e24fd913e7b048436aa7e5001cf875baac81ff5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
package com.code2roc.fastface.controller;
 
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.code2roc.fastface.bizlogic.FaceRegistLogic;
import com.code2roc.fastface.model.*;
import com.code2roc.fastface.service.IFaceRegistService;
import com.code2roc.fastface.util.ConvertOp;
import com.code2roc.fastface.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
 
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
@RestController
@RequestMapping("/faceApi")
@Slf4j
public class FaceRegist2Controller {
    @Autowired
    private IFaceRegistService faceRegistService;
    @Autowired
    private FaceRegistLogic faceRegistLogic;
    @Autowired
    private String localIpAddress;
    @Value("8081")
    private String imagesPort;
 
    //用于初始化人脸库测试使用
    @ResponseBody
    @PostMapping("/init")
    public Result2 init(@RequestBody Map<String, Object> params) {
        log.info("集体注册人脸信息");
        long begin = System.currentTimeMillis();
        File imageDir = new File(ConvertOp.convert2String(params.get("url")));
        for (File file : imageDir.listFiles()) {
            Path tempDir = Paths.get(System.getProperty("user.dir"), "images");
            try {
                // 确保目录存在
                if (!Files.exists(tempDir)) {
                    Files.createDirectories(tempDir);
                    log.info("创建图片目录: {}", tempDir.toAbsolutePath());
                }
                String userCode = file.getName().substring(0, file.getName().lastIndexOf("."));
                if (faceRegistService.checkExist("userID", userCode)) {
                    return ResultGenerator.genFailResult("用户ID已注册");
                }
                String base64Image = convert(file, true);
                RegistResult queryResult = faceRegistLogic.queryFace(base64Image);
                if (queryResult.getStatus() == 0) {
                    FaceRegistDO faceRegistDO = faceRegistService.selectOneByField("registIndex", queryResult.getMessage());
                    if (faceRegistDO != null) {
                        return ResultGenerator.genFailResult("用户照片已注册");
                    }
                }
                String userName = "/images/" + userCode + ".jpg";
                RegistResult registResult = faceRegistLogic.addFace(userCode, userName, base64Image);
                if (registResult.getStatus() != 0) {
                    return ResultGenerator.genFailResult(registResult.getMessage());
                }
                Path targetPath = tempDir.resolve(userCode + ".jpg");
                Files.copy(file.toPath(), targetPath, StandardCopyOption.REPLACE_EXISTING);
                JSONObject result = getSuccessResultJson();
                result.getJSONObject("data").put("faceUrl", "http://" + localIpAddress + ":" + imagesPort + "/images/" + userCode + ".jpg");
                long end = System.currentTimeMillis();
                log.info("user[{}],time addFace is:{}", userCode, (end - begin));
                return ResultGenerator.genSuccessResult(result);
            } catch (Exception e) {
                log.warn("addFace-文件上传失败");
                return ResultGenerator.genFailResult(e.getMessage());
            } finally {
                continue;
            }
        }
        return ResultGenerator.genSuccessResult();
    }
 
    //用于删除人脸库测试使用
    @ResponseBody
    @PostMapping("/deleteAll")
    @Transactional(rollbackFor = {Exception.class}, isolation = Isolation.READ_UNCOMMITTED)
    public Object deleteAll(@RequestBody Map<String, Object> params) throws Exception {
        Result result = Result.okResult();
        faceRegistLogic.deleteAllFace();
        return result;
    }
 
    @ResponseBody
    @PostMapping("/list")
    public Object list(@RequestBody Map<String, Object> params) {
        Result result = Result.okResult();
        HashMap<String, Object> paramMap = new HashMap<>();
        String sql = "1=1";
        String userName = ConvertOp.convert2String(params.get("userName"));
        if (!StringUtil.isEmpty(userName)) {
            sql += " and userName like #{userName}";
            paramMap.put("userName", "%" + userName + "%");
        }
        String userID = ConvertOp.convert2String(params.get("userID"));
        if (!StringUtil.isEmpty(userID)) {
            sql += " and userID like #{userID}";
            paramMap.put("userID", "%" + userID + "%");
        }
        List<FaceRegistDO> rows = faceRegistService.selectPageList("userID,userName,registDate,updateDate", sql, "id desc", paramMap);
        int count = faceRegistService.selectCount(sql, paramMap);
        result.add("rows", rows);
        result.add("total", count);
        return result;
    }
 
    /**
     * 注册人脸
     *
     * @param image
     * @param userCode
     * @return
     */
    @ResponseBody
    @PostMapping("/addFace")
    public Result2 insert(@RequestParam("image") MultipartFile image, String userCode) {
        log.info("注册人脸信息");
        long begin = System.currentTimeMillis();
        File tempFile = null;
        Path tempDir = Paths.get(System.getProperty("user.dir"), "images");
        String base64Image;
        try {
            // 确保目录存在
            if (!Files.exists(tempDir)) {
                Files.createDirectories(tempDir);
                log.info("创建图片目录: {}", tempDir.toAbsolutePath());
            }
            tempFile = Files.createTempFile(tempDir, "temp-addFace", ".jpg").toFile();
            try (InputStream inputStream = image.getInputStream()) {
                Files.copy(inputStream, tempFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
            }
            base64Image = convert(image, true);
        } catch (Exception e) {
            // 确保临时文件被删除
            if (tempFile != null && tempFile.exists()) {
                try {
                    if (!tempFile.delete()) {
                        log.warn("Failed to delete temp file: {}", tempFile.getAbsolutePath());
                    }
                } catch (Exception e2) {
                    log.warn("Error deleting temp file", e2);
                }
            }
            return ResultGenerator.genFailResult("addFace-文件上传失败");
        }
        try {
            if (faceRegistService.checkExist("userID", userCode)) {
                return ResultGenerator.genFailResult("用户ID已注册");
            }
            RegistResult queryResult = faceRegistLogic.queryFace(base64Image);
            if (queryResult.getStatus() == 0) {
                FaceRegistDO faceRegistDO = faceRegistService.selectOneByField("registIndex", queryResult.getMessage());
                if (faceRegistDO != null) {
                    return ResultGenerator.genFailResult("用户照片已注册");
                }
            }
            String userName = "/images/" + userCode + ".jpg";
            RegistResult registResult = faceRegistLogic.addFace(userCode, userName, base64Image);
            if (registResult.getStatus() != 0) {
                return ResultGenerator.genFailResult(registResult.getMessage());
            }
            Path targetPath = tempDir.resolve(userCode + ".jpg");
            Files.copy(tempFile.toPath(), targetPath, StandardCopyOption.REPLACE_EXISTING);
            JSONObject result = getSuccessResultJson();
            result.getJSONObject("data").put("faceUrl", "http://" + localIpAddress + ":" + imagesPort + "/images/" + userCode + ".jpg");
            long end = System.currentTimeMillis();
            log.info("user[{}],time addFace is:{}", userCode, (end - begin));
            return ResultGenerator.genSuccessResult(result);
        } catch (Exception e) {
            log.warn("addFace-文件上传失败");
            return ResultGenerator.genFailResult(e.getMessage());
        } finally {
            // 确保临时文件被删除
            if (tempFile != null && tempFile.exists()) {
                try {
                    if (!tempFile.delete()) {
                        log.warn("Failed to delete temp file: {}", tempFile.getAbsolutePath());
                    }
                } catch (Exception e) {
                    log.warn("Error deleting temp file", e);
                }
            }
        }
 
    }
 
    /**
     * 获取人脸地址
     *
     * @param userCode
     * @return
     */
    @ResponseBody
    @PostMapping("/getUserFaceUrl")
    public Result2 getUserFaceUrl(String userCode) {
        log.info("获取人脸信息");
        long begin = System.currentTimeMillis();
        FaceRegistDO faceRegistDO = faceRegistService.selectOne(userCode);
        long end = System.currentTimeMillis();
        log.info("user[{}],time getUserFaceUrl is:{}", userCode, (end - begin));
        if (faceRegistDO == null) {
            return ResultGenerator.genFailResult("获取不到数据");
        }
        return ResultGenerator.genSuccessResult("http://" + localIpAddress + ":" + imagesPort + "/images/" + userCode + ".jpg");
    }
 
    @ResponseBody
    @PostMapping("/identifyFace")
    public Result2 identifyFace(@RequestParam("image") MultipartFile image) {
        log.info("人脸识别");
        long begin = System.currentTimeMillis();
        String base64Image = null;
        try {
            base64Image = convert(image, true);
            long end = System.currentTimeMillis();
            log.info("time identifyFace 压缩图片is:{}", (end - begin));
            RegistResult registResult = faceRegistLogic.queryFace(base64Image);
            if (registResult.getStatus() != 0) {
                return ResultGenerator.genSuccessResult(registResult.getMessage());
            }
            FaceRegistDO faceRegistDO = faceRegistService.selectOneByField("registIndex", registResult.getMessage());
            String userId = faceRegistDO.getUserID();
            JSONObject result = getSuccessResultJson();
            JSONArray jsonArray = new JSONArray();
            JSONObject jsonObject = new JSONObject();
            jsonArray.add(jsonObject);
            jsonObject.put("score", 100);
            jsonObject.put("user_id", userId);
            result.getJSONObject("data").put("result", jsonArray);
            end = System.currentTimeMillis();
            log.info("user[{}],time identifyFace is:{}", userId, (end - begin));
            return ResultGenerator.genSuccessResult(result);
        } catch (Exception e) {
            log.warn("identifyFace Exception", e);
            return ResultGenerator.genSuccessResult(e.getMessage());
        }
    }
 
    @ResponseBody
    @PostMapping("/delFace")
    public Result2 delFace(String userCode) {
        String userID = userCode;
        if (!faceRegistService.checkExist("userID", userID)) {
            return ResultGenerator.genFailResult("用户ID不存在");
        }
        RegistResult registResult = faceRegistLogic.deleteFace(userID);
        if (registResult.getStatus() != 0) {
            return ResultGenerator.genFailResult("");
        }
        return ResultGenerator.genSuccessResult();
    }
 
    /**
     * 将MultipartFile转换为Data URL格式的字符串
     *
     * @param image 要转换的MultipartFile
     * @return 符合Data URL规范的字符串
     * @throws Exception 当读取文件或转换过程中发生错误时抛出
     */
    public static String convert(MultipartFile image, boolean needYs) throws Exception {
        if (needYs) {
            byte[] compressedBytes = null;
            // 1. 图片压缩处理
            // 对于小图片(小于1M)直接使用原图,大图片进行压缩
            if (image.getSize() > 1024 * 1024) {
                log.info("图片大小: {}KB,需要压缩", image.getSize() / 1024);
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                // 使用Thumbnails进行压缩,限制最大尺寸为1920x1080,质量0.7
                Thumbnails.of(image.getInputStream())
                        .size(1920, 1080)       // 按比例缩放,最大尺寸限制
                        .outputFormat("jpg")    // 明确输出格式
//                        .outputQuality(0.80f)   // 质量压缩,平衡大小和清晰度
                        .toOutputStream(outputStream);
                compressedBytes = outputStream.toByteArray();
                log.info("压缩后图片大小: {}KB", compressedBytes.length / 1024);
            } else {
                log.info("图片大小: {}KB,无需压缩", image.getSize() / 1024);
                compressedBytes = image.getBytes();
            }
            return "data:jpg;base64," + Base64.getEncoder().encodeToString(compressedBytes);
        } else {
            if (image == null || image.isEmpty()) {
                throw new IllegalArgumentException("文件不能为空");
            }
 
            // 获取文件的MIME类型
            String contentType = image.getContentType();
            if (contentType == null || !contentType.startsWith("image/")) {
                throw new IllegalArgumentException("不支持的文件类型,必须是图像文件");
            }
 
            // 读取文件字节并编码为Base64
            byte[] fileBytes = image.getBytes();
            String base64Encoded = Base64.getEncoder().encodeToString(fileBytes);
 
            // 构建Data URL格式的字符串
            return "data:" + contentType + ";base64," + base64Encoded;
        }
    }
 
    public static String convert(File imageFile, boolean needYs) throws Exception {
        // 验证文件合法性
        if (imageFile == null || !imageFile.exists() || !imageFile.isFile()) {
            throw new IllegalArgumentException("文件不存在或不是有效的文件");
        }
 
        if (needYs) {
            byte[] processedBytes = null;
            long fileSize = imageFile.length();
 
            // 图片压缩处理(大于1M的文件才压缩)
            if (fileSize > 1024 * 1024) {
                log.info("图片大小: {}KB,需要压缩", fileSize / 1024);
 
                try (InputStream inputStream = new FileInputStream(imageFile);
                     ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
 
                    // 使用Thumbnails进行压缩处理
                    Thumbnails.of(inputStream)
                            .size(1920, 1080)       // 按比例缩放,最大尺寸限制
                            .outputFormat("jpg")    // 明确输出格式
//                            .outputQuality(0.80f)   // 质量压缩参数
                            .toOutputStream(outputStream);
 
                    processedBytes = outputStream.toByteArray();
                    log.info("压缩后图片大小: {}KB", processedBytes.length / 1024);
                }
            } else {
                log.info("图片大小: {}KB,无需压缩", fileSize / 1024);
                // 小文件直接读取字节
                processedBytes = Files.readAllBytes(imageFile.toPath());
            }
 
            // 返回压缩后的Data URL(统一为jpg格式)
            return "data:image/jpg;base64," + Base64.getEncoder().encodeToString(processedBytes);
        } else {
            // 不压缩的情况,保留原始格式
            String contentType = Files.probeContentType(imageFile.toPath());
            if (contentType == null || !contentType.startsWith("image/")) {
                throw new IllegalArgumentException("不支持的文件类型,必须是图像文件");
            }
 
            // 读取文件字节并编码为Base64
            byte[] fileBytes = Files.readAllBytes(imageFile.toPath());
            String base64Encoded = Base64.getEncoder().encodeToString(fileBytes);
 
            // 构建Data URL格式的字符串
            return "data:" + contentType + ";base64," + base64Encoded;
        }
    }
 
    private JSONObject getSuccessResultJson() {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("error", 0);
        jsonObject.put("msg", "success");
        JSONObject data = new JSONObject();
        jsonObject.put("data", data);
        return jsonObject;
    }
 
    private JSONObject getIdentifyFaceSuccessResultJson() {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("error", 0);
        jsonObject.put("msg", "success");
        JSONObject data = new JSONObject();
        JSONArray resultArray = new JSONArray();
        JSONObject resultObject = new JSONObject();
        resultArray.add(resultObject);
        data.put("result", resultArray);
        jsonObject.put("data", data);
        return jsonObject;
    }
}