|
|
|
|
@ -8,25 +8,18 @@ import com.sz.admin.monitor.mapper.CameraAlarmMapper;
|
|
|
|
|
import com.sz.admin.monitor.mapper.CameraMapper;
|
|
|
|
|
import com.sz.admin.monitor.mapper.NvrMapper;
|
|
|
|
|
import com.sz.admin.monitor.pojo.dto.edgebox.BoxAlarmReportDto;
|
|
|
|
|
import com.sz.admin.monitor.pojo.po.Camera;
|
|
|
|
|
import com.sz.admin.monitor.pojo.po.CameraAlarm;
|
|
|
|
|
import com.sz.admin.monitor.pojo.po.Nvr;
|
|
|
|
|
import com.sz.admin.monitor.pojo.po.Preset;
|
|
|
|
|
import com.sz.admin.monitor.pojo.po.*;
|
|
|
|
|
import com.sz.admin.monitor.pojo.vo.camerasnapshot.CameraSnapshotVO;
|
|
|
|
|
import com.sz.admin.monitor.sdk.ManageNVR;
|
|
|
|
|
import com.sz.admin.monitor.service.CameraService;
|
|
|
|
|
import com.sz.admin.monitor.service.CameraSnapshotService;
|
|
|
|
|
import com.sz.admin.monitor.service.ForwardService;
|
|
|
|
|
import com.sz.admin.monitor.service.PresetService;
|
|
|
|
|
import com.sz.admin.monitor.utils.ImageNameUtils;
|
|
|
|
|
import com.sz.admin.monitor.utils.OffsetCalculator;
|
|
|
|
|
import com.sz.admin.monitor.utils.RobustImageMatcherUtil;
|
|
|
|
|
import com.sz.admin.monitor.service.*;
|
|
|
|
|
import com.sz.admin.monitor.utils.*;
|
|
|
|
|
import com.sz.admin.system.pojo.dto.sysmessage.Message;
|
|
|
|
|
import com.sz.admin.system.service.SysMessageService;
|
|
|
|
|
import com.sz.core.common.entity.SocketMessage;
|
|
|
|
|
import com.sz.core.common.entity.TransferMessage;
|
|
|
|
|
import com.sz.core.common.enums.MessageTransferScopeEnum;
|
|
|
|
|
import com.sz.core.common.enums.SocketChannelEnum;
|
|
|
|
|
import com.sz.core.util.JsonUtils;
|
|
|
|
|
import com.sz.redis.WebsocketRedisService;
|
|
|
|
|
import com.sz.security.core.util.LoginUtils;
|
|
|
|
|
import jakarta.annotation.Resource;
|
|
|
|
|
@ -44,6 +37,8 @@ import java.util.Base64;
|
|
|
|
|
import java.util.HashMap;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
import java.util.concurrent.CompletableFuture;
|
|
|
|
|
import java.util.concurrent.Executor;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* ClassName: ScheduleTask
|
|
|
|
|
@ -71,7 +66,10 @@ public class ScheduledTask {
|
|
|
|
|
private SysMessageService sysMessageService;
|
|
|
|
|
@Resource
|
|
|
|
|
private ForwardService forwardService;
|
|
|
|
|
|
|
|
|
|
@Resource
|
|
|
|
|
private BlurDetectionService blurDetectionService;
|
|
|
|
|
@Resource(name = "cameraInspectionExecutor")
|
|
|
|
|
private Executor cameraInspectionExecutor;
|
|
|
|
|
|
|
|
|
|
// @Scheduled(cron = "0/5 * * * * ?")
|
|
|
|
|
public void test()
|
|
|
|
|
@ -89,10 +87,192 @@ public class ScheduledTask {
|
|
|
|
|
msg.setToPushAll(true);
|
|
|
|
|
websocketRedisService.sendServiceToWs(msg);
|
|
|
|
|
}
|
|
|
|
|
// 定期模糊检测
|
|
|
|
|
// @Scheduled(cron = "0/20 * * * * ?")
|
|
|
|
|
public void executeFuzzyDetection() {
|
|
|
|
|
log.info("执行模糊检测");
|
|
|
|
|
// 遍历模糊检测表
|
|
|
|
|
List<BlurDetection> blurDetectionList = blurDetectionService.list();
|
|
|
|
|
// 过滤掉关闭的状态
|
|
|
|
|
blurDetectionList = blurDetectionList.stream().filter(blurDetection -> blurDetection.getEnable() == 1).toList();
|
|
|
|
|
if (blurDetectionList.isEmpty()) {
|
|
|
|
|
log.info("无启用的模糊检测任务");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
int count = 0;
|
|
|
|
|
for (BlurDetection blurDetection : blurDetectionList) {
|
|
|
|
|
Long cameraId = blurDetection.getCameraId();
|
|
|
|
|
try {
|
|
|
|
|
Camera camera = cameraService.getById(cameraId);
|
|
|
|
|
// 获取基准图
|
|
|
|
|
String imagePath1 = camera.getHomeImagePath();
|
|
|
|
|
// 检查基准图是否存在
|
|
|
|
|
boolean isExists = true;
|
|
|
|
|
if (imagePath1 == null || imagePath1.trim().isEmpty()) {
|
|
|
|
|
log.warn("摄像头[{}] 未设置基准图路径", cameraId);
|
|
|
|
|
isExists = false;
|
|
|
|
|
} else {
|
|
|
|
|
File file1 = new File(imagePath1);
|
|
|
|
|
if (!file1.exists() || !file1.isFile()) {
|
|
|
|
|
log.error("基准图文件物理路径不存在:{}", imagePath1);
|
|
|
|
|
isExists = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 抓取当前图
|
|
|
|
|
String filename = ImageNameUtils.generateFileName("CAPTURE", cameraId);
|
|
|
|
|
String imagePath2 = manageNVR.capturePic(cameraId.intValue(), filename);
|
|
|
|
|
if (imagePath2 == null || imagePath2.isEmpty()) {
|
|
|
|
|
log.error("抓拍图片失败,摄像头 ID: {}", cameraId);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
// 检查抓拍图是否存在
|
|
|
|
|
File file2 = new File(imagePath2);
|
|
|
|
|
if (!file2.exists() || !file2.isFile()) {
|
|
|
|
|
log.error("抓拍图不存在:{}", imagePath2);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
count++;
|
|
|
|
|
// 进行单一背景检测
|
|
|
|
|
BackgroundDetector.DetectResult result = BackgroundDetector.detectBackground(imagePath2);
|
|
|
|
|
if("1".equals(result.value))
|
|
|
|
|
{
|
|
|
|
|
// 当前摄像头面对的是白墙,直接进行报警
|
|
|
|
|
handleAnalysisResult(blurDetection, imagePath2, result);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
// 进行模糊图片对比
|
|
|
|
|
BlurDetectorV4.DetectResult detectResult = null;
|
|
|
|
|
if (isExists) {
|
|
|
|
|
// 基准图存在,使用双图对比功能
|
|
|
|
|
detectResult = BlurDetectorV4.doubleDetectBlur(imagePath1, imagePath2);
|
|
|
|
|
} else {
|
|
|
|
|
// 基准图不存在,使用单图对比功能
|
|
|
|
|
detectResult = BlurDetectorV4.detectBlur(imagePath2);
|
|
|
|
|
}
|
|
|
|
|
log.info("模糊检测结果:{}", detectResult);
|
|
|
|
|
handleAnalysisResult(blurDetection, imagePath1, imagePath2, detectResult, isExists);
|
|
|
|
|
log.info("模糊检测完成,共检测{}个摄像头", count);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.error("摄像头 ID [{}] 模糊检测过程中发生未知异常", cameraId, e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//Result{type='bpmh', value='1', code='2000', desc='模糊 score=39.82', conf=1.0, score=39.82, ratio=0.00}
|
|
|
|
|
public record DetectResult(String desc,double score) {
|
|
|
|
|
}
|
|
|
|
|
// 分析背景检测结果并且报警
|
|
|
|
|
private void handleAnalysisResult(BlurDetection blurDetection, String imagePath, BackgroundDetector.DetectResult result) throws IOException {
|
|
|
|
|
Camera camera = cameraService.getById(blurDetection.getCameraId());
|
|
|
|
|
CameraAlarm cameraAlarm = new CameraAlarm();
|
|
|
|
|
cameraAlarm.setCameraId(camera.getId());
|
|
|
|
|
Nvr nvr = nvrMapper.selectOneById(camera.getNvrId());
|
|
|
|
|
cameraAlarm.setAlarmType(6);
|
|
|
|
|
cameraAlarm.setAlarmAreaId(nvr.getStationId());
|
|
|
|
|
cameraAlarm.setChannelId(camera.getChannelId());
|
|
|
|
|
cameraAlarm.setCameraNo(camera.getCameraNo());
|
|
|
|
|
cameraAlarm.setCameraName(camera.getName());
|
|
|
|
|
cameraAlarm.setCaptureImage(imagePath);
|
|
|
|
|
DetectResult backgroundResult = new DetectResult(result.desc, result.score);
|
|
|
|
|
cameraAlarm.setAlgoResult(JsonUtils.toJsonString(result));
|
|
|
|
|
cameraAlarm.setStatus(0);
|
|
|
|
|
cameraAlarmMapper.insert(cameraAlarm);
|
|
|
|
|
SocketMessage bean = new SocketMessage();
|
|
|
|
|
Map<String, Object> data = new HashMap<>();
|
|
|
|
|
data.put("title", "摄像头报警");
|
|
|
|
|
data.put("content", "摄像头[" + camera.getId() + "]发生模糊,请及时处理!");
|
|
|
|
|
bean.setData(JSON.toJSONString(data));
|
|
|
|
|
bean.setChannel(SocketChannelEnum.MESSAGE);
|
|
|
|
|
bean.setScope(MessageTransferScopeEnum.SOCKET_CLIENT);
|
|
|
|
|
TransferMessage msg = new TransferMessage();
|
|
|
|
|
msg.setMessage(bean);
|
|
|
|
|
msg.setFromUser("system");
|
|
|
|
|
msg.setToPushAll(true);
|
|
|
|
|
websocketRedisService.sendServiceToWs(msg);
|
|
|
|
|
BoxAlarmReportDto reportDto = new BoxAlarmReportDto();
|
|
|
|
|
reportDto.setAlarmReportTime(LocalDateTime.now());
|
|
|
|
|
reportDto.setAlarmReportType(AlarmReportEnums.BLUR_ALARM.getAlarmDescription());
|
|
|
|
|
reportDto.setDescription("摄像头拍摄的图片出现模糊");
|
|
|
|
|
byte[] CaptureFileContent = Files.readAllBytes(Paths.get(imagePath));
|
|
|
|
|
reportDto.setCaptureImage(Base64.getEncoder().encodeToString(CaptureFileContent));
|
|
|
|
|
reportDto.setUrl(blurDetection.getUrl());
|
|
|
|
|
reportDto.setCameraName(camera.getName());
|
|
|
|
|
reportDto.setCameraId(camera.getId());
|
|
|
|
|
reportDto.setCameraNo(camera.getCameraNo());
|
|
|
|
|
try {
|
|
|
|
|
forwardService.enrichAndForward(reportDto);
|
|
|
|
|
}catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
log.error("模糊报警上报失败,摄像头 ID: {}, 相机编号:{}",
|
|
|
|
|
camera.getId(), camera.getCameraNo(), e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
// 分析模糊算法并且报警
|
|
|
|
|
private void handleAnalysisResult(BlurDetection blurDetection, String imagePath1, String imagePath2, BlurDetectorV4.DetectResult detectResult, boolean isExists) throws IOException {
|
|
|
|
|
if ("1".equals(detectResult.value)) {
|
|
|
|
|
// 发生了模糊,需要保存报警信息等人工处理
|
|
|
|
|
Camera camera = cameraService.getById(blurDetection.getCameraId());
|
|
|
|
|
CameraAlarm cameraAlarm = new CameraAlarm();
|
|
|
|
|
cameraAlarm.setCameraId(camera.getId());
|
|
|
|
|
// 设置告警区域
|
|
|
|
|
// 根据摄像头查询它对应的nvr
|
|
|
|
|
Nvr nvr = nvrMapper.selectOneById(camera.getNvrId());
|
|
|
|
|
// 设置告警区域
|
|
|
|
|
cameraAlarm.setAlarmType(6);
|
|
|
|
|
cameraAlarm.setAlarmAreaId(nvr.getStationId());
|
|
|
|
|
cameraAlarm.setChannelId(camera.getChannelId());
|
|
|
|
|
cameraAlarm.setCameraNo(camera.getCameraNo());
|
|
|
|
|
cameraAlarm.setCameraName(camera.getName());
|
|
|
|
|
cameraAlarm.setBaseImage(imagePath1);
|
|
|
|
|
cameraAlarm.setCaptureImage(imagePath2);
|
|
|
|
|
// 算法的结果
|
|
|
|
|
DetectResult result = new DetectResult(detectResult.desc, detectResult.score);
|
|
|
|
|
cameraAlarm.setAlgoResult(JsonUtils.toJsonString(result));
|
|
|
|
|
// 状态为未处理
|
|
|
|
|
cameraAlarm.setStatus(0);
|
|
|
|
|
cameraAlarmMapper.insert(cameraAlarm);
|
|
|
|
|
// log.info("生成模糊报警: 通道{}, 模糊信息: {}", camera.getChannelId(), detectResult.getDescription());
|
|
|
|
|
// 向前端主动推送消息
|
|
|
|
|
SocketMessage bean = new SocketMessage();
|
|
|
|
|
Map<String, Object> data = new HashMap<>();
|
|
|
|
|
data.put("title", "摄像头报警");
|
|
|
|
|
data.put("content", "摄像头[" + camera.getId() + "]发生模糊,请及时处理!");
|
|
|
|
|
bean.setData(JSON.toJSONString(data));
|
|
|
|
|
bean.setChannel(SocketChannelEnum.MESSAGE);
|
|
|
|
|
bean.setScope(MessageTransferScopeEnum.SOCKET_CLIENT);
|
|
|
|
|
TransferMessage msg = new TransferMessage();
|
|
|
|
|
msg.setMessage(bean);
|
|
|
|
|
msg.setFromUser("system");
|
|
|
|
|
msg.setToPushAll(true);
|
|
|
|
|
websocketRedisService.sendServiceToWs(msg);
|
|
|
|
|
// 统一处理报警信息后,将摄像头信息+报警信息上报给别人服务器
|
|
|
|
|
BoxAlarmReportDto reportDto = new BoxAlarmReportDto();
|
|
|
|
|
reportDto.setAlarmReportTime(LocalDateTime.now());
|
|
|
|
|
reportDto.setAlarmReportType(AlarmReportEnums.BLUR_ALARM.getAlarmDescription());
|
|
|
|
|
reportDto.setDescription("摄像头拍摄的图片出现模糊");
|
|
|
|
|
if(isExists && imagePath1 !=null) {
|
|
|
|
|
byte[] BaseFileContent = Files.readAllBytes(Paths.get(imagePath1));
|
|
|
|
|
reportDto.setBaseImage(Base64.getEncoder().encodeToString(BaseFileContent));
|
|
|
|
|
}
|
|
|
|
|
byte[] CaptureFileContent = Files.readAllBytes(Paths.get(imagePath2));
|
|
|
|
|
reportDto.setCaptureImage(Base64.getEncoder().encodeToString(CaptureFileContent));
|
|
|
|
|
reportDto.setUrl(blurDetection.getUrl());
|
|
|
|
|
reportDto.setCameraName(camera.getName());
|
|
|
|
|
reportDto.setCameraId(camera.getId());
|
|
|
|
|
reportDto.setCameraNo(camera.getCameraNo());
|
|
|
|
|
try {
|
|
|
|
|
forwardService.enrichAndForward(reportDto);
|
|
|
|
|
}catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
log.error("模糊报警上报失败,摄像头 ID: {}, 相机编号:{}",
|
|
|
|
|
camera.getId(), camera.getCameraNo(), e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 定期检查
|
|
|
|
|
@Scheduled(cron = "0/20 * * * * ?")
|
|
|
|
|
@SneakyThrows
|
|
|
|
|
public void executeInspection() {
|
|
|
|
|
public void executeInspection() throws InterruptedException {
|
|
|
|
|
// 从摄像头表中获取设置了抓图对比和在线的摄像头
|
|
|
|
|
List<Camera> cameraList = cameraService.selectListByInspection();
|
|
|
|
|
// 然后根据摄像头id查询设置为标准位的预置位,
|
|
|
|
|
@ -104,36 +284,53 @@ public class ScheduledTask {
|
|
|
|
|
}
|
|
|
|
|
List<Preset> presetList = presetService.selectByCameraIds(cameraIds);
|
|
|
|
|
for (Preset preset : presetList) {
|
|
|
|
|
// 调用SDK让摄像头回归到该预置位
|
|
|
|
|
boolean ok = manageNVR.ptzPresets(preset.getCameraId().intValue(), 39, String.valueOf(preset.getPresetId()), preset.getPresetName());
|
|
|
|
|
// 延时5秒
|
|
|
|
|
CompletableFuture.runAsync(() -> {
|
|
|
|
|
// 调用具体的单次检测逻辑
|
|
|
|
|
processSinglePreset(preset);
|
|
|
|
|
}, cameraInspectionExecutor).exceptionally(e -> {
|
|
|
|
|
// 捕获线程池级别或执行过程中的严重异常
|
|
|
|
|
log.error("预置位[{}]异步巡检任务执行失败", preset.getPresetId(), e);
|
|
|
|
|
return null;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
private void processSinglePreset(Preset preset) {
|
|
|
|
|
Long cameraId = preset.getCameraId();
|
|
|
|
|
try {
|
|
|
|
|
boolean ok = manageNVR.ptzPresets(cameraId.intValue(), 39, String.valueOf(preset.getPresetId()), preset.getPresetName());
|
|
|
|
|
// 这里的 sleep 现在是在独立的异步线程中执行的,不会阻塞主线程!
|
|
|
|
|
Thread.sleep(5000);
|
|
|
|
|
if (ok) {
|
|
|
|
|
// 抓取一张图片
|
|
|
|
|
String filename = ImageNameUtils.generateFileName("CAPTURE",preset.getCameraId());
|
|
|
|
|
//String image2 = "D:\\work\\images\\CAPTURE_367_20260212092406664_2d117293.jpg";
|
|
|
|
|
// String image2 = "D:\\work\\images\\CAPTURE_19_20260302152457977_db33f5a8.jpg";
|
|
|
|
|
String image2 = manageNVR.capturePic(preset.getCameraId().intValue(), filename);
|
|
|
|
|
// 从图片表中,根据预置位,摄像机id,类型为巡检为条件查询出基准图
|
|
|
|
|
CameraSnapshotVO cameraSnapshotVO = cameraSnapshotService.selectByCameraIdAndPresetIndex(preset.getCameraId(), preset.getPresetId());
|
|
|
|
|
if (cameraSnapshotVO == null || cameraSnapshotVO.getImagePath() == null) {
|
|
|
|
|
log.warn("摄像机[{}] 未设置基准图,无法对比", preset.getCameraId());
|
|
|
|
|
continue;
|
|
|
|
|
String filename = ImageNameUtils.generateFileName("CAPTURE", cameraId);
|
|
|
|
|
String image2 = manageNVR.capturePic(cameraId.intValue(), filename);
|
|
|
|
|
// String image2="D:\\work\\images\\CAPTURE_258_20260320170313838_4680425d.jpg";
|
|
|
|
|
// 抓图合法性校验
|
|
|
|
|
if (image2 == null || image2.isBlank()) {
|
|
|
|
|
log.error("摄像机[{}] 抓拍失败,无法获取当前图片", cameraId);
|
|
|
|
|
return; // 结束当前预置位的处理
|
|
|
|
|
}
|
|
|
|
|
CameraSnapshotVO cameraSnapshotVO = cameraSnapshotService.selectByCameraIdAndPresetIndex(cameraId, preset.getPresetId());
|
|
|
|
|
if (cameraSnapshotVO == null || cameraSnapshotVO.getImagePath() == null || cameraSnapshotVO.getImagePath().isBlank()) {
|
|
|
|
|
log.warn("摄像机[{}] 未设置预置位基准图,无法对比", cameraId);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// 调用图片对比算法,校验摄像头是否移位
|
|
|
|
|
// 基准图
|
|
|
|
|
String image1 = cameraSnapshotVO.getImagePath();
|
|
|
|
|
// 对比
|
|
|
|
|
Map<String, Object> map = RobustImageMatcherUtil.calculateOffset(image1, image2);
|
|
|
|
|
log.info("图片对比结果:{}", map);
|
|
|
|
|
// 判断结果并报警
|
|
|
|
|
handleAnalysisResult(preset, cameraSnapshotVO.getImagePath(), image2, map);
|
|
|
|
|
log.info("摄像机[{}] 预置位[{}] 对比结果:{}", cameraId, preset.getPresetId(), map);
|
|
|
|
|
if (map != null && map.containsKey("value")) {
|
|
|
|
|
handleAnalysisResult(preset, image1, image2, map);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} catch (InterruptedException ie) {
|
|
|
|
|
log.error("摄像机[{}] 等待云台转动被中断", cameraId);
|
|
|
|
|
Thread.currentThread().interrupt();
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.error("摄像机[{}] 预置位[{}] 巡检过程中发生业务异常", cameraId, preset.getPresetId(), e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//判断结果并报警
|
|
|
|
|
//判断移位算法结果并报警
|
|
|
|
|
private void handleAnalysisResult(Preset preset, String imagePath, String image2, Map<String, Object> map) throws IOException {
|
|
|
|
|
int value = (int) map.get("value");
|
|
|
|
|
if (value == 1) {
|
|
|
|
|
@ -147,6 +344,7 @@ public class ScheduledTask {
|
|
|
|
|
// 设置告警区域
|
|
|
|
|
cameraAlarm.setAlarmAreaId(nvr.getStationId());
|
|
|
|
|
cameraAlarm.setChannelId(camera.getChannelId());
|
|
|
|
|
cameraAlarm.setCameraNo(camera.getCameraNo());
|
|
|
|
|
cameraAlarm.setCameraName(camera.getName());
|
|
|
|
|
cameraAlarm.setPresetIndex(preset.getPresetId());
|
|
|
|
|
// 标记为移位报警
|
|
|
|
|
@ -185,7 +383,13 @@ public class ScheduledTask {
|
|
|
|
|
reportDto.setCameraName(camera.getName());
|
|
|
|
|
reportDto.setCameraId(camera.getId());
|
|
|
|
|
reportDto.setCameraNo(camera.getCameraNo());
|
|
|
|
|
try {
|
|
|
|
|
forwardService.enrichAndForward(reportDto);
|
|
|
|
|
}catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
log.error("移位报警上报失败,摄像头 ID: {}, 相机编号:{}",
|
|
|
|
|
camera.getId(), camera.getCameraNo(), e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|