package com.example.lxcameraapi.service; import ai.onnxruntime.OrtException; import com.example.lxcameraapi.conf.AppConfig; import com.example.lxcameraapi.service.IndustrialCamera.algorithm.ONNXServiceNew; import com.example.lxcameraapi.service.IndustrialCamera.camera.lx.LxCameraService; import com.example.lxcameraapi.service.IndustrialCamera.camera.lx.config.BoxCountRequest; import com.example.lxcameraapi.service.IndustrialCamera.camera.lx.config.BoxCountResult; import com.example.lxcameraapi.service.IndustrialCamera.camera.lx.config.CaptureResult; import com.example.lxcameraapi.service.IndustrialCamera.opencv.OpencvService; import com.example.lxcameraapi.service.IndustrialCamera.yolo.BoundingBox; import com.example.lxcameraapi.service.IndustrialCamera.QrCode.WeChatDeCode; import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import jakarta.annotation.Resource; import java.awt.image.BufferedImage; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import javax.imageio.ImageIO; @Slf4j @Service public class AsyncProcessingService { @Resource private ONNXServiceNew onnxServiceNew; @Resource private OpencvService opencvService; @Resource private LxCameraService lxCameraService; @Resource private HttpNotifyService httpNotifyService; @Resource private AppConfig appConfig; /** * 异步处理品规识别 */ @Async public void processCategoryAsync(BoxCountRequest request, String path, String url, String targetIp, Integer targetPort, String targetPath) { try { log.info("异步品规识别任务开始"); List detectResults = onnxServiceNew.detect26(path, null); opencvService.drawBoundingBoxesOnImage(detectResults, path, path + "detect.jpg"); log.info("检测结果: {}", detectResults); String result = "Unknown"; if (!detectResults.isEmpty()) { // 统计每个 index 出现的次数 Map indexCountMap = detectResults.stream() .collect(Collectors.groupingBy( BoundingBox::getIndex, Collectors.counting() )); // 找到出现次数最多的 index Map.Entry maxIndexEntry = indexCountMap.entrySet().stream() .max(Map.Entry.comparingByValue()) .orElse(null); if (maxIndexEntry != null) { // 根据最多的 index 找到对应的 name result = detectResults.stream() .filter(box -> box.getIndex().equals(maxIndexEntry.getKey())) .findFirst() .map(BoundingBox::getName) .orElse("Unknown"); log.info("检测结果统计 - 最常见的类别: {}, 出现次数: {}", result, maxIndexEntry.getValue()); } } // 发送HTTP通知到 singleInventoryReturn if (targetIp != null && targetPort != null && targetPath != null) { httpNotifyService.sendBoxCountResult(targetIp, targetPort, targetPath, request.getTaskId(), request.getScanType(), result, url, 0); } else { log.warn("异步任务完成,但未配置目标服务器信息"); } } catch (OrtException e) { log.error("异步品规识别异常", e); } catch (Exception e) { log.error("异步品规识别异常", e); } } /** * 异步处理箱子计数 */ @Async public void processBoxCountAsync(BoxCountRequest request, CaptureResult captureResult, String targetIp, Integer targetPort, String targetPath) { try { log.info("异步箱子计数任务开始"); request.setPcdFilePath(captureResult.getFilePath("pointCloud")); BoxCountResult result = lxCameraService.countBoxes(request); log.info("箱子数量计算结果: {}", result.getSummary()); String imagePath = captureResult.getFilePath("rgb").replace(appConfig.getPicPath(), appConfig.getPicUrl()); String resultStr = String.valueOf(result.getTotalBoxCount()); // 发送HTTP通知到 singleInventoryReturn if (targetIp != null && targetPort != null && targetPath != null) { httpNotifyService.sendBoxCountResult(targetIp, targetPort, targetPath, request.getTaskId(), request.getScanType(), resultStr, imagePath, result.getTotalBoxCount()); } else { log.warn("异步任务完成,但未配置目标服务器信息"); } } catch (Exception e) { log.error("异步箱子计数异常", e); } } /** * 异步处理二维码识别 */ @Async public void processQrCodeAsync(Integer cameraId, String taskId, String path, String url, String targetIp, Integer targetPort, String targetPath, String scanType) { try { log.info("异步识别任务开始,路径: {}", path); List detectResults = onnxServiceNew.detect26(path, "qrCode"); opencvService.drawBoundingBoxesOnImage(detectResults, path, path + ".jpg"); log.info("异步检测结果: {}", detectResults); // 读取原始图片 BufferedImage originalImage = ImageIO.read(new File(path)); if (originalImage == null) { log.error("异步任务:无法读取图片: {}", path); return; } // 存储解码结果 List qrCodeResults = new ArrayList<>(); for (BoundingBox box : detectResults) { try { BufferedImage croppedImage = cropBoundingBox(originalImage, box, 30); ImageIO.write(croppedImage, "jpg", new File(path + "_" + box.getIndex() + ".jpg")); String qrCodeContent = WeChatDeCode.deCode(croppedImage); qrCodeResults.add(qrCodeContent); if (qrCodeContent != null) { log.info("异步解码成功: {}, 置信度: {}", qrCodeContent, box.getConfidence()); } else { log.warn("异步解码失败,box: {}", box); } } catch (Exception e) { log.error("异步解码二维码异常,box: {}", box, e); } } // 构建结果 String result = qrCodeResults.size() > 0 ? qrCodeResults.get(0).substring(0, 8) : "Unknown"; String imagePath = url + ".jpg"; // 发送HTTP通知到 singleInventoryQrCodeReturn if (targetIp != null && targetPort != null && targetPath != null) { httpNotifyService.sendQrCodeResult(targetIp, targetPort, targetPath, taskId, result, imagePath, qrCodeResults, scanType); } else { log.warn("异步任务完成,但未配置目标服务器信息"); } } catch (Exception e) { log.error("异步任务执行异常", e); } } private BufferedImage cropBoundingBox(BufferedImage originalImage, BoundingBox box, int expandPixels) { int imageWidth = originalImage.getWidth(); int imageHeight = originalImage.getHeight(); int x = (int) box.getX(); int y = (int) box.getY(); int width = (int) box.getW(); int height = (int) box.getH(); x = x - expandPixels; y = y - expandPixels; width = width + (expandPixels * 2); height = height + (expandPixels * 2); x = Math.max(0, Math.min(x, imageWidth - 1)); y = Math.max(0, Math.min(y, imageHeight - 1)); width = Math.min(width, imageWidth - x); height = Math.min(height, imageHeight - y); width = Math.max(1, width); height = Math.max(1, height); return originalImage.getSubimage(x, y, width, height); } }