AiTaskService
package com.ruoyi.pc.service;
import com.ruoyi.pc.domain.*;
import java.util.List;
public interface AiTaskService {
/**
* 处理消息
*
* @param message
*/
public void processMessage(String message);
public void saveMonitoringDeviceResult(String createDate, List<ModelResult> modelResults, String frameImgPath, PcMonitoringDevice pcMonitoringDevice, PcMonitoringDeviceModel monitoringDeviceModel);
public void publishAlarmInformation(PcMonitoringDeviceResult monitoringDeviceResult, String deptName, String aiModelName, String monitoringDeviceName);
CheckResultAlarmRule checkResultRule(PcMonitoringDeviceModel pcMonitoringDeviceModel,List<ModelResult> modelResults);
}
public class AiTaskServiceImpl implements AiTaskService
package com.ruoyi.pc.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.config.ServerConfig;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.websocket.WebSocketServer;
import com.ruoyi.pc.config.DeviceMqtt;
import com.ruoyi.pc.config.redis.RedisUtil;
import com.ruoyi.pc.domain.*;
import com.ruoyi.pc.nodeserver.XbsNodeService;
import com.ruoyi.pc.service.*;
import com.ruoyi.pc.task.util.Location;
import com.ruoyi.pc.task.util.clustering.CentralPoint;
import com.ruoyi.pc.task.util.clustering.ClusteringUtils;
import com.ruoyi.pc.task.util.clustering.RectangleUtil;
import com.ruoyi.pc.util.*;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysDeptService;
import com.ruoyi.system.service.ISysUserService;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import net.sf.json.JSONArray;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
/**
* agent控制服务
*/
@Service("aiTaskService")
public class AiTaskServiceImpl implements AiTaskService {
public static Logger logger = LoggerFactory.getLogger(AiTaskServiceImpl.class);
Gson gson = new Gson();
@Resource
ThreadPoolTaskExecutor pool;
@Autowired
RedisUtil redisUtil;
@Autowired
ISysConfigService configService;
@Autowired
IPcMonitoringDeviceResultService iPcMonitoringDeviceResultService;
@Autowired
IPcAlarmConfigService pcAlarmConfigService;
@Autowired
IPcMonitoringDeviceVolumeService iPcMonitoringDeviceVolumeService;
@Autowired
AgentService agentService;
@Autowired
XbsNodeService xbsNodeService;
@Autowired
IPcPlayRecordService playRecordService;
@Autowired
IPcMonitoringTaskService taskService;
@Resource
private ISysDeptService sysDeptService;
@Autowired
DeRecognition deRecognition;
@Resource
private IPcDataReportConfigService pcDataReportConfigService;
@Resource
private ISysUserService userService;
@Resource
private WebSocketServer webSocketServer;
@Autowired
private ServerConfig serverConfig;
/**
* 处理消息
*
* @param message
*/
public void processMessage(String message) {
// 1、获取创建时间、图片地址、通道信息、关联模型信息、格式化后的识别结果
AiMessage aiMessage = null;
try {
aiMessage = gson.fromJson(message, AiMessage.class);
} catch (JsonSyntaxException e) {
logger.error("格式转换错误" + e);
return;
}
Long taskId = aiMessage.getTaskId();
String createDate = aiMessage.getCreateDate();
logger.info("任务ID--------" + taskId + ",发布时间--------" + createDate);
String imgPath = aiMessage.getImgPath();
PcMonitoringDevice pcMonitoringDevice = aiMessage.getPcMonitoringDevice();
PcMonitoringDeviceModel pcMonitoringDeviceModel = aiMessage.getPcMonitoringDeviceModel();
List<ModelResult> modelResults = aiMessage.getModelResults();
List<ModelResult> coincideModelResults = new ArrayList<>();
CheckResultAlarmRule checkResultAlarmRule = checkResultRule(pcMonitoringDeviceModel, modelResults);
//3、判断当前通道当前模型是否可以报警
if (checkResultAlarmRule.isAlarm()) {
ArrayList<Location> locations = checkResultAlarmRule.getLocations();
boolean flag = true;
//获取当前模型的监控任务时长
//判断是否开启去重
if (pcMonitoringDeviceModel.getEnableDeduplication() != null && StringUtils.isNotBlank(pcMonitoringDeviceModel.getEnableDeduplication())
&& pcMonitoringDeviceModel.getDeduplicationMode() != null && StringUtils.isNotBlank(pcMonitoringDeviceModel.getDeduplicationMode())
&& pcMonitoringDeviceModel.getDeduplicationDuration() != null && StringUtils.isNotBlank(pcMonitoringDeviceModel.getDeduplicationDuration()))
if (Objects.equals(pcMonitoringDeviceModel.getEnableDeduplication(), "0")) {
if (!(pcMonitoringDeviceModel.getType().equals(URLConstant.MODEL_TYPE_2) && locations.size() == 0)) {
//进行告警去重,如果告警信息一致则直接过滤,不一致则进行监测时长判断
if (Objects.equals(pcMonitoringDeviceModel.getDeduplicationMode(), "0")) {
//过滤数量
flag = deRecognition.quantityDetection(taskId, pcMonitoringDeviceModel, coincideModelResults, pcMonitoringDeviceModel.getDeduplicationDuration());
} else if (Objects.equals(pcMonitoringDeviceModel.getDeduplicationMode(), "1")) {
//过滤坐标
flag = deRecognition.coordinateDetection(taskId, pcMonitoringDeviceModel, coincideModelResults, pcMonitoringDeviceModel.getDeduplicationDuration());
} else if (Objects.equals(pcMonitoringDeviceModel.getDeduplicationMode(), "2")) {
//去重识别
flag = deRecognition.deduplicationIdentification(taskId, pcMonitoringDeviceModel, pcMonitoringDeviceModel.getDeduplicationDuration());
}
}
}
if (!flag) {
return;
}
//4、判断是否设置监测时长以及是否可以报警
TimeThresholdInfo timeThresholdInfo = isTimeThreshold(createDate, taskId, locations, imgPath, pcMonitoringDeviceModel, modelResults);
if (timeThresholdInfo.isFlag()) {
//结果坐标
ArrayList<Location> newLocations = timeThresholdInfo.getLocations();
//模型框图坐标
List<ModelResult> newModelResults = timeThresholdInfo.getModelResults();
// 5、保存告警信息
pool.execute(() -> {
SysDept sysDept = sysDeptService.selectDeptById(pcMonitoringDevice.getDeptId());
//生成水印内容
List<String> markContents = new ArrayList<String>();
markContents.add("模型名称:" + pcMonitoringDeviceModel.getAiModelName());
markContents.add("监控设备名称:" + pcMonitoringDevice.getName());
markContents.add("告警信息:" + pcMonitoringDeviceModel.getAlarmDetails());
markContents.add("告警时间:" + createDate);
markContents.add("部门名称:" + sysDept.getDeptName());
//5.1、根据坐标截图保存,并返回框图地址
String frameImgPath = transformImg(newLocations, timeThresholdInfo.getImgPath(), pcMonitoringDevice.getImei(), pcMonitoringDeviceModel, markContents);
if (null == frameImgPath || frameImgPath.trim().length() == 0) {
return;
}
//5.2、保存告警信息,包括框图访问地址
saveMonitoringDeviceResult(createDate, newModelResults, frameImgPath, pcMonitoringDevice, pcMonitoringDeviceModel);
});
//判断当前通道模型的识别结果是否进行播报:0:播报,1:不播报
if (pcMonitoringDeviceModel.getSoundColumnAlarmStatus() != null && pcMonitoringDeviceModel.getSoundColumnAlarmStatus() == 1) {
return;
}
// 6、音箱播控
pool.execute(new Runnable() {
@Override
public void run() {
//6.1、根据通道ID,获取关联音柱设备列表
List<PcDevice> pcList = iPcMonitoringDeviceVolumeService.selectPcDeviceListByMonitoringDeviceId(pcMonitoringDeviceModel.getMonitoringDeviceId());
//6.2、判断是否播放音箱设备,播放模型对应的音频文件
List<PcDevice> xbsPcList = new ArrayList<>(); //有线音柱设备集合
List<PcDevice> xxyPcList = new ArrayList<>(); //无线音柱设备集合
for (PcDevice pcDevice : pcList) {
if (null != pcDevice && pcDevice.getType().equals(URLConstant.DEVICE_TYPE_XBS)) {
xbsPcList.add(pcDevice);
}
if (null != pcDevice && pcDevice.getType().equals(URLConstant.DEVICE_TYPE_XXY)) {
xxyPcList.add(pcDevice);
}
}
//6.3.1、有线音柱将设备全部播放
if (xbsPcList.size() > 0) {
try {
//8.12.1、有线音柱将设备全部停止
xbsNodeService.stopPcDeviceByAep(xbsPcList);
//8.12.2、有线音柱开始播放设备
xbsNodeService.palyPcDeviceByAep(xbsPcList, pcMonitoringDeviceModel.getAudioUrl());
} catch (Exception e) {
logger.error("有线音柱播放失败" + e);
}
}
//6.3.2、无线音柱将设备全部播放
if (xxyPcList.size() > 0) {
try {
// 加入无线音柱操作列表
ArrayList<DeviceMqtt> devices = new ArrayList<DeviceMqtt>();
for (int i = 0; i < xxyPcList.size(); i++) {
PcDevice pcDevice = xxyPcList.get(i);
DeviceMqtt deviceMqtt = new DeviceMqtt(pcDevice.getAep());
deviceMqtt.setTask_id("202101011200371234"); //默认
deviceMqtt.setVol(Integer.valueOf(pcDevice.getVol()));
devices.add(deviceMqtt);
}
//8.12、开始播放无线音柱
agentService.setPlayService(pcMonitoringDeviceModel.getAudioUrl(), URLConstant.PLAY_LEVEL_1, URLConstant.NORMAL_PLAY, devices);
} catch (Exception e) {
logger.error("无线音柱播放失败" + e);
}
}
//6.4、记录音箱设备播放记录
playRecordService.insertPcPlayRecord(pcMonitoringDevice.getCreateId(), pcMonitoringDevice.getDeptId(), pcList, URLConstant.TYPE_MONITORING);
}
});
}
}
}
/**
* 检测结果告警规则
* @param pcMonitoringDeviceModel pcMonitoringDeviceModel
* @param modelResults List<ModelResult>
* @return CheckResultAlarmRule
*/
public CheckResultAlarmRule checkResultRule(PcMonitoringDeviceModel pcMonitoringDeviceModel,List<ModelResult> modelResults){
CheckResultAlarmRule checkResultAlarmRule = new CheckResultAlarmRule();
List<ModelResult> coincideModelResults = new ArrayList<>();
ArrayList<Location> locations = null;
boolean isAlarm = false; //默认不保存告警信息
// 2、 当模型比较类型是大于等于阈值时
if (pcMonitoringDeviceModel.getType().equals(URLConstant.MODEL_TYPE_0)) {
// 2.1、获取模型识别结果与通道框选区域重合的识别结果列表
coincideModelResults = getCoincideModelResults(modelResults, pcMonitoringDeviceModel);
// 2.2、判断重合的模型识别结果列表长度是否大于等于告警目标数阈值
if (coincideModelResults.size() >= Integer.parseInt(pcMonitoringDeviceModel.getNumber())) {
// 2.3、若是,继续格式化模型识别结果列表为框图Location列表
locations = getLocations(coincideModelResults);
// 2.4、定制算法判断(聚集算法、其他算法)并更新框图Location列表
// 2.4.1、聚集算法告警判断,默认告警
//2.4.2、其他算法
isAlarm = isGather(pcMonitoringDeviceModel, locations);
}
}
if (pcMonitoringDeviceModel.getType().equals(URLConstant.MODEL_TYPE_1)) {
// 2.1、获取模型识别结果与通道框选区域重合的识别结果列表
coincideModelResults = getCoincideModelResults(modelResults, pcMonitoringDeviceModel);
// 2.2、判断重合的模型识别结果列表长度是否大于等于告警目标数阈值
if (coincideModelResults.size() >= Integer.parseInt(pcMonitoringDeviceModel.getNumber())) {
// 2.3、若是,继续格式化模型识别结果列表为框图Location列表
locations = getLocations(coincideModelResults);
// 2.4、定制算法判断(聚集算法、其他算法)并更新框图Location列表
// 2.4.1、聚集算法告警判断,默认告警
//2.4.2、其他算法
isAlarm = isGather(pcMonitoringDeviceModel, locations);
}
}
// 2、 当模型比较类型是小于等于阈值(包含识别没有结果)时
if (pcMonitoringDeviceModel.getType().equals(URLConstant.MODEL_TYPE_2)) {
logger.info("-----------------------start-------------------{}", gson.toJson(modelResults));
List<ModelResult> modelResultList = new ArrayList<>();
for (ModelResult modelResult : modelResults) {
if (modelResult.getBbox().size() > 0 && modelResult.getScore() > Double.parseDouble(pcMonitoringDeviceModel.getSimilarity())) {
modelResultList.add(modelResult);
}
}
if (modelResultList.size() > 0) {
Map<String, List<ModelResult>> coincideModelResultsType = new HashMap<>();
JSONArray coordinates = JSONArray.fromObject(pcMonitoringDeviceModel.getCoordinate());
if (coordinates.size() == 0) {
coincideModelResultsType.put("0", modelResultList);
} else {
coincideModelResultsType = getCoincideModelResultsType(modelResultList, pcMonitoringDeviceModel);
}
logger.error("---------------coincideModelResultsType============{}----------------------", gson.toJson(coincideModelResultsType));
boolean flag = false;
String departure_model_type = configService.selectConfigByKey(URLConstant.DEPARTURE_MODEL_TYPE);
if (CollectionUtil.isNotEmpty(coincideModelResultsType)) {
if (Objects.equals(departure_model_type, "0")) {
flag = coincideModelResultsType.entrySet().stream().allMatch(l -> l.getValue().size() >= Integer.parseInt(pcMonitoringDeviceModel.getNumber()));
logger.error("---------------coincideModelResultsType.entrySet().stream().allMatch(l -> l.getValue().size()============{}------pcMonitoringDeviceModel.getNumber()==================={}----------------{}", gson.toJson(coincideModelResultsType), Integer.parseInt(pcMonitoringDeviceModel.getNumber()), flag);
} else if (Objects.equals(departure_model_type, "1")) {
flag = coincideModelResultsType.entrySet().stream().anyMatch(l -> l.getValue().size() >= Integer.parseInt(pcMonitoringDeviceModel.getNumber()));
logger.error("---------------coincideModelResultsType.entrySet().stream().anyMatch(l -> l.getValue().size()============{}------pcMonitoringDeviceModel.getNumber()==================={}----------------{}", gson.toJson(coincideModelResultsType), Integer.parseInt(pcMonitoringDeviceModel.getNumber()), flag);
} else if (Objects.equals(departure_model_type, "2")) {
flag = coincideModelResultsType.values().stream().mapToInt(List::size).sum() >= Integer.parseInt(pcMonitoringDeviceModel.getNumber());
logger.error("---------------coincideModelResultsType.values().stream().mapToInt(List::size).sum()============{}------pcMonitoringDeviceModel.getNumber()==================={}----------------{}", coincideModelResultsType.values().stream().mapToInt(List::size).sum(), Integer.parseInt(pcMonitoringDeviceModel.getNumber()), flag);
}
}
isAlarm = !flag;
} else {
isAlarm = true;
}
locations = new ArrayList<>();
logger.info("-----------------------end-------------------");
}
checkResultAlarmRule.setAlarm(isAlarm);
checkResultAlarmRule.setLocations(locations);
checkResultAlarmRule.setModelResults(coincideModelResults);
return checkResultAlarmRule;
}
/**
* 获取模型识别结果与通道框选区域重合的识别结果列表
*
* @param modelResults
* @param monitoringDeviceModel
* @return
*/
private List<ModelResult> getCoincideModelResults(List<ModelResult> modelResults, PcMonitoringDeviceModel monitoringDeviceModel) {
List<ModelResult> coincideModelResults = new ArrayList<ModelResult>();
// 1、判断是否标记了识别范围,若是,筛选识别结果和通道框选区域重合的识别结果数据集,若不是,识别所有
// 2、获取识别区域框选范围坐标集合
// coordinates: [{"oX":151,"oY":108},{"oX":417,"oY":130},{"oX":376,"oY":236},{"oX":196,"oY":294},{"oX":135,"oY":195}]
JSONArray coordinates = JSONArray.fromObject(monitoringDeviceModel.getCoordinate());
// logger.info("识别区域框选范围"+coordinates.toString());
if (coordinates.size() > 0) {
List<PolygonUtil.Polygon> polygonList = new ArrayList<>();
for (Object coordinateArrays : coordinates) {
JSONArray coordinateList = JSONArray.fromObject(coordinateArrays);
if (coordinateList.size() > 0) {
ArrayList<PolygonUtil.Point> coordinatePoints = new ArrayList<PolygonUtil.Point>();
for (int i = 0; i < coordinateList.size(); i++) {
Coordinate coordinate = gson.fromJson(coordinateList.get(i).toString(), Coordinate.class);
coordinatePoints.add(new PolygonUtil.Point(coordinate.getoX(), coordinate.getoY()));
}
PolygonUtil.Polygon coordinatePolygon = new PolygonUtil.Polygon().setPoints(coordinatePoints);
polygonList.add(coordinatePolygon);
}
}
// 3、 遍历识别结果集合,判断识别结果是否和通道框选区域重合,若是,添加jsonArray中
// array: [{ "category": "smoke", "bbox": [182.2, 218.1, 211.2, 278.4],"score": 0.7568120956420898 },{ "category": "smoke", "bbox": [182.0, 218.0, 211.0, 278.0],"score": 0.7568120956420898 }]
for (ModelResult modelResult : modelResults) {
List<Double> bbox = modelResult.getBbox(); // 获取框图位置信息
PolygonUtil.Polygon locationPolygon = new PolygonUtil.Polygon().setPoints(Arrays.asList(
new PolygonUtil.Point(bbox.get(0), bbox.get(1)),
new PolygonUtil.Point(bbox.get(2), bbox.get(1)),
new PolygonUtil.Point(bbox.get(2), bbox.get(3)),
new PolygonUtil.Point(bbox.get(0), bbox.get(3))
));
//判断多边形是否相交
for (PolygonUtil.Polygon polygonTest : polygonList) {
//判断多边形是否相交
// boolean coinCide = PolygonUtil.intersectionJudgment(locationPolygon, polygonTest);
String area = getAreaProportion(locationPolygon, polygonTest);
// String area = "";
logger.info("框图坐标->{},识别结果坐标->{},面积占比大小:{}", gson.toJson(polygonTest), gson.toJson(locationPolygon), area);
//判断设置是在框外还是框内 : 0:框内,1:框外
if (monitoringDeviceModel.getBoxStatus() == null || monitoringDeviceModel.getBoxStatus() == 0) {
//判断当前面积是否大于设置阈值
if (Double.parseDouble(area) > 0 && new BigDecimal(area).compareTo(new BigDecimal(StringUtils.isEmpty(monitoringDeviceModel.getAreaThreshold()) ? "0" : monitoringDeviceModel.getAreaThreshold())) >= 0) {
coincideModelResults.add(modelResult);
break;
}
} else {
if (new BigDecimal(area).compareTo(new BigDecimal(StringUtils.isEmpty(monitoringDeviceModel.getAreaThreshold()) ? "0" : monitoringDeviceModel.getAreaThreshold())) < 0) {
coincideModelResults.add(modelResult);
break;
}
}
}
}
} else {
coincideModelResults.addAll(modelResults);
}
return coincideModelResults;
}
@SuppressWarnings("all")
private Map<String, List<ModelResult>> getCoincideModelResultsType(List<ModelResult> modelResults, PcMonitoringDeviceModel monitoringDeviceModel) {
Map<String, List<ModelResult>> coincideModelResults = new HashMap<>();
// 1、判断是否标记了识别范围,若是,筛选识别结果和通道框选区域重合的识别结果数据集,若不是,识别所有
// 2、获取识别区域框选范围坐标集合
// coordinates: [[{"oX":151,"oY":108},{"oX":417,"oY":130},{"oX":376,"oY":236},{"oX":196,"oY":294},{"oX":135,"oY":195}],[{"oX":151,"oY":108},{"oX":417,"oY":130},{"oX":376,"oY":236},{"oX":196,"oY":294},{"oX":135,"oY":195}]]
JSONArray coordinates = JSONArray.fromObject(monitoringDeviceModel.getCoordinate());
List<PolygonUtil.Polygon> polygonList = new ArrayList<>();
for (Object coordinateArrays : coordinates) {
JSONArray coordinateList = JSONArray.fromObject(coordinateArrays);
if (coordinateList.size() > 0) {
ArrayList<PolygonUtil.Point> coordinatePoints = new ArrayList<PolygonUtil.Point>();
for (Object o : coordinateList) {
Coordinate coordinate = gson.fromJson(o.toString(), Coordinate.class);
coordinatePoints.add(new PolygonUtil.Point(coordinate.getoX(), coordinate.getoY()));
}
PolygonUtil.Polygon coordinatePolygon = new PolygonUtil.Polygon().setPoints(coordinatePoints);
polygonList.add(coordinatePolygon);
}
}
logger.info("----------------------start------------------+++++++++++++++++++++++++++++++++++++");
for (ModelResult modelResult : modelResults) {
List<Double> bbox = modelResult.getBbox(); // 获取框图位置信息
PolygonUtil.Polygon locationPolygon = new PolygonUtil.Polygon().setPoints(Arrays.asList(
new PolygonUtil.Point(bbox.get(0), bbox.get(1)),
new PolygonUtil.Point(bbox.get(2), bbox.get(1)),
new PolygonUtil.Point(bbox.get(2), bbox.get(3)),
new PolygonUtil.Point(bbox.get(0), bbox.get(3))
));
//判断多边形是否相交
logger.info("-------polygonList.size()------{}------------", polygonList.size());
for (int i = 0; i < polygonList.size(); i++) {
List<ModelResult> modelResultList = coincideModelResults.get(i + "");
if (CollectionUtil.isEmpty(modelResultList))
modelResultList = new ArrayList<>();
//判断多边形是否相交
String area = getAreaProportion(locationPolygon, polygonList.get(i));
logger.info("************{}**********area-----{}*****", i, area);
//判断设置是在框外还是框内 : 0:框内,1:框外
if (monitoringDeviceModel.getBoxStatus() == null || monitoringDeviceModel.getBoxStatus() == 0) {
//判断当前面积是否大于设置阈值
if (Double.parseDouble(area) > 0 && new BigDecimal(area).compareTo(new BigDecimal(StringUtils.isEmpty(monitoringDeviceModel.getAreaThreshold()) ? "0" : monitoringDeviceModel.getAreaThreshold())) >= 0) {
logger.error("面积占比大小{}>面积占比阈值{}", area, monitoringDeviceModel.getAreaThreshold());
modelResultList.add(modelResult);
logger.info("----------modelResult---------{}", gson.toJson(modelResult));
}
coincideModelResults.put(i + "", modelResultList);
} else {
if (new BigDecimal(area).compareTo(new BigDecimal(StringUtils.isEmpty(monitoringDeviceModel.getAreaThreshold()) ? "0" : monitoringDeviceModel.getAreaThreshold())) <= 0) {
modelResultList.add(modelResult);
}
coincideModelResults.put(i + "", modelResultList);
}
}
}
logger.info("----------------------end------------------+++++++++++++++++++++++++++++++++++++");
return coincideModelResults;
}
public static String getAreaProportion(PolygonUtil.Polygon locationPolygon, PolygonUtil.Polygon polygonTest) {
//框图坐标
List<PolygonUtil.Point> polygonTestPoints = polygonTest.getPoints();
//结果坐标
List<PolygonUtil.Point> locationPolygonPoints = locationPolygon.getPoints();
// 创建第一个多边形
GeometryFactory factory = new GeometryFactory();
com.vividsolutions.jts.geom.Coordinate[] coords1 = new com.vividsolutions.jts.geom.Coordinate[polygonTestPoints.size() + 1];
for (int i = 0; i < polygonTestPoints.size(); i++) {
coords1[i] = new com.vividsolutions.jts.geom.Coordinate(polygonTestPoints.get(i).getX(), polygonTestPoints.get(i).getY(), 0.0);
if (polygonTestPoints.size() - 1 == i) {
coords1[i + 1] = new com.vividsolutions.jts.geom.Coordinate(polygonTestPoints.get(0).getX(), polygonTestPoints.get(0).getY(), 0.0);
}
}
com.vividsolutions.jts.geom.Polygon polygon1 = factory.createPolygon(coords1);
com.vividsolutions.jts.geom.Coordinate[] coords2 = new com.vividsolutions.jts.geom.Coordinate[locationPolygonPoints.size() + 1];
for (int i = 0; i < locationPolygonPoints.size(); i++) {
coords2[i] = new com.vividsolutions.jts.geom.Coordinate(locationPolygonPoints.get(i).getX(), locationPolygonPoints.get(i).getY(), 0.0);
if (locationPolygonPoints.size() - 1 == i) {
coords2[i + 1] = new com.vividsolutions.jts.geom.Coordinate(locationPolygonPoints.get(0).getX(), locationPolygonPoints.get(0).getY(), 0.0);
}
}
com.vividsolutions.jts.geom.Polygon polygon2 = factory.createPolygon(coords2);
// 对第一个多边形进行自交处理
Geometry polygon1Buffer = polygon1.buffer(0.01);
Geometry polygon1BufferUnion = polygon1Buffer.union();
// 计算两个多边形的相交面积
Geometry intersection = polygon2.intersection(polygon1BufferUnion);
// 计算相交面积占polygon1面积的百分比
double percentage = intersection.getArea() / polygon2.getArea() * 100;
return new Gson().toJson(percentage);
}
/**
* 格式化模型识别结果列表为框图Location列表
*
* @param coincideModelResults
*/
private ArrayList<Location> getLocations(List<ModelResult> coincideModelResults) {
ArrayList<Location> locations = new ArrayList<>();
for (ModelResult modelResult : coincideModelResults) {
Location location = new Location();
List<Double> bbox = modelResult.getBbox();
location.setX(bbox.get(0).intValue());
location.setY(bbox.get(1).intValue());
Double width = bbox.get(2) - bbox.get(0);
location.setWidth(width.intValue());
Double height = bbox.get(3) - bbox.get(1);
location.setHeight(height.intValue());
locations.add(location);
}
return locations;
}
/**
* 判断是否有聚集
* K-Means算法计算聚集情况,true 聚集 false 没有聚集
*
* @param monitoringDeviceModel
* @param locations
* @return
*/
private boolean isGather(PcMonitoringDeviceModel monitoringDeviceModel, ArrayList<Location> locations) {
boolean isGather = true; //是否可以直接保存告警结果,默认可以直接告警
String model_id_gather = configService.selectConfigByKey(URLConstant.MODEL_ID_GATHER); // 进行聚集算法判断的模型ID
if (null != model_id_gather && model_id_gather.trim().length() > 0 && !model_id_gather.equals("model_id_gather")) {
//若需要聚集算法判断的模型名称中包含当前模型名称
boolean flag = false; // 默认当前模型不是聚集算法
String[] split = model_id_gather.split(",");
for (int i = 0; i < split.length; i++) {
if (Long.parseLong(split[i]) == monitoringDeviceModel.getAiModelId()) {
flag = true; // 是聚集算法
break;
}
}
//当前是聚集算法
if (flag) {
//获取矩形框的中心点数组
ArrayList<CentralPoint> centralPoints = RectangleUtil.calculateCentralPoint(locations);
// 将中心点坐标用double数组存储,方便聚类计算使用
ArrayList<double[]> dataSet = new ArrayList<>();
for (CentralPoint centralPoint : centralPoints) {
double[] onePoint = new double[2];
onePoint[0] = centralPoint.getX();
onePoint[1] = centralPoint.getY();
dataSet.add(onePoint);
}
//K-Means算法计算聚集情况 true 聚集 false 没有聚集
isGather = ClusteringUtils.kMeansGather(dataSet, Integer.parseInt(monitoringDeviceModel.getNumber()));
}
}
return isGather;
}
/**
* 判断当前通道是否可以告警
*
* @param createDate
* @param taskId
* @param locations
* @param imgPath
* @param pcMonitoringDeviceModel
* @return
*/
private TimeThresholdInfo isTimeThreshold(String createDate, Long taskId, ArrayList<Location> locations, String imgPath, PcMonitoringDeviceModel pcMonitoringDeviceModel, List<ModelResult> modelResults) {
TimeThresholdInfo timeThresholdInfo = null;
String timeThreshold = pcMonitoringDeviceModel.getTimeThreshold();
Integer monitoringStatus = pcMonitoringDeviceModel.getMonitoringStatus();
if ((monitoringStatus == null || monitoringStatus == 0) && null != timeThreshold && timeThreshold.trim().length() != 0 && !timeThreshold.equals("0")) {
//若不为空且不等于0
//判断redis中当前通道、当前模型是否存在监测时长相关信息,若不存在,保存第一次监测的信息,监测信息包括,第一次记录时间,当前记录次数,报警信息
String keyTimeThreshold = pcMonitoringDeviceModel.getMonitoringDeviceId() + "_" + pcMonitoringDeviceModel.getAiModelId() + "_" + pcMonitoringDeviceModel.getClassName() + "_" + pcMonitoringDeviceModel.getLabel() + "_time_threshold";
if (!redisUtil.hasKey(keyTimeThreshold)) {
// 若不存在,保存第一次监测的信息
//第一次 number默认为1
timeThresholdInfo = new TimeThresholdInfo(createDate, 1, locations, imgPath, modelResults);
redisUtil.set(keyTimeThreshold, gson.toJson(timeThresholdInfo));
logger.info("第一次监测信息键值:" + keyTimeThreshold);
timeThresholdInfo.setFlag(false);
} else {
// 若存在,获取上一次监控信息
timeThresholdInfo = gson.fromJson(String.valueOf(redisUtil.get(keyTimeThreshold)), TimeThresholdInfo.class);
timeThresholdInfo.setNumber(timeThresholdInfo.getNumber() + 1);
logger.info("第" + (timeThresholdInfo.getNumber() + 1) + "次监测信息键值:" + keyTimeThreshold);
List<ModelResult> results = timeThresholdInfo.getModelResults();
// 大于等于阈值时,比较获取最大得分的监控信息
if (pcMonitoringDeviceModel.getType().equals(URLConstant.MODEL_TYPE_0)) {
// logger.info("大于等于阈值时,本次监测覆盖时间---------"+createDate);
//获取本次得分的最大值
double maxLocal = 0.0;
for (ModelResult result : modelResults) {
maxLocal = (result.getScore() >= maxLocal) ? result.getScore() : maxLocal;
}
// logger.info("获取本次得分的最大值---------"+maxLocal);
//获取上次得分的最大值
double maxLast = 0.0;
for (ModelResult result : results) {
maxLast = (result.getScore() >= maxLast) ? result.getScore() : maxLast;
}
// logger.info("获取上次得分的最大值---------"+maxLast);
//若本次得分大于等于上次得分
if (maxLocal >= maxLast) {
// logger.info("本次监测覆盖时间---------"+createDate);
timeThresholdInfo.setLocations(locations);
timeThresholdInfo.setImgPath(imgPath);
timeThresholdInfo.setModelResults(modelResults);
}
//
}
// 大于零且小于等于阈值,比较获取最大得分的监控信息
if (pcMonitoringDeviceModel.getType().equals(URLConstant.MODEL_TYPE_1)) {
// logger.info("大于零且小于等于阈值时,本次监测覆盖时间---------"+createDate);
//获取本次得分的最大值
double maxLocal = 0.0;
for (ModelResult result : modelResults) {
maxLocal = (result.getScore() >= maxLocal) ? result.getScore() : maxLocal;
}
// logger.info("获取本次得分的最大值---------"+maxLocal);
//获取上次得分的最大值
double maxLast = 0.0;
for (ModelResult result : results) {
maxLast = (result.getScore() >= maxLast) ? result.getScore() : maxLast;
}
// logger.info("获取上次得分的最大值---------"+maxLast);
//若本次得分大于等于上次得分
if (maxLocal >= maxLast) {
timeThresholdInfo.setLocations(locations);
timeThresholdInfo.setImgPath(imgPath);
timeThresholdInfo.setModelResults(modelResults);
}
}
//小于等于阈值(包含识别没有结果),比较获取最小得分的监控信息
if (pcMonitoringDeviceModel.getType().equals(URLConstant.MODEL_TYPE_2)) {
// logger.info("小于等于阈值(包含识别没有结果)时,本次监测覆盖时间---------"+createDate);
// 获取本次得分的最小值
double minLocal = 0.0;
for (ModelResult result : modelResults) {
minLocal = (result.getScore() <= minLocal) ? result.getScore() : minLocal;
}
// logger.info("获取本次得分的最小值---------"+minLocal);
// 获取上次得分的最小值
double minLast = 0.0;
for (ModelResult result : results) {
minLast = (result.getScore() <= minLast) ? result.getScore() : minLast;
}
// logger.info("获取上次得分的最小值---------"+minLast);
//若本次得分小于等于上次得分
if (minLocal <= minLast) {
timeThresholdInfo.setLocations(locations);
timeThresholdInfo.setImgPath(imgPath);
timeThresholdInfo.setModelResults(modelResults);
}
}
// 本次监测时间和第一次监控时间之差是否大于等于监测时长 若大于等于返回true 不大于返回false
boolean b = DayUtils.compareTimeMinute(timeThresholdInfo.getFirstTime(), createDate, Integer.valueOf(timeThreshold));
if (b) {
logger.info("超过监测时间---------" + timeThreshold);
// 本次监测时间和第一次监控时间之差大于等于监测时长
// 获取当前任务的轮询时间
// PcMonitoringTask pcMonitoringTask = taskService.selectPcMonitoringTaskById(taskId);
String timeThresholdProportion = pcMonitoringDeviceModel.getTimeThresholdProportion(); // 监测事件次数
// logger.info("当前比例为---------"+time_threshold_proportion);
// if ((timeThresholdInfo.getNumber() + 1) >= ((Integer.valueOf(timeThreshold) * 60 / pcMonitoringTask.getTimeInterval()) * Double.valueOf(timeThresholdProportion))) {
if ((timeThresholdInfo.getNumber() + 1) >= Integer.parseInt(timeThresholdProportion)) {
// 若当前时间大于等于第一次报警后的2倍监测时长后,就不报警
if (DayUtils.compareTimeMinute(timeThresholdInfo.getFirstTime(), createDate, Integer.valueOf(timeThreshold) * 2)) {
timeThresholdInfo.setFlag(false);
} else {
timeThresholdInfo.setFlag(true);
}
} else {
//若不大于
timeThresholdInfo.setFlag(false);
}
//清除当前redis信息
redisUtil.del(keyTimeThreshold);
} else {
logger.info("未超过监测时间---------" + timeThreshold);
// 本次监测时间和第一次监控时间之差小于监测时长,记录当前最好的监控信息,跳出执行
redisUtil.set(keyTimeThreshold, gson.toJson(timeThresholdInfo));
timeThresholdInfo.setFlag(false);
}
}
} else {
timeThresholdInfo = new TimeThresholdInfo();
timeThresholdInfo.setFlag(true);
timeThresholdInfo.setImgPath(imgPath);
timeThresholdInfo.setLocations(locations);
timeThresholdInfo.setModelResults(modelResults);
}
return timeThresholdInfo;
}
/**
* 根据坐标截图保存
*
* @param locations 坐标地址数组
* @param imgPath 原图地址
* @param imei 通道号
* @param monitoringDeviceModel 模型
* @return 返回框图保存的地址
*/
public String transformImg(ArrayList<Location> locations, String imgPath, String imei, PcMonitoringDeviceModel monitoringDeviceModel, List<String> markContents) {
String frameImgPath = imei + "/" + "frameImg" + "/" + DayUtils.getToday() + File.separator + DayUtils.getBeforeByHourTime(0);
//新建文件夹
FileUtil.createFile(RuoYiConfig.getFfmpefPath() + "/" + frameImgPath);
FileUtil.createFile(RuoYiConfig.getOriginalFfmpefPath() + "/" + frameImgPath);
String frameImgName = DayUtils.getToday() + "_" + DayUtils.getTodayTime() + "_" + UUID.randomUUID() + "_" + monitoringDeviceModel.getClassName() + "_" + monitoringDeviceModel.getClassName() + ".jpg"; //随机数图片名称
String frameOriginalImgPath = RuoYiConfig.getOriginalFfmpefPath() + "/" + frameImgPath + "/" + frameImgName;
frameImgPath = RuoYiConfig.getFfmpefPath() + "/" + frameImgPath + "/" + frameImgName;
//保存原图
try {
FileUtil.copy(imgPath, frameOriginalImgPath);
} catch (IOException e) {
e.printStackTrace();
logger.error("原图复制失败!-----{}", e.getMessage());
}
Graphics g = null;
FileOutputStream out = null;
try {
BufferedImage image = ImageIO.read(new File(imgPath));
g = image.getGraphics();
BasicStroke stokeLine = new BasicStroke(2.0f);
Graphics2D g2 = (Graphics2D) g;
g2.setStroke(stokeLine);
g.setColor(Color.RED);//画笔颜色
if (locations.size() > 0) {
for (Location location : locations) {
//矩形框(原点x坐标,原点y坐标,矩形的长,矩形的宽)
g.drawRect(location.getX(), location.getY(), location.getWidth(), location.getHeight());
}
}
// coordinates: [[{"oX":151,"oY":108},{"oX":417,"oY":130},{"oX":376,"oY":236},{"oX":196,"oY":294},{"oX":135,"oY":195}]]
JSONArray coordinates = JSONArray.fromObject(monitoringDeviceModel.getCoordinate());
if (coordinates.size() > 0) {
Gson gson = new Gson();
for (Object coordinateArrays : coordinates) {
JSONArray coordinateList = JSONArray.fromObject(coordinateArrays);
if (coordinateList.size() > 0) {
Polygon polygon = new Polygon();
for (int i = 0; i < coordinateList.size(); i++) {
Coordinate coordinate = gson.fromJson(coordinateList.get(i).toString(), Coordinate.class);
polygon.addPoint(coordinate.getoX(), coordinate.getoY());
}
//画多边形
g.setColor(Color.BLUE);//画笔颜色
g.drawPolygon(polygon);
}
}
}
//生成水印
int srcImgWidth = image.getWidth(null);
int srcImgHeight = image.getHeight(null);
// 加水印
// g.drawImage(image, 0, 0, srcImgWidth, srcImgHeight, null);
// Font font = new Font("Courier New", Font.PLAIN, 12);
Font font = new Font("宋体", Font.PLAIN, srcImgWidth / 300 * 8);
g.setColor(new Color(30, 144, 255)); // 根据图片的背景设置水印颜色
g.setFont(font);
for (int i = 0; i < markContents.size(); i++) {
int x = 10;
int y = srcImgHeight - srcImgHeight / 5 + srcImgWidth / 300 * 8 * i + 10;
g.drawString(markContents.get(i), x, y);
}
out = new FileOutputStream(frameImgPath);//输出图片的地址
ImageIO.write(image, "jpeg", out);
out.flush();
} catch (IOException e) {
logger.error("根据坐标截图保存失败" + e);
return null;
} finally {
g.dispose();
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
logger.error("输出流关闭失败");
}
}
return frameImgPath;
}
/**
* 保存告警信息
*
* @param createDate 创建时间
* @param modelResults 模型调用返回结果
* @param frameImgPath 框图保存地址
* @param pcMonitoringDevice 通道信息
* @param monitoringDeviceModel 模型信息
*/
public void saveMonitoringDeviceResult(String createDate, List<ModelResult> modelResults, String frameImgPath, PcMonitoringDevice pcMonitoringDevice, PcMonitoringDeviceModel monitoringDeviceModel) {
PcMonitoringDeviceResult monitoringDeviceResult = new PcMonitoringDeviceResult();
monitoringDeviceResult.setDelFlag(URLConstant.DELFLAG_0); // 未删除标志
monitoringDeviceResult.setCreateId(pcMonitoringDevice.getCreateId()); // 创建人
monitoringDeviceResult.setCreateDate(createDate); // 创建时间
monitoringDeviceResult.setDeptId(pcMonitoringDevice.getDeptId()); // 创建部门ID
monitoringDeviceResult.setMonitoringDeviceId(monitoringDeviceModel.getMonitoringDeviceId()); // 监控通道ID
monitoringDeviceResult.setAiModelId(monitoringDeviceModel.getAiModelId()); // ai模型ID
monitoringDeviceResult.setSimilarity(monitoringDeviceModel.getSimilarity()); // ai模型相似度
monitoringDeviceResult.setImgUrl(Constants.RESOURCE_PREFIX + frameImgPath.replace(RuoYiConfig.getProfile(), "")); // 截取并拼接保存图片URL访问地址
monitoringDeviceResult.setResult(modelResults.toString()); //接口调用识别结果详情
monitoringDeviceResult.setAlarmEvent(0L);//设置事件类型
monitoringDeviceResult.setSynStatus(5);
int i = iPcMonitoringDeviceResultService.insertPcMonitoringDeviceResult(monitoringDeviceResult);
if (i > 0) {
PcDataReportConfig pcDataReportConfig = pcDataReportConfigService.selectPcDataReportConfigById(1L);
//数据上报顶层平台
if (iPcMonitoringDeviceResultService.synDataReport(monitoringDeviceResult.getId(), "add", pcDataReportConfig)) {
logger.info("告警信息(id->{})信息上报成功!", monitoringDeviceResult.getId());
} else {
logger.info("告警信息(id->{})信息上报失败!", monitoringDeviceResult.getId());
}
}
//判断当前通道、当前模型是否允许告警推送
boolean isTimeInterval = isTimeInterval(createDate, monitoringDeviceModel);
if (isTimeInterval) {
pool.execute(() -> {
//通道告警通知 短信、钉钉、企业微信、邮箱、第三方接口
pcAlarmConfigService.sendMonitoringMsg(frameImgPath, monitoringDeviceResult);
});
}
publishAlarmInformation(monitoringDeviceResult, pcMonitoringDevice.getDeptName(), monitoringDeviceModel.getAiModelName(), pcMonitoringDevice.getName());
}
@SuppressWarnings("all")
public void publishAlarmInformation(PcMonitoringDeviceResult monitoringDeviceResult, String deptName, String aiModelName, String monitoringDeviceName) {
String screen_url = configService.selectConfigByKey(URLConstant.SCREEN_URL);
if (null == screen_url || screen_url.trim().length() < 1 || screen_url.equals("screen_url"))
return;
//判断连接状态用户是否为null
ConcurrentHashMap<String, ConcurrentHashMap<String, ConcurrentHashMap<String, WebSocketServer>>> webSocketSet = webSocketServer.webSocketSet;
if (CollectionUtil.isEmpty(webSocketSet))
return;
//获取该部门及其父部门id
List<Long> parentDeptIdList = sysDeptService.getParentDeptIdList(monitoringDeviceResult.getDeptId());
ConcurrentHashMap<String, ConcurrentHashMap<String, WebSocketServer>> apiScreen = webSocketSet.get("screenAlarm");
if (CollectionUtil.isNotEmpty(apiScreen)) {
//判断推送视频流
//判断当前部门下的用户及其父部门
Map<String, ConcurrentHashMap<String, WebSocketServer>> sendUserMap = apiScreen.entrySet().stream().filter(l -> parentDeptIdList.contains(userService.selectUserById(Long.valueOf(l.getKey())).getDeptId())).collect(Collectors.toMap(l -> l.getKey(), k -> k.getValue(), (oldValue, newValue) -> oldValue));
sendUserMap.entrySet().stream().forEach(entry -> {
try {
//创建发布实体类
String is_or_not_important_alarm = configService.selectConfigByKey(URLConstant.IS_OR_NOT_IMPORTANT_ALARM);
List<String> isOrNotImportantAlarm = StringUtils.isNotBlank(is_or_not_important_alarm) ? Arrays.asList(is_or_not_important_alarm.split(",")) : null;
Map<String, Object> hashMap = new HashMap<>();
hashMap.put("id", monitoringDeviceResult.getId());
hashMap.put("createDate", monitoringDeviceResult.getCreateDate());
hashMap.put("deptName", deptName);
hashMap.put("aiModelName", monitoringDeviceResult.getAiModelName());
hashMap.put("alarmEvent", monitoringDeviceResult.getAlarmEvent());
hashMap.put("imgUrl", screen_url + monitoringDeviceResult.getImgUrl());
hashMap.put("monitoringDeviceName", monitoringDeviceResult.getMonitoringDeviceName());
hashMap.put("importantAlarm", !Optional.ofNullable(isOrNotImportantAlarm).isPresent() ? false : isOrNotImportantAlarm.contains(String.valueOf(monitoringDeviceResult.getAiModelId())));
entry.getValue().entrySet().stream().forEach(entry_1 -> publishAlarmInformation(entry_1.getValue(), gson.toJson(hashMap), "apiScreen", "publishAlarmInformation"));
} catch (Exception e) {
logger.error("推送告警画面失败----->告警信息id{}-------->用户id{}", monitoringDeviceResult.getId(), entry.getKey());
logger.error("推送告警画面失败" + e);
}
});
}
}
@SuppressWarnings("all")
public void publishAlarmInformation(WebSocketServer webSocketServer, String hashMap, String
moduleName, String methodName) {
try {
HashMap<String, Object> map = new HashMap<>();
map.put("code", 200);
map.put("errMessage", "");
map.put("data", hashMap);
Map<String, Object> data = new HashMap<>();
data.put("moduleName", moduleName);
data.put("methodName", methodName);
data.put("params", map);
webSocketServer.sendMessage(gson.toJson(data));
} catch (Exception e) {
e.printStackTrace();
logger.error("Error sending json map!");
}
}
/**
* 判断当前通道、当前模型是否允许告警推送
*
* @param createDate
* @param monitoringDeviceModel
* @return
*/
private boolean isTimeInterval(String createDate, PcMonitoringDeviceModel monitoringDeviceModel) {
boolean isTimeInterval = false;
if (monitoringDeviceModel.getAlarmStatus().equals(URLConstant.PC_MODEL_ALARM_ON)) {
// 若允许推送,判断告警推送间隔时间是否等于0
String timeInterval = monitoringDeviceModel.getTimeInterval();
if (timeInterval.equals("0")) {
isTimeInterval = true;
} else {
//若不等于0,查询当前通道当前模型上一次告警推送时间(从redis中取)
String key_time_interval = monitoringDeviceModel.getMonitoringDeviceId() + "_" + monitoringDeviceModel.getAiModelId() + "_" + monitoringDeviceModel.getClassName() + "_" + monitoringDeviceModel.getLabel() + "_time_interval";
if (!redisUtil.hasKey(key_time_interval)) {
// 若不存在,立即推送,并记录当前创建时间到redis
logger.info("第一次告警推送时间:" + key_time_interval);
redisUtil.set(key_time_interval, createDate);
isTimeInterval = true;
} else {
// 若存在,比较上一次告警推送时间和创建时间
//获取上一次告警推送时间
String redisTime = String.valueOf(redisUtil.get(key_time_interval));
// 创建时间和上一次告警推送时间之差大于等于告警间隔时间 若大于等于返回true 不大于返回false
boolean b = DayUtils.compareTimeMinute(redisTime, createDate, Integer.valueOf(timeInterval));
if (b) {
// 若创建时间和上一次告警时间之差大于等于告警间隔时间,立即推送 true
redisUtil.set(key_time_interval, createDate);
isTimeInterval = true;
} else {
// 若创建时间和上一次告警时间之差小于告警间隔时间,跳过推送 false
isTimeInterval = false;
}
}
}
}
return isTimeInterval;
}
}
CheckResultAlarmRule
package com.ruoyi.pc.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.domain.BaseEntity;
import com.ruoyi.pc.task.util.Location;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* 监控通道对象 pc_monitoring_device
*
* @author sc
* @date 2021-03-09
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class CheckResultAlarmRule extends BaseEntity {
private boolean alarm;
private ArrayList<Location> locations;
private List<ModelResult> modelResults;
}
public class PcVideoServiceImpl implements IPcVideoService
package com.ruoyi.pc.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.pc.config.redis.RedisUtil;
import com.ruoyi.pc.domain.*;
import com.ruoyi.pc.mapper.PcMonitoringDeviceMapper;
import com.ruoyi.pc.mapper.PcMonitoringTaskDeviceMapper;
import com.ruoyi.pc.mapper.PcMonitoringTaskMapper;
import com.ruoyi.pc.service.*;
import com.ruoyi.pc.task.VideoStreamTask;
import com.ruoyi.pc.util.*;
import com.ruoyi.quartz.service.ISysJobService;
import com.ruoyi.system.service.ISysConfigService;
import lombok.extern.log4j.Log4j2;
import net.sf.json.JSONArray;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.*;
import java.util.concurrent.CountDownLatch;
@Service
@Log4j2
public class PcVideoServiceImpl implements IPcVideoService {
public static Logger logger = LoggerFactory.getLogger(VideoStreamTask.class);
Gson gson = new Gson();
@Value("${server.port}")
private int serverPort;
@Resource
ThreadPoolTaskExecutor pool;
@Autowired
IPcMonitoringTaskService pcMonitoringTaskService;
@Autowired
ISysConfigService configService;
@Autowired
private IPcMonitoringDeviceService pcMonitoringDeviceService;
@Autowired
FasterRcnnHttpService httpService;
@Autowired
IPcMonitoringDeviceModelService iPcMonitoringDeviceModelService;
@Autowired
RedisUtil redisUtil;
@Autowired
IPcMonitoringTaskDeviceService iPcMonitoringTaskDeviceService;
@Autowired
private ISysJobService sysJobService;
@Resource
private PcMonitoringTaskDeviceMapper pcMonitoringTaskDeviceMapper;
@Resource
private PcMonitoringDeviceMapper pcMonitoringDeviceMapper;
@Resource
private PcMonitoringTaskMapper pcMonitoringTaskMapper;
@Resource
AiTaskService aiTaskService;
@Resource
TaskService taskService;
@Override
public synchronized void startVideoStreamByTaskId(Long taskId, boolean initialStatus, boolean isOrNotUpdateVideoStreamTaskStatus) {
//获取当前监控任务
PcMonitoringTask pcMonitoringTask = pcMonitoringTaskMapper.selectPcMonitorDeviceTaskByTaskId(taskId);
//查询监控任务下开启的监控通道
List<PcMonitoringDevice> monitoringDeviceIdList = pcMonitoringTaskDeviceMapper.selectPcMonitorDeviceByTaskId(taskId);
if (null != pcMonitoringTask && null != monitoringDeviceIdList && monitoringDeviceIdList.size() > 0) {
CountDownLatch countDownLatch = new CountDownLatch(monitoringDeviceIdList.size());
// 更新监控任务状态
PcMonitoringTask pcMonitoringTaskStatus = new PcMonitoringTask();
pcMonitoringTaskStatus.setId(taskId);
pcMonitoringTaskStatus.setStatus(URLConstant.PC_TASK_STATUS_CARRY_OUT);
pcMonitoringTaskMapper.updatePcMonitoringTask(pcMonitoringTaskStatus);
redisUtil.hset("taskThreadPoolExecutor", taskId + "", 0, 300);
for (PcMonitoringDevice pcMonitoringDevice : monitoringDeviceIdList) {
taskService.taskAsync(pcMonitoringTask, taskId, pcMonitoringDevice, countDownLatch, initialStatus, isOrNotUpdateVideoStreamTaskStatus);
}
}
}
@Override
public synchronized void startVideoStreamByMonitorDeviceId(Long taskId, Long monitorDeviceId, boolean initialStatus, boolean isOrNotUpdateVideoStreamTaskStatus) {
//获取当前监控任务
PcMonitoringTask pcMonitoringTask = pcMonitoringTaskMapper.selectPcMonitorDeviceTaskByTaskId(taskId);
PcMonitoringDevice pcMonitoringDevice = pcMonitoringDeviceMapper.selectPcMonitorDevice(monitorDeviceId);
if (null != pcMonitoringTask && null != pcMonitoringDevice) {
CountDownLatch countDownLatch = new CountDownLatch(1);
// 更新监控任务状态
PcMonitoringTask pcMonitoringTaskStatus = new PcMonitoringTask();
pcMonitoringTaskStatus.setId(taskId);
pcMonitoringTaskStatus.setStatus(URLConstant.PC_TASK_STATUS_CARRY_OUT);
pcMonitoringTaskMapper.updatePcMonitoringTask(pcMonitoringTaskStatus);
redisUtil.hset("taskThreadPoolExecutor", taskId + "", 0, 300);
taskService.taskAsync(pcMonitoringTask, taskId, pcMonitoringDevice, countDownLatch, initialStatus, isOrNotUpdateVideoStreamTaskStatus);
}
}
@Override
public synchronized void stopVideoStreamByTaskId(Long taskId, boolean initialStatus, boolean isOrNotUpdateVideoStreamTaskStatus) {
//获取当前监控任务下的监控通道
List<PcMonitoringDevice> monitoringDeviceIdList = pcMonitoringTaskDeviceMapper.selectPcMonitorDeviceByTaskId(taskId);
CountDownLatch countDownLatch = new CountDownLatch(monitoringDeviceIdList.size());
// 更新监控任务状态
PcMonitoringTask pcMonitoringTaskStatus = new PcMonitoringTask();
pcMonitoringTaskStatus.setId(taskId);
pcMonitoringTaskStatus.setStatus(URLConstant.PC_TASK_STATUS_CARRY_OUT);
pcMonitoringTaskMapper.updatePcMonitoringTask(pcMonitoringTaskStatus);
redisUtil.hset("taskThreadPoolExecutor", taskId + "", 1, 300);
for (PcMonitoringDevice pcMonitoringDevice : monitoringDeviceIdList) {
taskService.taskAsync(null, taskId, pcMonitoringDevice, countDownLatch, initialStatus, isOrNotUpdateVideoStreamTaskStatus);
}
}
@Override
public synchronized void stopVideoStreamByMonitorDeviceId(Long taskId, Long monitorDeviceId, boolean initialStatus, boolean isOrNotUpdateVideoStreamTaskStatus) {
PcMonitoringDevice pcMonitoringDevice = pcMonitoringDeviceMapper.selectPcMonitorDevice(monitorDeviceId);
if (pcMonitoringDevice != null) {
CountDownLatch countDownLatch = new CountDownLatch(1);
// 更新监控任务状态
PcMonitoringTask pcMonitoringTaskStatus = new PcMonitoringTask();
pcMonitoringTaskStatus.setId(taskId);
pcMonitoringTaskStatus.setStatus(URLConstant.PC_TASK_STATUS_CARRY_OUT);
pcMonitoringTaskMapper.updatePcMonitoringTask(pcMonitoringTaskStatus);
redisUtil.hset("taskThreadPoolExecutor", taskId + "", 1, 300);
taskService.taskAsync(null, taskId, pcMonitoringDevice, countDownLatch, initialStatus, isOrNotUpdateVideoStreamTaskStatus);
}
}
/**
* 处理视频流回调返回结果
*
* @param videoResult videoResult
*/
@Override
public void videoResult(VideoResult videoResult) {
pool.execute(() -> {
try {
if (videoResult.getMessage() == null || Objects.equals(videoResult.getMessage(), "")) {
String videoId = videoResult.getVideoId();//视频流获取监控通道 通道唯一编码
if (null == videoId || "".equals(videoId) || !redisUtil.hasKey("task_id_" + videoId)) {
logger.error("当前结果taskId未保存到redis里,请查询redis确认task_id_" + videoId + "是否存在");
return;
}
String className = videoResult.getModelName();
if (null == className || "".equals(className)) {
logger.error("当前结果返回的模型标识为空");
return;
}
Long taskId = Long.valueOf(String.valueOf(redisUtil.get("task_id_" + videoId)));//从redis中获取当前通道的任务Id
if (null == taskId) {
logger.error("从redis中获取当前通道的任务Id为空");
return;
}
//查询唯一启用通道
PcMonitoringDevice pcMonitoringDeviceQuery = new PcMonitoringDevice();
pcMonitoringDeviceQuery.setUniqueCode(videoId);
pcMonitoringDeviceQuery.setAppStatus(URLConstant.STATUS_DEVICE_ACTOVATION);
List<PcMonitoringDevice> pcMonitoringDevices = pcMonitoringDeviceService.selectPcMonitoringDeviceList(pcMonitoringDeviceQuery);
if (null == pcMonitoringDevices || pcMonitoringDevices.size() == 0) {
logger.error("当前已启用的监控通道不存在");
return;
}
PcMonitoringDevice pcMonitoringDevice = pcMonitoringDevices.get(0);
//3、根据通道ID,获取关联的模型列表 (模型未删除、已启用、且模型地址不为空、通道相似度不为空的模型列表)
List<PcMonitoringDeviceModel> pcMonitoringDeviceModels = iPcMonitoringDeviceModelService.selectPcAiModelListByMonitoringDeviceId(pcMonitoringDevice.getId());
if (null == pcMonitoringDeviceModels || pcMonitoringDeviceModels.size() == 0) {
logger.error("当前通道关联的模型列表不存在");
return;
}
//4、根据通道信息,截取图片,返回截图地址
String imgPath = videoResult.getImagePath();
//4.1、判断截图地址是否为空
if (null == imgPath) {
logger.error("通道截取图片失败,通道号为---------------" + pcMonitoringDevices.get(0).getImei());
return; // 图片地址为空,跳过当前通道,继续下个通道
}
//4.2、判断截图是否成功
File file = new File(imgPath);
if (file.exists()) {
String createDate = DayUtils.getNow();
//判断当前是否存在识别类别是2的模型
List<ModelResult> result = videoResult.getResult();
// 7、遍历当前通道关联模型列表
String key = "";
for (PcMonitoringDeviceModel pcMonitoringDeviceModel : pcMonitoringDeviceModels) {
boolean isOrNotSaveFlag = false;
if (pcMonitoringDeviceModel.getEnableDeduplication() != null && StringUtils.isNotBlank(pcMonitoringDeviceModel.getEnableDeduplication())
&& pcMonitoringDeviceModel.getDeduplicationMode() != null && StringUtils.isNotBlank(pcMonitoringDeviceModel.getDeduplicationMode())
&& pcMonitoringDeviceModel.getDeduplicationDuration() != null && StringUtils.isNotBlank(pcMonitoringDeviceModel.getDeduplicationDuration())) {
if (Objects.equals(pcMonitoringDeviceModel.getEnableDeduplication(), "0")) {
key = "quantity_detection" + taskId + pcMonitoringDeviceModel.getMonitoringDeviceId() + pcMonitoringDeviceModel.getAiModelId() + pcMonitoringDeviceModel.getId();
} else if (Objects.equals(pcMonitoringDeviceModel.getEnableDeduplication(), "1")) {
key = "coordinate_detection" + taskId + pcMonitoringDeviceModel.getMonitoringDeviceId() + pcMonitoringDeviceModel.getAiModelId() + pcMonitoringDeviceModel.getId();
} else if (Objects.equals(pcMonitoringDeviceModel.getEnableDeduplication(), "2")) {
key = "deduplication_identification" + taskId + pcMonitoringDeviceModel.getMonitoringDeviceId() + pcMonitoringDeviceModel.getAiModelId() + pcMonitoringDeviceModel.getId();
}
}
if (URLConstant.MODEL_TYPE_2.equals(pcMonitoringDeviceModel.getType())) {
String pc_http_url = configService.selectConfigByKey(URLConstant.PC_HTTP_URL);
if (null != pc_http_url && pc_http_url.trim().length() != 0 && !pc_http_url.equals("false")) {
Map<String, Object> stringObjectMap = new HashMap<>();
stringObjectMap.put("taskId", taskId);
stringObjectMap.put("pcMonitoringDeviceModelId", pcMonitoringDeviceModel.getId());
stringObjectMap.put("monitoringDeviceId", pcMonitoringDevice.getId());
stringObjectMap.put("createDate", createDate);
stringObjectMap.put("frontAlgoResult", result);
getModelResultHttp(imgPath, pc_http_url, pcMonitoringDeviceModel.getClassName(), pcMonitoringDeviceModel.getLabel(), stringObjectMap);
continue;
}
}
// 8.2、判断识别结果是否为空
if (null != result && result.size() > 0) {
// 8.3 当模型比较类型是大于等于相似度阈值时
if (pcMonitoringDeviceModel.getType().equals(URLConstant.MODEL_TYPE_0)) {
//8.3.1、筛选大于等于相似度阈值的识别结果
List<ModelResult> modelResults = new ArrayList<ModelResult>(); //筛选后识别结果
for (int i = 0; i < result.size(); i++) {
// 识别结果格式化成ModelResult
ModelResult modelResult = result.get(i);
// 获取结果category等于当前模型label,且大于等于相似度阈值
if (modelResult.getCategory().equals(pcMonitoringDeviceModel.getLabel())
&& Double.valueOf(modelResult.getScore()) >= Double.parseDouble(pcMonitoringDeviceModel.getSimilarity())) {
isOrNotSaveFlag = true;
modelResults.add(modelResult);
}
}
List<ModelResult> personFrontAlgo = getPersonFrontAlgo(createDate, taskId, imgPath, pcMonitoringDeviceModel, modelResults);
// 8.3.2、筛选后识别结果数 大于等于 告警目标数阈值
if (null != personFrontAlgo && personFrontAlgo.size() >= Integer.parseInt(pcMonitoringDeviceModel.getNumber())) {
// 8.3.3、发布到redis通道
publishAiMessage(taskId, personFrontAlgo, createDate, imgPath, pcMonitoringDevices.get(0), pcMonitoringDeviceModel);
logger.info("任务ID--------" + taskId + ",发布时间--------" + createDate + ",通道ID--------" + pcMonitoringDeviceModel.getMonitoringDeviceId() + ",配置模型ID--------" + pcMonitoringDeviceModel.getId() + ",模型标识--------" + pcMonitoringDeviceModel.getClassName() + ",模型标签------" + pcMonitoringDeviceModel.getLabel() + ",模型识别结果--------" + gson.toJson(modelResults));
}
}
// 8.4 当模型比较类型是大于零且小于等于相似度阈值时
if (pcMonitoringDeviceModel.getType().equals(URLConstant.MODEL_TYPE_1)) {
//8.4.1、筛选大于零且小于等于相似度阈值的识别结果
List<ModelResult> modelResults = new ArrayList<ModelResult>(); //筛选后识别结果
for (int i = 0; i < result.size(); i++) {
// 识别结果格式化成ModelResult
ModelResult modelResult = result.get(i);
// 获取结果category等于当前模型label,且大于等于相似度阈值
if (modelResult.getCategory().equals(pcMonitoringDeviceModel.getLabel())
&& Double.valueOf(modelResult.getScore()) > 0
&& Double.valueOf(modelResult.getScore()) <= Double.parseDouble(pcMonitoringDeviceModel.getSimilarity())) {
isOrNotSaveFlag = true;
modelResults.add(modelResult);
}
}
List<ModelResult> personFrontAlgo = getPersonFrontAlgo(createDate, taskId, imgPath, pcMonitoringDeviceModel, modelResults);
// 8.4.2、筛选后识别结果数 大于等于 告警目标数阈值
if (null != personFrontAlgo && personFrontAlgo.size() >= Integer.parseInt(pcMonitoringDeviceModel.getNumber())) {
// 8.4.3、发布到redis通道
publishAiMessage(taskId, personFrontAlgo, createDate, imgPath, pcMonitoringDevices.get(0), pcMonitoringDeviceModel);
logger.info("任务ID--------" + taskId + ",发布时间--------" + createDate + ",通道ID--------" + pcMonitoringDeviceModel.getMonitoringDeviceId() + ",配置模型ID--------" + pcMonitoringDeviceModel.getId() + ",模型标识--------" + pcMonitoringDeviceModel.getClassName() + ",模型标签------" + pcMonitoringDeviceModel.getLabel() + ",模型识别结果--------" + gson.toJson(modelResults));
}
}
} else {
if (StringUtils.isNotBlank(key) && redisUtil.hasKey(key)) {
if (key.startsWith("quantity_detection")) {
Map<Object, Object> hmget = redisUtil.hmget(key);
long expire = redisUtil.getExpire(key);
if (hmget.size() == 1) {
redisUtil.hset(key, "2", DayUtils.getNow() + "_" + 0, expire);
} else if (hmget.size() == 2) {
redisUtil.hset(key, "3", DayUtils.getNow() + "_" + 0, expire);
} else if (hmget.size() == 3) {
Object second = redisUtil.hget(key, "2");
Object three = redisUtil.hget(key, "3");
redisUtil.del(key);
redisUtil.hset(key, "1", second, expire);
redisUtil.hset(key, "2", three, expire);
redisUtil.hset(key, "3", DayUtils.getNow() + "_" + 0, expire);
}
} else {
logger.error("-------------------------------------------删除了", key);
redisUtil.del(key);
}
}
}
// 8.3、若模型设置保留截图,保存原图
if (pcMonitoringDeviceModel.getIsSave().equals(URLConstant.TYPE_DEVICE_ON) && isOrNotSaveFlag) {
pool.execute(() -> {
try {
//根据模型保存图片
//保存实体路径为 ffmpeg图片保存地址+通道号+当天日期
String baseImgPath = RuoYiConfig.getModelImgPath() + "/" + pcMonitoringDevice.getImei() + "/" + pcMonitoringDeviceModel.getAiModelId() + "/" + DayUtils.getToday();
//新建文件夹
FileUtil.createFile(baseImgPath);
baseImgPath = baseImgPath + "/" + DayUtils.getToday() + "_" + DayUtils.getTodayTime() + "_" + UUID.randomUUID() + ".jpg";
FileUtil.copy(imgPath, baseImgPath);
} catch (IOException e) {
logger.error("保存原图失败" + e);
}
});
}
}
} else {
logger.error("{} 文件不存在++++++++++++++++++++", imgPath);
}
} else {
//结果失败
logger.error("当前处理是视频流处理出现错误时返回的信息,请根据相关信息检查出现错误的原因:" + "任务ID--------" + redisUtil.get("task_id_" + videoResult.getVideoId()) + ",code--------" + videoResult.getCode() + ",视频流ID--------" + videoResult.getVideoId() + ",失败信息------" + videoResult.getMessage());
}
} catch (Exception e) {
logger.error("视频流回调处理结果报错" + e);
}
});
}
public void getOffDutyDetection(String createDate, Long taskId, String imgPath, PcMonitoringDeviceModel pcMonitoringDeviceModel, List<ModelResult> result, PcMonitoringDevice pcMonitoringDevice) {
if (pcMonitoringDeviceModel.getType().equals(URLConstant.MODEL_TYPE_2)) {
//8.5.1、筛选大于零且小于等于相似度阈值的识别结果
List<ModelResult> modelResults = new ArrayList<ModelResult>(); //筛选后识别结果
if (result.size() > 0) {
for (int i = 0; i < result.size(); i++) {
// 识别结果格式化成ModelResult
ModelResult modelResult = result.get(i);
// 获取结果category等于当前模型label
if (modelResult.getCategory().equals(pcMonitoringDeviceModel.getLabel())) {
modelResults.add(modelResult);
}
}
}
// 8.5.2、筛选后识别结果数等于0
if (modelResults.size() == 0) {
ModelResult modelResult = new ModelResult();
modelResult.setCategory(pcMonitoringDeviceModel.getLabel());
modelResult.setBbox(new ArrayList<>());
modelResult.setScore(0);
modelResults.add(modelResult);
}
// 8.5.3、发布到redis通道
publishAiMessage(taskId, modelResults, createDate, imgPath, pcMonitoringDevice, pcMonitoringDeviceModel);
logger.info("小于等于阈值(包含识别没有结果)--------任务ID--------" + taskId + ",发布时间--------" + createDate + ",通道ID--------" + pcMonitoringDeviceModel.getMonitoringDeviceId() + ",配置模型ID--------" + pcMonitoringDeviceModel.getId() + ",模型标识--------" + pcMonitoringDeviceModel.getClassName() + ",模型标签------" + pcMonitoringDeviceModel.getLabel() + ",模型识别结果--------" + gson.toJson(modelResults));
}
}
/**
* 处理视频流前置算法回调返回结果
*
* @param videoResult
*/
@Override
public void videoFrontAlgoResult(VideoResult videoResult) {
pool.execute(new Runnable() {
@Override
public void run() {
try {
Map<String, Object> inferParameterMap = videoResult.getInferParameter();
Object pcMonitoringDeviceModelId = inferParameterMap.get("pcMonitoringDeviceModelId");
if (null == pcMonitoringDeviceModelId || "".equals(pcMonitoringDeviceModelId)) {
logger.error("前置算法缺少监控通道关联模型Id【***************************************】");
return;
}
PcMonitoringDeviceModel pcMonitoringDeviceModel = iPcMonitoringDeviceModelService.selectPcMonitoringDeviceModelId(Long.valueOf(String.valueOf(pcMonitoringDeviceModelId)));
if (null == pcMonitoringDeviceModel) {
logger.error("前置算法数据库缺少监控通道关联模型【***************************************】");
return;
}
Object pcMonitoringDeviceId = inferParameterMap.get("monitoringDeviceId");
if (null == pcMonitoringDeviceId || "".equals(pcMonitoringDeviceId)) {
logger.error("前置算法缺少监控通道Id【***************************************】");
return;
}
PcMonitoringDevice pcMonitoringDeviceQuery = new PcMonitoringDevice();
pcMonitoringDeviceQuery.setId(Long.valueOf(String.valueOf(pcMonitoringDeviceId)));
List<PcMonitoringDevice> pcMonitoringDevices = pcMonitoringDeviceService.selectPcMonitoringDeviceList(pcMonitoringDeviceQuery);
if (null == pcMonitoringDevices || pcMonitoringDevices.size() == 0) {
logger.error("前置算法数据库缺少监控通道【***************************************】");
return;
}
String imagePath = videoResult.getImagePath();
if (null == imagePath || "".equals(imagePath)) {
logger.error("前置算法缺少图片路径【***************************************】");
return;
}
File file = new File(imagePath);
if (!file.exists()) {
logger.error("前置算法缺少图片文件【***************************************】");
return;
}
Object taskId = inferParameterMap.get("taskId");
if (null == taskId || "".equals(taskId)) {
logger.error("前置算法缺少任务Id【***************************************】");
return;
}
Object createDate = inferParameterMap.get("createDate");
if (null == createDate || "".equals(createDate)) {
logger.error("前置算法缺少创建时间【***************************************】");
return;
}
if (pcMonitoringDeviceModel.getType().equals(URLConstant.MODEL_TYPE_2)) {
getOffDutyDetection(String.valueOf(createDate), Long.parseLong(String.valueOf(taskId)), imagePath, pcMonitoringDeviceModel, videoResult.getResult(), pcMonitoringDevices.get(0));
return;
}
Object resultOld = inferParameterMap.get("frontAlgoResult");
if (null == resultOld || "".equals(resultOld)) {
logger.error("前置算法缺少算法识别结果【***************************************】");
return;
}
//人体前置算法识别结果
List<ModelResult> result = videoResult.getResult();
if (null == result || result.size() == 0) {
logger.error("前置算法缺少算法识别结果【***************************************】");
return;
}
//算法识别结果
JSONArray resultOldJSONArray = JSONArray.fromObject(resultOld);
//如果是非需要两次结果的交集的 就是按照第二次结果与ROI进行比较 则过滤结果是第二次的结果
boolean needCheckForFirstResult = (boolean) inferParameterMap.get("needCheckForFirstResult");
List<ModelResult> filterResult;
if (!needCheckForFirstResult){
//不需要与第一次结果进行比较,则直接进行第二次结果的过滤
String personBodyPreModelIds = configService.selectConfigByKey(URLConstant.PERSON_BODY_PRE_MODEL_IDS);
String[] split = personBodyPreModelIds.split(",");
String resVal = null;
for (String s : split) {
String[] split1 = new String[0];
if (s.contains("&")){
split1 = s.split("&");
s = split1[0];
}
if (pcMonitoringDeviceModel.getAiModelId() == Long.parseLong(s)){
resVal = split1.length > 1 ? split1[1] : pcMonitoringDeviceModel.getSimilarity();
}
}
pcMonitoringDeviceModel.setSimilarity(resVal == null ? pcMonitoringDeviceModel.getSimilarity() : resVal);
CheckResultAlarmRule checkResultAlarmRule = aiTaskService.checkResultRule(pcMonitoringDeviceModel, result);
filterResult = checkResultAlarmRule.getModelResults();
}else {
filterResult = getFilterResult(result, resultOldJSONArray);
}
if (null != filterResult && filterResult.size() >= Integer.parseInt(pcMonitoringDeviceModel.getNumber())) {
// 8.3.3、发布到redis通道
publishAiMessage(Long.valueOf(String.valueOf(taskId)), filterResult, String.valueOf(createDate), imagePath, pcMonitoringDevices.get(0), pcMonitoringDeviceModel);
logger.info("任务ID--------" + taskId + ",发布时间--------" + createDate + ",通道ID--------" + pcMonitoringDeviceModel.getMonitoringDeviceId() + ",配置模型ID--------" + pcMonitoringDeviceModel.getId() + ",模型标识--------" + pcMonitoringDeviceModel.getClassName() + ",模型标签------" + pcMonitoringDeviceModel.getLabel() + ",模型识别结果--------" + gson.toJson(filterResult));
}
} catch (Exception e) {
logger.error("前置算法处理结果报错" + e);
}
}
});
}
/**
* 自启动视频流
*
* @return
*/
public void selfStartVideoStream() {
logger.info("======================自动开启视频流========================");
try {
PcMonitoringTask pcMonitoringTask = new PcMonitoringTask();
List<PcMonitoringTask> pcMonitoringTaskList = pcMonitoringTaskService.selectPcMonitoringTaskList(pcMonitoringTask);
for (PcMonitoringTask pcMonitoringTask1 : pcMonitoringTaskList) {
if (pcMonitoringTask1.getStatus().equals(URLConstant.MONITORING_TASK_STATUS_ENABLE)) {
//判断当前任务是视频分析还是抽帧检测
if (pcMonitoringTask1.getRecognitionMode().equals(URLConstant.RECOGNITION_MODE_VIDEO_ANALYSIS_PUSH_FLOW) || pcMonitoringTask1.getRecognitionMode().equals(URLConstant.RECOGNITION_MODE_VIDEO_ANALYSIS_NOT_PUSH_FLOW)) {
//是否在任务执行期间
boolean rNotTriggerStartVideoStream = sysJobService.is0rNotTriggerStartVideoStream(pcMonitoringTask1);
if (rNotTriggerStartVideoStream) {
startVideoStreamByTaskId(pcMonitoringTask1.getId(), true, false);
Thread.sleep(5000);
}
}
}
}
} catch (Exception e) {
logger.error("视频流自启动失败", e.getMessage());
}
}
/**
* 获取当前设备的主机号和端口号
*
* @return
*/
public String getUrl() {
InetAddress address = null;
try {
address = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
e.printStackTrace();
}
return "http://" + address.getHostAddress() + ":" + this.serverPort;
}
/**
* 发布消息到redis中
*
* @param modelResults
* @param createDate
* @param imgPath
* @param pcMonitoringDevice
* @param pcMonitoringDeviceModel
*/
@Async
public void publishAiMessage(Long taskId, List<ModelResult> modelResults, String createDate, String imgPath, PcMonitoringDevice pcMonitoringDevice, PcMonitoringDeviceModel pcMonitoringDeviceModel) {
AiMessage aiMessage = new AiMessage();
aiMessage.setTaskId(taskId);
aiMessage.setCreateDate(createDate);
aiMessage.setImgPath(imgPath);
aiMessage.setPcMonitoringDevice(pcMonitoringDevice);
aiMessage.setPcMonitoringDeviceModel(pcMonitoringDeviceModel);
aiMessage.setModelResults(modelResults);
aiTaskService.processMessage(gson.toJson(aiMessage));
}
public List<ModelResult> getPersonFrontAlgo(String createDate, Long taskId, String imgPath, PcMonitoringDeviceModel pcMonitoringDeviceModel, List<ModelResult> result) {
// 人体识别算法模型标识
String person_body_model_name = configService.selectConfigByKey(URLConstant.PERSON_BODY_MODEL_NAME);
// 人体识别算法模型标签
String person_body_label = configService.selectConfigByKey(URLConstant.PERSON_BODY_LABEL);
String pc_http_url = configService.selectConfigByKey(URLConstant.PC_HTTP_URL);
// 需要人体前置检测的算法模型
String person_body_pre_model_ids = configService.selectConfigByKey(URLConstant.PERSON_BODY_PRE_MODEL_IDS);
// 配置模型
boolean flag = false;
if (null != person_body_model_name && person_body_model_name.trim().length() != 0 && !person_body_model_name.equals("false")
&& null != person_body_label && person_body_label.trim().length() != 0 && !person_body_label.equals("false")
&& null != person_body_pre_model_ids && person_body_pre_model_ids.trim().length() != 0 && !person_body_pre_model_ids.equals("false")) {
// 判断需要人体前置检测的算法模型中的是否包含当前模型名称,若包含继续执行,若不包含跳出执行
// 默认当前模型不在人体检测前置算法模型中
boolean checkROIResult = false;
boolean needCheckForFirstResult = true;
String[] pre_model_ids = person_body_pre_model_ids.split(",");
for (String pre_model : pre_model_ids) {
if (pre_model.contains("&")){
checkROIResult = true;
needCheckForFirstResult = false;
String[] split = pre_model.split("&");
pre_model = split[0];
}
if (null != pcMonitoringDeviceModel.getAiModelId() && Long.valueOf(pre_model).equals(pcMonitoringDeviceModel.getAiModelId())) {
flag = true; // 包含在人体检测前置算法模型中
break;
}
}
if (!flag) {
// 若不包含在,直接返回
return result;
} else {
if (checkROIResult){
//检查结果是否符合条件
CheckResultAlarmRule checkResultAlarmRule = aiTaskService.checkResultRule(pcMonitoringDeviceModel, result);
if (!checkResultAlarmRule.isAlarm()){
return null;
}
}
if (null != result && result.size() >= Integer.parseInt(pcMonitoringDeviceModel.getNumber())) {
Long monitoringDeviceId = pcMonitoringDeviceModel.getMonitoringDeviceId();
Map<String, Object> stringObjectMap = new HashMap<>();
stringObjectMap.put("taskId", taskId);
stringObjectMap.put("pcMonitoringDeviceModelId", pcMonitoringDeviceModel.getId());
stringObjectMap.put("monitoringDeviceId", monitoringDeviceId);
stringObjectMap.put("createDate", createDate);
stringObjectMap.put("frontAlgoResult", result);
stringObjectMap.put("needCheckForFirstResult",needCheckForFirstResult);
getModelResultHttp(imgPath, pc_http_url, person_body_model_name, person_body_label, stringObjectMap);
}
return null;
}
} else {
return result;
}
}
public List<ModelResult> getFilterResult(List<ModelResult> personBodyInfo, JSONArray result) {
logger.info("测试筛选前的结果长度{}*******************************************************{}", result.size(), gson.toJson(result));
// 人体识别算法模型标识
// String person_body_model_name = configService.selectConfigByKey(URLConstant.PERSON_BODY_MODEL_NAME);
// 人体识别算法模型标签
String person_body_label = configService.selectConfigByKey(URLConstant.PERSON_BODY_LABEL);
// 人体识别算法模型得分
String person_body_score = configService.selectConfigByKey(URLConstant.PERSON_BODY_SCORE);
if (null == person_body_score || person_body_score.trim().length() == 0) {
person_body_score = "0";
}
List<ModelResult> personBodyInfos = new ArrayList<>();
for (ModelResult o : personBodyInfo) {
// ModelResult personBodyResult = gson.fromJson(o.toString(), ModelResult.class);
if (person_body_label.equals(o.getCategory())
&& o.getScore() >= Double.parseDouble(person_body_score)) {
personBodyInfos.add(o);
}
}
if (personBodyInfos.size() == 0) {
return new ArrayList<>();
}
//判断当前返回结果是否和框图存在交叉
List<ModelResult> modelResult = new ArrayList<>();
for (ModelResult personBodyResult : personBodyInfos) {
// 人体识别坐标
List<Double> personBodyBbox = personBodyResult.getBbox();
// 人体的矩形
PolygonUtil.Polygon personBodyPolygon = new PolygonUtil.Polygon().setPoints(Arrays.asList(
new PolygonUtil.Point(personBodyBbox.get(0), personBodyBbox.get(1)),
new PolygonUtil.Point(personBodyBbox.get(2), personBodyBbox.get(1)),
new PolygonUtil.Point(personBodyBbox.get(2), personBodyBbox.get(3)),
new PolygonUtil.Point(personBodyBbox.get(0), personBodyBbox.get(3))
));
for (Object classNameResult1 : result) {
ModelResult classNameResult = gson.fromJson(classNameResult1.toString(), ModelResult.class);
// 调用模型的循环
if (!"no".equals(classNameResult.getCategory())) {
// 调用模型得到的结果坐标
List<Double> classNameBbox = classNameResult.getBbox();
// 调用模型得到的结果矩形
PolygonUtil.Polygon classNamePolygon = new PolygonUtil.Polygon().setPoints(Arrays.asList(
new PolygonUtil.Point(classNameBbox.get(0), classNameBbox.get(1)),
new PolygonUtil.Point(classNameBbox.get(2), classNameBbox.get(1)),
new PolygonUtil.Point(classNameBbox.get(2), classNameBbox.get(3)),
new PolygonUtil.Point(classNameBbox.get(0), classNameBbox.get(3))
));
if (PolygonUtil.intersectionJudgment(classNamePolygon, personBodyPolygon)) {
// logger.info("模型识别矩形与人体识别矩形相交。");
modelResult.add(classNameResult);
}
}
}
}
// 去重
if (modelResult.size() != 0 && modelResult.size() != 1) {
for (int i = 0; i < modelResult.size(); i++) {
for (int j = i + 1; j < modelResult.size(); j++) {
BigDecimal score1 = BigDecimal.valueOf(modelResult.get(i).getScore());
BigDecimal score2 = BigDecimal.valueOf(modelResult.get(j).getScore());
boolean isEqual = modelResult.get(i).getCategory().equals(modelResult.get(j).getCategory()) && modelResult.get(i).getBbox().equals(modelResult.get(j).getBbox()) &&
score1.compareTo(score2) == 0;
if (isEqual) {
modelResult.remove(j);
j--;
}
}
}
}
logger.info("测试筛选后的结果长度{}*******************************************************{}", modelResult.size(), gson.toJson(modelResult));
return modelResult;
}
public void getModelResultHttp(String imgPath, String pc_http_url, String person_body_model_name, String person_body_label, Map<String, Object> inferParameter) {
JSONObject param = new JSONObject();
param.put("imagePath", imgPath);
param.put("imageName", imgPath.substring(imgPath.lastIndexOf("/") + 1).replace(".jpg", ""));
param.put("inferParameter", inferParameter);
List<ModelNames> modelNamesList = new ArrayList<>();
ArrayList<String> stringArrayList = new ArrayList<>(Arrays.asList(person_body_label.split(",")));
ModelNames modelNames = new ModelNames(person_body_model_name, stringArrayList, "");
modelNamesList.add(modelNames);
param.put("modelNames", modelNamesList);
try {
// logger.info("前置算法参数*******************************************************{}", gson.toJson(param));
String resultPersonAlgo = OkHttpUtil.post(pc_http_url, param.toString());
// logger.info("调用底层接口返回值*******************************************************{}", gson.toJson(resultPersonAlgo));
} catch (Exception e) {
logger.error("前置算法调用错误->{}", e.getMessage());
}
}
}
文档更新时间: 2023-12-18 03:25 作者:JeffreyCheung