package com.inspect.nvr.service.impl;
|
|
|
|
|
|
import cn.hutool.core.util.ObjectUtil;
|
|
import com.alibaba.fastjson.JSONObject;
|
|
import com.fasterxml.jackson.databind.JsonNode;
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
import com.google.gson.Gson;
|
|
import com.inspect.nvr.domain.Infrared.*;
|
|
import com.inspect.nvr.domain.algorithm.in.AnalyseReqItem;
|
|
import com.inspect.nvr.domain.algorithm.in.AnalyseRequest;
|
|
import com.inspect.nvr.domain.algorithm.out.AnalyseResItem;
|
|
import com.inspect.nvr.domain.algorithm.out.AnalyseResPoint;
|
|
import com.inspect.nvr.domain.algorithm.out.AnalyseResult;
|
|
import com.inspect.nvr.domain.camera.CameraPresetPoint;
|
|
import com.inspect.nvr.hikVision.utils.AjaxResult;
|
|
import com.inspect.nvr.hikVision.utils.StringUtils;
|
|
import com.inspect.nvr.hikVision.utils.jna.HCNetSDK;
|
|
import com.inspect.nvr.hikVision.utils.jna.HikVisionUtils;
|
|
import com.inspect.nvr.service.HikCameraService;
|
|
import com.inspect.nvr.service.HikFRemoteConfigCallBack_imp;
|
|
import com.inspect.nvr.service.HikLoginService;
|
|
import com.inspect.nvr.service.HikVisionService;
|
|
import com.inspect.nvr.tempCount.TempCount;
|
|
import com.inspect.nvr.utils.DateUtils;
|
|
import com.inspect.nvr.utils.redis.RedisService;
|
|
import com.inspect.nvr.utils.sftp.SftpClient;
|
|
import com.sun.jna.Memory;
|
|
import com.sun.jna.Pointer;
|
|
import com.sun.jna.ptr.IntByReference;
|
|
import okhttp3.*;
|
|
import org.apache.commons.compress.utils.IOUtils;
|
|
import org.apache.commons.csv.CSVFormat;
|
|
import org.apache.commons.csv.CSVParser;
|
|
import org.apache.commons.csv.CSVRecord;
|
|
import org.apache.commons.net.ftp.FTPSClient;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.data.redis.core.RedisTemplate;
|
|
import org.springframework.http.ResponseEntity;
|
|
import org.springframework.stereotype.Service;
|
|
|
|
import javax.annotation.Resource;
|
|
import javax.imageio.ImageIO;
|
|
import java.awt.*;
|
|
import java.awt.image.BufferedImage;
|
|
import java.io.*;
|
|
import java.net.URI;
|
|
import java.net.URISyntaxException;
|
|
import java.nio.ByteBuffer;
|
|
import java.nio.ByteOrder;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Path;
|
|
import java.nio.file.Paths;
|
|
import java.text.SimpleDateFormat;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Date;
|
|
import java.util.List;
|
|
import java.util.concurrent.*;
|
|
|
|
/**
|
|
* 海康威视测试服务类
|
|
*/
|
|
@Service
|
|
public class HikVisionServiceImpl implements HikVisionService {
|
|
|
|
private static HikFExceptionCallBack_Imp fExceptionCallBack;
|
|
private final Logger log = LoggerFactory.getLogger(this.getClass());
|
|
@Autowired
|
|
private HCNetSDK hcNetSDK;
|
|
private String picPath;
|
|
|
|
// @Value("${file.hrUavUrl:test}")
|
|
// private String hrUavUrl = "http://192.168.4.167:2000/";
|
|
private String hrUavUrl = "http://192.168.4.160:2000/";
|
|
|
|
// @Value("${file.hrFtpUrl:test}")
|
|
private String hrFtpUrl = "ftp://ftpuser:atia2018@192.168.4.129:10012/";
|
|
|
|
// @Value("${file.ftpUrlAddress:test}")
|
|
private String ftpUrlAddress = "192.168.1.116";
|
|
|
|
// @Value("${file.ftpUrlAccount:test}")
|
|
private String ftpUrlAccount = "ftpuser";
|
|
|
|
// @Value("${file.ftpUrlPwd:test}")
|
|
private String ftpUrlPwd = "atia2018";
|
|
|
|
// @Value("${file.ftpUrlPort:10000}")
|
|
private Integer ftpUrlPort = 10990;
|
|
|
|
|
|
// @Value("${file.produceEnvironment:true}")
|
|
private Boolean produceEnvironment = true;
|
|
|
|
|
|
@Autowired
|
|
private RedisTemplate redisTemplate;
|
|
|
|
@Resource
|
|
private SftpClient sftpClient;
|
|
|
|
@Resource
|
|
private TempCount tempCount;
|
|
|
|
@Resource
|
|
private RedisService redisService;
|
|
|
|
@Resource
|
|
private HikCameraService hikCameraService;
|
|
|
|
|
|
private Integer lUserID;
|
|
@Autowired
|
|
private HikLoginService hikLoginService;
|
|
|
|
//二维数组转 CSV
|
|
private static String convertMatrixToCsv(float[][] matrix) {
|
|
StringBuilder csvBuilder = new StringBuilder();
|
|
for (float[] row : matrix) {
|
|
for (int i = 0; i < row.length; i++) {
|
|
csvBuilder.append(row[i]);
|
|
if (i < row.length - 1) {
|
|
csvBuilder.append(",");
|
|
}
|
|
}
|
|
csvBuilder.append("\n");
|
|
}
|
|
return csvBuilder.toString();
|
|
}
|
|
|
|
public static String truncateFileNameToCsv(String originalPath) {
|
|
// 获取文件名部分(最后一个 '/' 之后的内容)
|
|
int lastSlashIndex = originalPath.lastIndexOf('/');
|
|
if (lastSlashIndex == -1) {
|
|
// 如果没有路径分隔符,直接处理整个字符串
|
|
return processFileNameToCsv(originalPath);
|
|
}
|
|
|
|
// 分离路径和文件名
|
|
String path = originalPath.substring(0, lastSlashIndex + 1);
|
|
String fileName = originalPath.substring(lastSlashIndex + 1);
|
|
|
|
// 处理文件名部分并强制改为.csv
|
|
String processedFileName = processFileNameToCsv(fileName);
|
|
|
|
|
|
return path + processedFileName;
|
|
}
|
|
|
|
private static String processFileNameToCsv(String fileName) {
|
|
// 去掉文件扩展名(如果有)
|
|
int lastDotIndex = fileName.lastIndexOf('.');
|
|
if (lastDotIndex != -1) {
|
|
fileName = fileName.substring(0, lastDotIndex);
|
|
}
|
|
|
|
// 去掉最后一个 '_' 及其后面的部分
|
|
int lastUnderscoreIndex = fileName.lastIndexOf('_');
|
|
if (lastUnderscoreIndex != -1) {
|
|
fileName = fileName.substring(0, lastUnderscoreIndex);
|
|
}
|
|
|
|
// 强制添加.csv后缀
|
|
return fileName + ".csv";
|
|
}
|
|
|
|
@Override
|
|
public AjaxResult login(NvrInfo nvrInfo) {
|
|
return login_V40(nvrInfo);
|
|
}
|
|
|
|
/**
|
|
* 设备登录V40 与V30功能一致
|
|
*/
|
|
public AjaxResult login_V40(NvrInfo nvrInfo) {
|
|
|
|
HCNetSDK.NET_DVR_USER_LOGIN_INFO m_strLoginInfo = HikVisionUtils.login_V40(nvrInfo.getNvrIp(), nvrInfo.getServerPort().shortValue(), nvrInfo.getAccount(), nvrInfo.getPassword());//设备登录信息
|
|
HCNetSDK.NET_DVR_DEVICEINFO_V40 m_strDeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V40();//设备信息
|
|
|
|
int lUserID = hcNetSDK.NET_DVR_Login_V40(m_strLoginInfo, m_strDeviceInfo);
|
|
if (lUserID == -1) {
|
|
System.out.println("登录失败,错误码为" + hcNetSDK.NET_DVR_GetLastError());
|
|
return AjaxResult.error(hcNetSDK.NET_DVR_GetErrorMsg(new IntByReference(hcNetSDK.NET_DVR_GetLastError())));
|
|
} else {
|
|
System.out.println(":设备登录成功!" + lUserID);
|
|
// birdNvrMapper.updateNvrInfo(nvrInfo);
|
|
// redisTemplate.opsForValue().set(nvrInfo.getNvrIp() + "_userId", lUserID);
|
|
redisService.setCacheObject(nvrInfo.getNvrIp() + "_userId", lUserID, 200L, TimeUnit.SECONDS);
|
|
//若果设备序列号为空时,即为第一次登陆,写入基础数据
|
|
if (nvrInfo.getNvrSerial() == null || nvrInfo.getNvrSerial().equals("")) {
|
|
m_strDeviceInfo.read();
|
|
HCNetSDK.NET_DVR_DEVICEINFO_V30 deviceinfo_v30 = m_strDeviceInfo.struDeviceV30;
|
|
nvrInfo.setNvrSerial(StringUtils.bytetoString(deviceinfo_v30.sSerialNumber, "GB2312"));
|
|
//模拟通道不为0,并且数字通道为0,即为模拟通道
|
|
if (deviceinfo_v30.byChanNum != 0 && deviceinfo_v30.byIPChanNum == 0) {
|
|
nvrInfo.setChannelType(0);
|
|
nvrInfo.setChannelNumber(deviceinfo_v30.byChanNum + deviceinfo_v30.byHighDChanNum * 256);
|
|
nvrInfo.setStartChannel((int) deviceinfo_v30.byStartChan);
|
|
}
|
|
//模拟通道为0,并且数字通道不为0,即为数字通道
|
|
if (deviceinfo_v30.byChanNum == 0 && deviceinfo_v30.byIPChanNum != 0) {
|
|
nvrInfo.setChannelType(1);
|
|
nvrInfo.setChannelNumber(deviceinfo_v30.byIPChanNum + deviceinfo_v30.byHighDChanNum * 256);
|
|
nvrInfo.setStartChannel((int) deviceinfo_v30.byStartDChan);
|
|
}
|
|
//模拟通道不为0,并且数字通道不为0,即为双通道。
|
|
if (deviceinfo_v30.byChanNum != 0 && deviceinfo_v30.byIPChanNum != 0) {
|
|
nvrInfo.setChannelType(2);
|
|
nvrInfo.setChannelNumber(deviceinfo_v30.byChanNum + deviceinfo_v30.byHighDChanNum * 256);
|
|
nvrInfo.setStartChannel((int) deviceinfo_v30.byStartChan);
|
|
}
|
|
nvrInfo.setCalicheNumber((int) deviceinfo_v30.byDiskNum);
|
|
nvrInfo.setCharEncodeType((int) m_strDeviceInfo.byCharEncodeType);
|
|
nvrInfo.setSyncDate(new Date());
|
|
// nvrInfoMapper.updateNvrInfo(nvrInfo);
|
|
}
|
|
return AjaxResult.success(hcNetSDK.NET_DVR_GetErrorMsg(new IntByReference(hcNetSDK.NET_DVR_GetLastError())));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 海康实时测温接口
|
|
* 优化并发场景
|
|
*/
|
|
public TemperatureData StartRemote(Camera camera) {
|
|
NvrInfo nvrInfo = new NvrInfo();
|
|
nvrInfo.setNvrIp(camera.getIp());
|
|
nvrInfo.setServerPort(camera.getPort());
|
|
nvrInfo.setAccount(camera.getUserName());
|
|
nvrInfo.setPassword(camera.getPassword());
|
|
TemperatureData data = hikCameraService.realTimeThermometry(nvrInfo, camera.getChannel());
|
|
return data;
|
|
}
|
|
|
|
/**
|
|
* @deprecated 实时测温接口,获取最高温和最低温
|
|
*/
|
|
@Deprecated
|
|
public TemperatureData StartRemoteOld(Camera camera) {
|
|
int result = 0;
|
|
TemperatureData temperatureData = null;
|
|
|
|
try {
|
|
|
|
log.info("实时测温入口=================================================");
|
|
if (camera.getLUserID() != 0) {
|
|
NvrInfo nvrInfo = new NvrInfo();
|
|
nvrInfo.setNvrIp(camera.getIp());
|
|
nvrInfo.setServerPort(camera.getPort());
|
|
nvrInfo.setAccount(camera.getUserName());
|
|
nvrInfo.setPassword(camera.getPassword());
|
|
int userId = hikLoginService.login(nvrInfo);
|
|
camera.setLUserID(userId);
|
|
}
|
|
|
|
log.info("开始实时测温=================================================");
|
|
// 2. 设置测温参数
|
|
HCNetSDK.NET_DVR_REALTIME_THERMOMETRY_COND cond = new HCNetSDK.NET_DVR_REALTIME_THERMOMETRY_COND();
|
|
cond.dwSize = cond.size();
|
|
cond.dwChan = camera.getChannel();// 通道号
|
|
cond.byRuleID = 1; // 规则ID
|
|
cond.byMode = 1; // 测温模式
|
|
cond.wInterval = 10; // 间隔
|
|
cond.byRes2 = new byte[32];
|
|
Arrays.fill(cond.byRes2, (byte) 0);
|
|
cond.write(); // 手动同步结构体到内存
|
|
CompletableFuture<TemperatureData> temperatureFuture = new CompletableFuture<>();
|
|
// 启动看门狗(4秒超时,比get()的5秒早1秒,预留处理时间)
|
|
ScheduledExecutorService watchdog = Executors.newSingleThreadScheduledExecutor();
|
|
watchdog.schedule(() -> {
|
|
if (!temperatureFuture.isDone()) {
|
|
log.warn("回调线程可能阻塞,看门狗强制标记超时");
|
|
temperatureFuture.completeExceptionally(new TimeoutException("回调线程阻塞超时"));
|
|
}
|
|
}, 5, TimeUnit.SECONDS);
|
|
// 3. 启动远程测温
|
|
Pointer lpInBuffer = cond.getPointer();
|
|
int dwInBufferSize = cond.size();
|
|
result = hcNetSDK.NET_DVR_StartRemoteConfig(
|
|
camera.getLUserID(),
|
|
HCNetSDK.NET_DVR_GET_REALTIME_THERMOMETRY,
|
|
lpInBuffer,
|
|
dwInBufferSize,
|
|
new HikFRemoteConfigCallBack_imp() {
|
|
@Override
|
|
public void invoke(int dwType, Pointer lpBuffer, int dwBufLen, Pointer pUserData) {
|
|
System.out.println("回调收到数据,类型: " + dwType + ", 长度: " + dwBufLen);
|
|
HCNetSDK.NET_DVR_THERMOMETRY_UPLOAD thermometryData = new HCNetSDK.NET_DVR_THERMOMETRY_UPLOAD();
|
|
int structSize = thermometryData.size();
|
|
if (dwBufLen < structSize) {
|
|
System.out.println("缓冲区长度不足,期望: " + structSize + ", 实际: " + dwBufLen);
|
|
return;
|
|
}
|
|
Pointer structurePointer = thermometryData.getPointer();
|
|
structurePointer.write(0, lpBuffer.getByteArray(0, structSize), 0, structSize);
|
|
thermometryData.read(); // 解析数据到结构体字段
|
|
HCNetSDK.NET_DVR_LINEPOLYGON_THERM_CFG struLinePolygonThermCfg = thermometryData.struLinePolygonThermCfg;
|
|
System.out.println("规则ID: " + thermometryData.byRuleID);
|
|
System.out.println("最高温度: " + struLinePolygonThermCfg.fMaxTemperature);
|
|
System.out.println("最低温度: " + struLinePolygonThermCfg.fMinTemperature);
|
|
System.out.println("平均温度: " + struLinePolygonThermCfg.fAverageTemperature);
|
|
System.out.println("温差: " + struLinePolygonThermCfg.fTemperatureDiff);
|
|
System.out.println("通道号: " + thermometryData.dwChan);
|
|
System.out.println("-----------------------------------------------------------");
|
|
// 封装所有温度数据
|
|
TemperatureData data = new TemperatureData(
|
|
String.valueOf(struLinePolygonThermCfg.fMaxTemperature),
|
|
String.valueOf(struLinePolygonThermCfg.fMinTemperature),
|
|
struLinePolygonThermCfg.fAverageTemperature,
|
|
struLinePolygonThermCfg.fTemperatureDiff,
|
|
thermometryData.dwChan,
|
|
thermometryData.byRuleID
|
|
);
|
|
temperatureFuture.complete(data); // 返回完整数据
|
|
}
|
|
},
|
|
null
|
|
);
|
|
log.info("测温结束=================================================");
|
|
if (result == -1) {
|
|
int errorCode = hcNetSDK.NET_DVR_GetLastError();
|
|
String errorMsg = hcNetSDK.NET_DVR_GetErrorMsg(new IntByReference(errorCode));
|
|
log.error("启动远程测温失败,错误码为:{},错误信息为:{}", errorCode, errorMsg);
|
|
}
|
|
temperatureData = temperatureFuture.get();
|
|
} catch (Exception e) {
|
|
log.error("测温异常报错: {}", e.getMessage());
|
|
} finally {
|
|
log.info("关闭实时测温result值 {}", result);
|
|
//关闭实时测温
|
|
boolean i = StopRemote(result);
|
|
if (i) {
|
|
log.info("关闭实时测温成功 {}", true);
|
|
}
|
|
}
|
|
return temperatureData;
|
|
}
|
|
|
|
//关闭实时测温
|
|
@Override
|
|
public boolean StopRemote(int result) {
|
|
boolean b = hcNetSDK.NET_DVR_StopRemoteConfig(result);
|
|
return b;
|
|
}
|
|
|
|
@Override
|
|
public AjaxResult cameraAngleJump(Camera camera) {
|
|
log.info(camera.getIp() + "摄像头跳转");
|
|
// hcNetSDK.NET_DVR_Init();
|
|
// 1. 登录设备
|
|
HCNetSDK.NET_DVR_USER_LOGIN_INFO m_strLoginInfo = HikVisionUtils.login_V40(
|
|
camera.getIp(),
|
|
(short) camera.getPort(),
|
|
camera.getUserName(),
|
|
camera.getPassword()
|
|
);
|
|
HCNetSDK.NET_DVR_DEVICEINFO_V40 m_strDeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V40();
|
|
int lUserID = hcNetSDK.NET_DVR_Login_V40(m_strLoginInfo, m_strDeviceInfo);
|
|
//将登录认证传下去
|
|
camera.setLUserID(lUserID);
|
|
|
|
//2. 直连摄像头跳转,打开实时预览
|
|
HCNetSDK.NET_DVR_CLIENTINFO netDvrClientinfo = new HCNetSDK.NET_DVR_CLIENTINFO();
|
|
netDvrClientinfo.lChannel = 1;
|
|
netDvrClientinfo.lLinkMode = 1;
|
|
|
|
|
|
int i = hcNetSDK.NET_DVR_RealPlay(lUserID, netDvrClientinfo);
|
|
|
|
//实时预览返回,预置位跳转,跳转的预置位码
|
|
boolean gotoPreset = hcNetSDK.NET_DVR_PTZPreset(i, HCNetSDK.GOTO_PRESET, camera.getPointNum());
|
|
if (!gotoPreset) {
|
|
log.error("获取设备预置位跳转设备参数失败,错误码:" + hcNetSDK.NET_DVR_GetLastError());
|
|
return AjaxResult.error(hcNetSDK.NET_DVR_GetErrorMsg(new IntByReference(hcNetSDK.NET_DVR_GetLastError())));
|
|
} else {
|
|
log.info("海康-成功跳转到预置位!" + camera.getPointNum());
|
|
}
|
|
return AjaxResult.success();
|
|
}
|
|
|
|
//抓图 单独测试 未使用
|
|
@Override
|
|
public Camera cameraPictrue(Camera camera) throws Exception {
|
|
log.info(camera.getIp() + "摄像头抓图");
|
|
if (camera.getLUserID() != 0) {
|
|
// 1. 登录设备
|
|
HCNetSDK.NET_DVR_USER_LOGIN_INFO m_strLoginInfo = HikVisionUtils.login_V40(
|
|
camera.getIp(),
|
|
(short) camera.getPort(),
|
|
camera.getUserName(),
|
|
camera.getPassword()
|
|
);
|
|
HCNetSDK.NET_DVR_DEVICEINFO_V40 m_strDeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V40();
|
|
int lUserID = hcNetSDK.NET_DVR_Login_V40(m_strLoginInfo, m_strDeviceInfo);
|
|
//将登录认证传下去
|
|
camera.setLUserID(lUserID);
|
|
}
|
|
|
|
// 1. 设置抓图参数
|
|
HCNetSDK.NET_DVR_JPEGPARA dvrJpegpara = new HCNetSDK.NET_DVR_JPEGPARA();
|
|
dvrJpegpara.wPicSize = 0xff; // 0xff表示最高分辨率
|
|
dvrJpegpara.wPicQuality = 2; // 图像质量(1-6,1最高)
|
|
// 2. 创建临时存储目录(系统临时目录更安全)
|
|
// Path tempDir = Paths.get(System.getProperty("java.io.tmpdir"), "hik_capture");
|
|
// if (!Files.exists(tempDir)) {
|
|
// Files.createDirectories(tempDir);
|
|
// }
|
|
// // 3. 生成唯一文件名(IP+时间戳)
|
|
// String fileName = String.format("%s_%s.jpg", camera.getIp(), DateUtils.dateTimeNow("yyyyMMddHHmmss"));
|
|
// Path tempImagePath = tempDir.resolve(fileName);
|
|
// 确保目录存在
|
|
File picDir = new File("D:\\pic");
|
|
if (!picDir.exists()) {
|
|
picDir.mkdirs(); // 如果目录不存在,创建它
|
|
}
|
|
// 生成文件名(例如:camera_ip + timestamp)
|
|
String fileName = "D:\\pic\\" + camera.getIp() + "_" + System.currentTimeMillis() + ".jpg";
|
|
Path tempImagePath = Paths.get(fileName);
|
|
// 4. 执行抓图(注意:海康SDK要求Windows风格的路径)
|
|
boolean success = hcNetSDK.NET_DVR_CaptureJPEGPicture(camera.getLUserID(), 2, dvrJpegpara,
|
|
tempImagePath.toString().getBytes("GBK")); // 海康设备通常需要GBK编码
|
|
if (!success) {
|
|
int errorCode = hcNetSDK.NET_DVR_GetLastError();
|
|
String errorMsg = hcNetSDK.NET_DVR_GetErrorMsg(new IntByReference(errorCode));
|
|
// return AjaxResult.error("抓图失败:" + errorMsg + "(错误码:" + errorCode + ")");
|
|
log.error("抓图失败,错误码:{},错误信息:{}", errorCode, errorMsg);
|
|
}
|
|
// 5. 上传到FTP
|
|
try (InputStream inputStream = Files.newInputStream(tempImagePath)) {
|
|
picFtp(picPath + fileName,
|
|
inputStream,
|
|
ftpUrlAddress,
|
|
ftpUrlPort,
|
|
ftpUrlAccount,
|
|
ftpUrlPwd
|
|
);
|
|
} catch (Exception e) {
|
|
// return AjaxResult.error("FTP上传失败:" + e.getMessage());
|
|
log.error("抓图并上传失败:{}", e.getMessage());
|
|
} finally {
|
|
// 6. 确保删除临时文件
|
|
Files.deleteIfExists(tempImagePath);
|
|
}
|
|
camera.setUlr(picPath + fileName);
|
|
return camera;
|
|
}
|
|
|
|
//红外摄像头任务流程
|
|
public InfraredInfo cameraCalculatePicture(Camera camera) {
|
|
log.info("进入摄像头红外图片接口!");
|
|
picPath = "/2/";
|
|
|
|
InfraredInfo infraredInfo = new InfraredInfo();
|
|
int firstX = 1;
|
|
int firstY = 1;
|
|
int secondX = 639;
|
|
int secondY = 511;
|
|
int imgWidth = 640;
|
|
int imgHeight = 512;
|
|
InfraPictureInfo infraPictureInfo = new InfraPictureInfo();
|
|
List<Coordinate> coordinates = new ArrayList<>();
|
|
coordinates.add(new Coordinate(firstX, firstY, secondX, secondY));
|
|
infraPictureInfo.setImgWidth(imgWidth);
|
|
infraPictureInfo.setImgHeight(imgHeight);
|
|
infraPictureInfo.setCoordinates(coordinates);
|
|
|
|
|
|
//红外摄像头需要设置最大框测温规则1,固定到一个预置位上绑定
|
|
|
|
//1:跳转预置位
|
|
//家里相机没有预置位,现场相机存在预置位需要跳转到画测温框预置位,否则无法获取规则温度
|
|
// cameraAngleJump(camera);
|
|
|
|
//2:抓取图片,保存到ftp
|
|
try {
|
|
Camera cameraPictrue = cameraPictrue(camera);
|
|
camera.setLUserID(cameraPictrue.getLUserID());
|
|
} catch (Exception e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
//3:调取摄像头实时测温功能,获取最高温和最低温
|
|
TemperatureData temperatureData = StartRemote(camera);
|
|
|
|
// double maxTemperature = temperatureData.getMaxTemperature();
|
|
// double minTemperature = temperatureData.getMinTemperature();
|
|
temperatureData.getAvgTemperature();
|
|
temperatureData.getTemperatureDiff();
|
|
|
|
|
|
InputStream inputStream = downloadFtp(camera.getUlr());
|
|
//传入照片流,最大值最小温度值,反算温度矩阵
|
|
// float[][] floats = tempCount.countTemp(inputStream, maxTemperature, minTemperature);
|
|
// infraredInfo.setTemperatureMatrix(floats);
|
|
|
|
//4:画框标注,保存到ftp
|
|
|
|
infraPictureInfo.setFilePath(camera.getUlr());
|
|
|
|
String s = cameraImageOverlays(infraPictureInfo, infraredInfo);
|
|
infraredInfo.setOutPath(s);
|
|
|
|
return infraredInfo;
|
|
}
|
|
|
|
//摄像头画框
|
|
public String cameraImageOverlays(InfraPictureInfo infraPictureInfo, InfraredInfo infraredInfo) {
|
|
|
|
List<Coordinate> coordinates = infraPictureInfo.getCoordinates();
|
|
|
|
Date date = new Date();
|
|
SimpleDateFormat sf = new SimpleDateFormat("yyyyMMddHHmmss");
|
|
String markPicName = sf.format(date);
|
|
// 图片路径(请替换为实际路径)
|
|
String imagePath = infraPictureInfo.getFilePath();
|
|
// 获取文件名(不含扩展名)
|
|
File file = new File(imagePath);
|
|
String fileName = file.getName();
|
|
String pureName = fileName.substring(0, fileName.lastIndexOf('.'));
|
|
String filename = picPath;
|
|
String outputPath = picPath + pureName + "_" + markPicName + ".jpg";
|
|
String csvPath = picPath + pureName + "_" + markPicName + ".csv";
|
|
//判断路径是否存在
|
|
File filePath = new File(filename);
|
|
if (!filePath.exists()) {
|
|
//不存在,创建目录
|
|
filePath.mkdirs();
|
|
}
|
|
try {
|
|
InputStream inputStreamPath = downloadFtp(imagePath);
|
|
if (inputStreamPath == null) {
|
|
System.out.println("无法加载图片: " + imagePath);
|
|
return null;
|
|
}
|
|
// 加载原始图片
|
|
BufferedImage originalImage = ImageIO.read(inputStreamPath);
|
|
// 创建可编辑的图片副本
|
|
BufferedImage annotatedImage = new BufferedImage(
|
|
originalImage.getWidth(),
|
|
originalImage.getHeight(),
|
|
BufferedImage.TYPE_INT_RGB
|
|
);
|
|
// 绘制原始图片
|
|
Graphics2D g2d = annotatedImage.createGraphics();
|
|
g2d.drawImage(originalImage, 0, 0, null);
|
|
// 设置标注样式
|
|
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
|
// Font font = new Font("微软雅黑", Font.BOLD, 17);
|
|
Font font = new Font("WenQuanYi Zen Hei", Font.BOLD, 20);
|
|
final String imageType = infraPictureInfo.getImgType();
|
|
for (Coordinate c : coordinates) {
|
|
//点标注
|
|
if (c.getFirstX() != null && c.getFirstY() != null && c.getSecondX() == null && c.getSecondY() == null) {
|
|
g2d.setFont(font);
|
|
// 标注点坐标
|
|
g2d.setColor(Color.WHITE);
|
|
int x = c.getFirstX();
|
|
int y = c.getFirstY();
|
|
|
|
// 确保坐标在图片范围内
|
|
if (x >= 0 && x < originalImage.getWidth() &&
|
|
y >= 0 && y < originalImage.getHeight()) {
|
|
// 绘制点(用实心圆表示)
|
|
g2d.fillOval(x - 3, y - 3, 6, 6);
|
|
infraPictureInfo.setFirstX(x);
|
|
infraPictureInfo.setFirstY(y);
|
|
// InfraredInfo drawStringPoint = PointTemperatureShow(c, infraredInfo.getMatrixWidth(), infraredInfo.getMatrixHeight(), infraredInfo.getTemperatureMatrix());
|
|
// // 添加坐标标签
|
|
// g2d.drawString("(" + String.format("%.2f", drawStringPoint.getPointTemperature()) + ")", x + 8, y - 8);
|
|
}
|
|
}
|
|
//矩阵标注
|
|
if (c.getSecondX() != null && c.getSecondY() != null) {
|
|
// 标注矩形(每两个点确定一个矩形)
|
|
g2d.setColor(Color.WHITE);
|
|
int x1 = c.getFirstX();
|
|
int y1 = c.getFirstY();
|
|
int x2 = c.getSecondX();
|
|
int y2 = c.getSecondY();
|
|
|
|
// 确保坐标在图片范围内
|
|
if (x1 >= 0 && x1 < originalImage.getWidth() && y1 >= 0 && y1 < originalImage.getHeight() &&
|
|
x2 >= 0 && x2 < originalImage.getWidth() && y2 >= 0 && y2 < originalImage.getHeight()) {
|
|
|
|
// 确保x1,y1是左上角,x2,y2是右下角
|
|
int rectX = Math.min(x1, x2);
|
|
int rectY = Math.min(y1, y2);
|
|
int width = Math.abs(x2 - x1);
|
|
int height = Math.abs(y2 - y1);
|
|
|
|
// 设置更粗的画笔(加粗矩形边框)
|
|
g2d.setStroke(new BasicStroke(3)); // 3像素宽
|
|
// 绘制矩形
|
|
g2d.drawRect(rectX, rectY, width, height);
|
|
infraPictureInfo.setFirstX(x1);
|
|
infraPictureInfo.setFirstY(y1);
|
|
infraPictureInfo.setSecondX(x2);
|
|
infraPictureInfo.setSecondY(y2);
|
|
|
|
InfraredInfo drawStringMatrix = matrixTemperatureShow(c, infraredInfo.getMatrixWidth(), infraredInfo.getMatrixHeight(), infraredInfo.getTemperatureMatrix());
|
|
infraredInfo.setFrameMax(Math.round(drawStringMatrix.getFrameMax() * 100) / 100f);
|
|
Integer maxTempX = drawStringMatrix.getMaxTempX();
|
|
Integer maxTempY = drawStringMatrix.getMaxTempY();
|
|
log.info("最高温度值坐标点:" + "maxTempX:" + maxTempX + " maxTempY:" + maxTempY);
|
|
|
|
|
|
// 添加矩形标签
|
|
String line1 = "平均温度:" + String.format("%.2f", drawStringMatrix.getFrameAverage());
|
|
String line2 = "最高温度:" + String.format("%.2f", drawStringMatrix.getFrameMax());
|
|
String line3 = "最低温度:" + String.format("%.2f", drawStringMatrix.getFrameMin());
|
|
g2d.drawString(line1, rectX + 5, rectY + 15);
|
|
g2d.drawString(line2, rectX + 5, rectY + 30);
|
|
g2d.drawString(line3, rectX + 5, rectY + 45);
|
|
|
|
// 在最高温度点画一个空心圆(红色边框)
|
|
if (maxTempX != null && maxTempY != null) {
|
|
log.info("画最高温度的点,坐标:x={}, y={}", maxTempX, maxTempY);
|
|
|
|
// 边界检查
|
|
if (maxTempX >= 0 && maxTempX < originalImage.getWidth() &&
|
|
maxTempY >= 0 && maxTempY < originalImage.getHeight()) {
|
|
|
|
// 设置醒目的颜色
|
|
g2d.setColor(Color.RED);
|
|
g2d.setStroke(new BasicStroke(5));
|
|
|
|
// 画空心圆
|
|
int circleDiameter = 8;
|
|
g2d.drawOval(maxTempX - circleDiameter / 2, maxTempY - circleDiameter / 2,
|
|
circleDiameter, circleDiameter);
|
|
|
|
// 画十字标记
|
|
g2d.drawLine(maxTempX - 3, maxTempY, maxTempX + 3, maxTempY);
|
|
g2d.drawLine(maxTempX, maxTempY - 3, maxTempX, maxTempY + 3);
|
|
|
|
log.info("成功绘制最高温度点标记");
|
|
} else {
|
|
log.warn("最高温度点坐标超出图像范围:x={}, y={}", maxTempX, maxTempY);
|
|
}
|
|
}
|
|
} else {
|
|
log.error("画框坐标超出图片范围");
|
|
// 确保x1,y1是左上角,x2,y2是右下角
|
|
int rectX = Math.min(1, 639);
|
|
int rectY = Math.min(1, 511);
|
|
int width = Math.abs(639 - 1);
|
|
int height = Math.abs(511 - 1);
|
|
|
|
// 设置更粗的画笔(加粗矩形边框)
|
|
g2d.setStroke(new BasicStroke(3)); // 3像素宽
|
|
// 绘制矩形
|
|
g2d.drawRect(rectX, rectY, width, height);
|
|
infraPictureInfo.setFirstX(x1);
|
|
infraPictureInfo.setFirstY(y1);
|
|
infraPictureInfo.setSecondX(x2);
|
|
infraPictureInfo.setSecondY(y2);
|
|
|
|
InfraredInfo drawStringMatrix = matrixTemperatureShow(c, infraredInfo.getMatrixWidth(), infraredInfo.getMatrixHeight(), infraredInfo.getTemperatureMatrix());
|
|
infraredInfo.setFrameMax(Math.round(drawStringMatrix.getFrameMax() * 100) / 100f);
|
|
// 添加矩形标签
|
|
String line1 = "平均温度:" + String.format("%.2f", drawStringMatrix.getFrameAverage());
|
|
String line2 = "最高温度:" + String.format("%.2f", drawStringMatrix.getFrameMax());
|
|
String line3 = "最低温度:" + String.format("%.2f", drawStringMatrix.getFrameMin());
|
|
g2d.drawString(line1, rectX + 5, rectY + 15);
|
|
g2d.drawString(line2, rectX + 5, rectY + 30);
|
|
g2d.drawString(line3, rectX + 5, rectY + 45);
|
|
}
|
|
}
|
|
}
|
|
|
|
g2d.dispose();
|
|
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
|
ImageIO.write(annotatedImage, "jpg", os);
|
|
InputStream inputStream = new ByteArrayInputStream(os.toByteArray());
|
|
|
|
float[][] temperatureMatrix = infraredInfo.getTemperatureMatrix();
|
|
String csvData = convertMatrixToCsv(temperatureMatrix);
|
|
InputStream csvStream = new ByteArrayInputStream(csvData.getBytes(StandardCharsets.UTF_8));
|
|
|
|
//保存到FTP服务器
|
|
picFtp(outputPath, inputStream, ftpUrlAddress, ftpUrlPort, ftpUrlAccount, ftpUrlPwd);
|
|
picFtp(csvPath, csvStream, ftpUrlAddress, ftpUrlPort, ftpUrlAccount, ftpUrlPwd);
|
|
|
|
|
|
} catch (IOException e) {
|
|
System.err.println("处理图片时出错: " + e.getMessage());
|
|
e.printStackTrace();
|
|
}
|
|
return outputPath;
|
|
}
|
|
|
|
@Override
|
|
public AjaxResult capturePicture(InfraPictureInfo infraPictureInfo) {
|
|
|
|
return AjaxResult.success("设置成功");
|
|
}
|
|
|
|
//从ftp获取csv流转换成二维数组
|
|
|
|
//框选温度值计算
|
|
public InfraredInfo matrixTemperatureShow(Coordinate coordinate, short width, short height, float[][] temperatureMatrix) {
|
|
InfraredInfo infraredInfo = new InfraredInfo();
|
|
//存储框选矩阵温度值
|
|
List<Float> values = new ArrayList<>();
|
|
// 用于记录最高温度的坐标
|
|
int maxTempX = -1;
|
|
int maxTempY = -1;
|
|
float currentMax = Float.MIN_VALUE;
|
|
if (ObjectUtil.isNotEmpty(coordinate.getFirstX()) && ObjectUtil.isNotEmpty(coordinate.getSecondX())) {
|
|
//if (coordinate.getImgType() != 3)
|
|
// {//无人机不需要对比底图
|
|
// //倍数计算
|
|
// double xMultiple = (coordinate.getImgWidth().doubleValue() / width) * 100 / 100.0;
|
|
// double yMultiple = (coordinate.getImgHeight().doubleValue() / height) * 100 / 100.0;
|
|
//
|
|
// //比例缩放像素 获取底图温度值
|
|
// int x1 = (int) (coordinate.getFirstX() / xMultiple);
|
|
// int y1 = (int) (coordinate.getFirstY() / yMultiple);
|
|
// int x2 = (int) (coordinate.getSecondX() / xMultiple);
|
|
// int y2 = (int) (coordinate.getSecondY() / yMultiple);
|
|
// coordinate.setFirstX(x1);
|
|
// coordinate.setFirstY(y1);
|
|
// coordinate.setSecondX(x2);
|
|
// coordinate.setSecondY(y2);
|
|
// }
|
|
if (coordinate.getSecondX() != 0 && coordinate.getSecondY() != 0) {
|
|
for (int j = coordinate.getFirstY(); j <= coordinate.getSecondY(); j++) { // 列
|
|
if (j < 0 || j >= temperatureMatrix.length) continue;
|
|
for (int i = coordinate.getFirstX(); i <= coordinate.getSecondX(); i++) { // 行(固定列,遍历行)
|
|
if (i < 0 || i >= temperatureMatrix[j].length) continue;
|
|
float temp = temperatureMatrix[j][i];
|
|
values.add(temp);
|
|
|
|
if (temp > currentMax) {
|
|
currentMax = temp;
|
|
maxTempX = i;
|
|
maxTempY = j;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// 计算框选矩阵温度数值
|
|
float frameAverage = (float) values.stream().mapToDouble(f -> f).average().orElse(0);
|
|
float frameMax = (float) values.stream().mapToDouble(f -> f).max().orElse(0);
|
|
float frameMin = (float) values.stream().mapToDouble(f -> f).min().orElse(0);
|
|
|
|
// 设置最高温度坐标(如果有找到的话)
|
|
if (maxTempX != -1 && maxTempY != -1) {
|
|
infraredInfo.setMaxTempX(maxTempX);
|
|
infraredInfo.setMaxTempY(maxTempY);
|
|
log.info("最大温度坐标:{}, {}", maxTempX, maxTempY);
|
|
}
|
|
|
|
infraredInfo.setFrameAverage(frameAverage);
|
|
infraredInfo.setFrameMax(frameMax);
|
|
infraredInfo.setFrameMin(frameMin);
|
|
}
|
|
return infraredInfo;
|
|
}
|
|
|
|
//调用华软接口获取csv文件
|
|
public float[][] UploadFtpImage(String url, String type, String image) {
|
|
log.info("imageName" + image);
|
|
log.info("hrUrl" + hrUavUrl);
|
|
type = "ftp";
|
|
// OkHttpClient client = new OkHttpClient();
|
|
|
|
OkHttpClient client = new OkHttpClient.Builder()
|
|
.connectTimeout(5, TimeUnit.SECONDS) // 连接超时5秒
|
|
.readTimeout(10, TimeUnit.SECONDS) // 读取超时10秒
|
|
.writeTimeout(5, TimeUnit.SECONDS) // 写入超时5秒
|
|
.retryOnConnectionFailure(false) // 禁用自动重试
|
|
.build();
|
|
log.info("UploadFtpImage, client: {}", client);
|
|
float[][] floats = new float[0][];
|
|
try {
|
|
// 构建 multipart 请求体
|
|
RequestBody requestBody = new MultipartBody.Builder()
|
|
.setType(MultipartBody.FORM)
|
|
.addFormDataPart("type", type)
|
|
.addFormDataPart("image", image)
|
|
.build();
|
|
|
|
log.info("UploadFtpImage, url: {}", url);
|
|
// 构建请求
|
|
Request request = new Request.Builder()
|
|
.url(url)
|
|
.post(requestBody)
|
|
.addHeader("User-Agent", "Apifox/1.0.0 (https://apifox.com)")
|
|
.addHeader("Accept", "*/*")
|
|
.addHeader("Connection", "keep-alive")
|
|
.build();
|
|
|
|
log.info("UploadFtpImage, request: {}", request);
|
|
|
|
// 执行请求并处理响应
|
|
try (Response response = client.newCall(request).execute()) {
|
|
log.info("UploadFtpImage, response: {}", response);
|
|
if (!response.isSuccessful() && response.code() != 4006) {
|
|
throw new IOException("请求失败,HTTP状态码: " + response.code());
|
|
}
|
|
// if (!response.isSuccessful()) {
|
|
// throw new IOException("请求失败,HTTP状态码: " + response.code());
|
|
// }
|
|
|
|
String responseBody = response.body() != null ? response.body().string() : null;
|
|
if (responseBody == null) {
|
|
throw new IOException("响应体为空");
|
|
}
|
|
// 解析 JSON 并提取 image_raw_flow
|
|
|
|
ObjectMapper mapper = new ObjectMapper();
|
|
JsonNode jsonArray = mapper.readTree(responseBody);
|
|
if (jsonArray.isEmpty()) {
|
|
throw new RuntimeException("JSON数组为空");
|
|
}
|
|
JsonNode firstItem = jsonArray.get(0);
|
|
String imageRawFlow = firstItem.get("image_raw_flow").asText();
|
|
log.info("imageRawFlow" + imageRawFlow);
|
|
floats = parseCsvFromFtp2(imageRawFlow);
|
|
|
|
}
|
|
} catch (Exception e) {
|
|
e.printStackTrace();
|
|
System.err.println("FTP请求处理失败,尝试本地文件: " + e.getMessage());
|
|
//
|
|
return null;
|
|
}
|
|
return floats;
|
|
|
|
}
|
|
|
|
private float[][] parseCsvFromFtp2(String csvUrl) throws IOException, URISyntaxException {
|
|
log.info("连接ftp,获取csv文件");
|
|
InputStream inputStream = null;
|
|
FTPSClient ftps = null;
|
|
CSVParser csvParser = null;
|
|
try {
|
|
ftps = new FTPSClient(true);
|
|
ftps.connect(ftpUrlAddress, ftpUrlPort);
|
|
boolean loginRes = ftps.login(ftpUrlAccount, ftpUrlPwd);
|
|
if (loginRes) {
|
|
log.info("[FTP] LOGIN SUCCESS: {}", ftpUrlAddress);
|
|
}
|
|
ftps.setFileType(2);
|
|
ftps.enterLocalPassiveMode();
|
|
ftps.setControlEncoding("UTF-8");
|
|
ftps.setFileTransferMode(10);
|
|
ftps.execPROT("P");
|
|
//
|
|
URI uri = new URI(csvUrl);
|
|
String filePath = uri.getPath();
|
|
log.info("[FTP] DOWNLOAD: {}", filePath);
|
|
inputStream = ftps.retrieveFileStream(filePath);
|
|
if (inputStream == null) {
|
|
log.error("[FTP] DOWNLOAD FAIL, EMPTY STREAM: {}", filePath);
|
|
|
|
}
|
|
Reader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
|
|
csvParser = CSVFormat.DEFAULT.parse(reader);
|
|
List<CSVRecord> records = csvParser.getRecords();
|
|
|
|
// 7. 转换为 float[][]
|
|
float[][] result = new float[records.size()][];
|
|
for (int i = 0; i < records.size(); i++) {
|
|
CSVRecord record = records.get(i);
|
|
result[i] = new float[record.size()];
|
|
for (int j = 0; j < record.size(); j++) {
|
|
result[i][j] = Float.parseFloat(record.get(j));
|
|
}
|
|
}
|
|
return result;
|
|
} finally {
|
|
// 8. 确保资源关闭
|
|
IOUtils.closeQuietly(csvParser);
|
|
IOUtils.closeQuietly(inputStream);
|
|
if (ftps != null && ftps.isConnected()) {
|
|
try {
|
|
ftps.logout();
|
|
ftps.disconnect();
|
|
} catch (IOException e) {
|
|
log.error("FTP 断开连接失败", e);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//上传图片到ftp
|
|
public void picFtp(String newPath, InputStream originalPath, String ftpUrlAddress, Integer ftpUrlPort, String ftpUrlAccount, String ftpUrlPwd) {
|
|
FTPSClient ftps = null;
|
|
try {
|
|
ftps = new FTPSClient(true);
|
|
ftps.connect(ftpUrlAddress, ftpUrlPort);
|
|
boolean loginRes = ftps.login(ftpUrlAccount, ftpUrlPwd);
|
|
System.out.println(loginRes);
|
|
ftps.setFileType(2);
|
|
ftps.enterLocalPassiveMode();
|
|
ftps.setControlEncoding("UTF-8");
|
|
ftps.setFileTransferMode(10);
|
|
ftps.execPROT("P");
|
|
boolean success = ftps.storeFile(newPath, originalPath);
|
|
if (!success) {
|
|
System.err.println("上传失败!FTP 返回: " + ftps.getReplyString());
|
|
}
|
|
} catch (Exception e) {
|
|
log.error("error" + e);
|
|
} finally {
|
|
// 5. 关闭资源
|
|
try {
|
|
if (originalPath != null) originalPath.close();
|
|
if (ftps != null && ftps.isConnected()) {
|
|
ftps.logout();
|
|
ftps.disconnect();
|
|
}
|
|
} catch (IOException e) {
|
|
log.error("error" + e);
|
|
}
|
|
}
|
|
}
|
|
|
|
//ftp图片获取
|
|
public InputStream downloadFtp(String downloadPath) {
|
|
InputStream inputStream = null;
|
|
FTPSClient ftps;
|
|
try {
|
|
ftps = new FTPSClient(true);
|
|
ftps.connect(ftpUrlAddress, ftpUrlPort);
|
|
boolean loginRes = ftps.login(ftpUrlAccount, ftpUrlPwd);
|
|
System.out.println(loginRes);
|
|
ftps.setFileType(2);
|
|
ftps.enterLocalPassiveMode();
|
|
ftps.setControlEncoding("UTF-8");
|
|
ftps.setFileTransferMode(10);
|
|
ftps.execPROT("P");
|
|
inputStream = ftps.retrieveFileStream(downloadPath);
|
|
if (inputStream == null) {
|
|
System.out.println("[FTP] DOWNLOAD FAIL, EMPTY STREAM:" + downloadPath);
|
|
|
|
}
|
|
} catch (Exception e) {
|
|
log.error("error" + e);
|
|
}
|
|
return inputStream;
|
|
}
|
|
|
|
@Override
|
|
public ResponseEntity<String> irPicAnalyse(final String analyseRequestJson) {
|
|
log.info("[INFRARED] irPicAnalyse: analyseRequestJson={}", analyseRequestJson);
|
|
AnalyseRequest analyseRequest;
|
|
try {
|
|
analyseRequest = new Gson().fromJson(analyseRequestJson, AnalyseRequest.class);
|
|
} catch (Exception e) {
|
|
log.error("[INFRARED] irPicAnalyse: analyseRequestJson parse exception: {}", e.getMessage());
|
|
return ResponseEntity.ok().body("{\"code\":\"201\"}");
|
|
}
|
|
log.info("[INFRARED] irPicAnalyse: analyseRequest={}", new Gson().toJson(analyseRequest));
|
|
|
|
|
|
List<AnalyseReqItem> analyseReqItemList = analyseRequest.getObjectList();
|
|
if (analyseReqItemList == null || analyseReqItemList.isEmpty()) {
|
|
log.error("[INFRARED] irPicAnalyse: analyseReqItemList empty!");
|
|
return ResponseEntity.ok().body("{\"code\":\"202\"}");
|
|
}
|
|
|
|
final AnalyseReqItem analyseReqItem = analyseReqItemList.get(0);
|
|
final String[] typeList = analyseReqItem.getTypeList();
|
|
String algType = "unKnownType";
|
|
if (typeList != null && typeList.length != 0) {
|
|
algType = typeList[0];
|
|
}
|
|
final String feedBackHostIp = analyseRequest.getRequestHostIp();
|
|
final String feedBackPort = analyseRequest.getRequestHostPort();
|
|
final String feedbackUrl = feedBackHostIp + feedBackPort + "/picAnalyseRetNotify";
|
|
log.info("[INFRARED] irPicAnalyse: feedbackUrl={}", feedbackUrl);
|
|
String[] imageUrlList = analyseReqItem.getImageUrlList();
|
|
String[] typeListImg = analyseReqItem.getTypeList();
|
|
|
|
InfraPictureInfo infraPictureInfo = new InfraPictureInfo();
|
|
// infraPictureInfo.setChannelId();
|
|
infraPictureInfo.setImgType(typeListImg[0]);
|
|
infraPictureInfo.setFilePath(imageUrlList[0]);
|
|
|
|
//红外方法
|
|
InfraredInfo infraredInfo = calculatePicture(infraPictureInfo, "1,1,639,511,640,512");
|
|
|
|
|
|
AnalyseResult analyseResult = new AnalyseResult();
|
|
analyseResult.setRequestId(analyseRequest.getRequestId());
|
|
AnalyseResPoint analyseResPoint = new AnalyseResPoint();
|
|
// analyseResPoint.setValue("0");
|
|
// analyseResPoint.setConf("0.85");
|
|
if (String.valueOf((double) infraredInfo.getFrameMax()) != null && infraredInfo.getOutPath() != null) {
|
|
analyseResPoint.setValue("0");//成功
|
|
} else {
|
|
analyseResPoint.setValue("1");//失败
|
|
}
|
|
analyseResPoint.setConf(String.format("%.2f", (double) infraredInfo.getFrameMax()));
|
|
analyseResPoint.setResImageUrl(infraredInfo.getOutPath());
|
|
|
|
analyseResPoint.setCode("2000");
|
|
// analyseResPoint.setResImageUrl(analyseRequest.getObjectList().get(0).getImageUrlList()[0]);
|
|
List<AnalyseResPoint> analyseResPoints = new ArrayList<>();
|
|
analyseResPoints.add(analyseResPoint);
|
|
AnalyseResItem analyseResItem = new AnalyseResItem();
|
|
analyseResItem.setObjectId(analyseRequest.getObjectList().get(0).getObjectId());
|
|
analyseResItem.setAlgFactory(algType);
|
|
analyseResItem.setResults(analyseResPoints);
|
|
List<AnalyseResItem> analyseResItems = new ArrayList<>();
|
|
analyseResItems.add(analyseResItem);
|
|
analyseResult.setResultList(analyseResItems);
|
|
System.out.println("返回值打印: 是否成功(0成功;1失败)" + analyseResPoint.getValue() +
|
|
",最高温度值" + analyseResPoint.getConf() + ",返回图片路径:" + analyseResPoint.getResImageUrl());
|
|
try {
|
|
String analyseResultOutJson = JSONObject.toJSONString(analyseResult);
|
|
log.info("[INFRARED] irPicAnalyse: feedbackUrl={}, analyseResultOutJson={}", feedbackUrl, analyseResultOutJson);
|
|
// String result = HttpClientUtils.sendPostAgain(feedbackUrl, analyseResultOutJson);
|
|
// log.info("[INFRARED] irPicAnalyse: feedbackUrl={}, result: {}", feedbackUrl, result);
|
|
} catch (Exception e) {
|
|
log.info("[INFRARED] irPicAnalyse: feedbackUrl={}, EXCEPTION: {}", feedbackUrl, e.getMessage());
|
|
}
|
|
return ResponseEntity.ok().body("{\"code\":\"200\"}");
|
|
}
|
|
|
|
public InfraredInfo calculatePicture(InfraPictureInfo infraPictureInfo, String picData) {
|
|
InfraredInfo infraredInfo = new InfraredInfo();
|
|
|
|
return infraredInfo;
|
|
}
|
|
|
|
@Override
|
|
public InputStream downloadCsv(String filePath) {
|
|
log.info("解析csv图片地址" + filePath);
|
|
String updatePath = truncateFileNameToCsv(filePath);
|
|
InputStream inputStream = downloadFtp(updatePath);
|
|
if (inputStream == null) {
|
|
log.info("图片地址" + updatePath + "无返回");
|
|
}
|
|
|
|
// if (!produceEnvironment) {
|
|
// //调用华软接口
|
|
// String protocol = hrFtpUrl.substring(0, 6); // "ftp://"
|
|
// String withoutProtocol = hrFtpUrl.substring(6); // "zthr02:zthr02@123.184.14.138:50021/"
|
|
// String[] userAndHost = withoutProtocol.split("@");
|
|
// if (userAndHost.length != 2) {
|
|
// throw new IllegalArgumentException("URL 格式错误,缺少 @ 分隔符");
|
|
// }
|
|
// String[] userPass = userAndHost[0].split(":");
|
|
// String username = userPass[0];
|
|
// String password = userPass[1];
|
|
// String hostPort = userAndHost[1].replace("/", ""); // 移除末尾的 "/"
|
|
// String[] hostAndPort = hostPort.split(":");
|
|
// String host = hostAndPort[0];
|
|
// int port = Integer.parseInt(hostAndPort[1]);
|
|
// String imageName = Paths.get(filePath).getFileName().toString();
|
|
// //将图片上传到华软
|
|
// boolean isLoginHr = pic2Ftp(imageName, inputStreamPath, host, port, username, password);
|
|
// String ftpUrlName = "[\"" + hrFtpUrl + imageName + "\"]";
|
|
// if (isLoginHr) {
|
|
// //可以登陆华软ftp
|
|
// inputStream = UploadFtpImageStream(hrUavUrl, ftpUrlName);
|
|
// if (inputStream != null) {
|
|
// return inputStream;
|
|
// }
|
|
// } else {
|
|
// log.error("调用华软接口失败,使用本地1.csv文件!");
|
|
// inputStream = getClass().getClassLoader().getResourceAsStream("1.csv");
|
|
// return inputStream;
|
|
// }
|
|
// } else {
|
|
// //共用同一ftp
|
|
// String imageName = Paths.get(filePath).getFileName().toString();
|
|
// String ftpUrlName = "[\"ftp://" + ftpUrlAccount + ":" + ftpUrlPwd + "@" + ftpUrlAddress + ":" + ftpUrlPort + "/" + imageName + "\"]";
|
|
// inputStream = UploadFtpImageStream(hrUavUrl, ftpUrlName);
|
|
// if (inputStream != null) {
|
|
//
|
|
// return inputStream;
|
|
// }
|
|
// }
|
|
return inputStream;
|
|
}
|
|
|
|
// NVR跳转到预置位
|
|
public AjaxResult NvrCameraAngleJump(Camera camera) {
|
|
|
|
lUserID = (Integer) redisService.redisTemplate.opsForValue().get(camera.getIp() + "_userId");
|
|
|
|
if (ObjectUtil.isEmpty(lUserID)) {
|
|
NvrInfo nvrInfo = new NvrInfo();
|
|
nvrInfo.setNvrIp(camera.getIp());
|
|
nvrInfo.setServerPort(camera.getPort());
|
|
nvrInfo.setAccount(camera.getUserName());
|
|
nvrInfo.setPassword(camera.getPassword());
|
|
login_V40(nvrInfo);
|
|
lUserID = (Integer) redisService.redisTemplate.opsForValue().get(camera.getIp() + "_userId");
|
|
}
|
|
|
|
|
|
//参数:登录令牌,通道号,预置位跳转,跳转的预置位码
|
|
boolean gotoPreset = hcNetSDK.NET_DVR_PTZPreset_Other(lUserID, camera.getChannel(), HCNetSDK.GOTO_PRESET, camera.getPointNum());
|
|
if (!gotoPreset) {
|
|
System.out.println("获取设备预置位跳转设备参数失败,错误码:" + hcNetSDK.NET_DVR_GetLastError());
|
|
return AjaxResult.error(hcNetSDK.NET_DVR_GetErrorMsg(new IntByReference(hcNetSDK.NET_DVR_GetLastError())));
|
|
} else {
|
|
System.out.println("海康-成功跳转到预置位!");
|
|
}
|
|
|
|
return AjaxResult.success();
|
|
}
|
|
|
|
//NVR抓图
|
|
public AjaxResult NvrCameraPictrue(Camera camera) throws IOException {
|
|
|
|
lUserID = (Integer) redisService.redisTemplate.opsForValue().get(camera.getIp() + "_userId");
|
|
if (ObjectUtil.isEmpty(lUserID)) {
|
|
NvrInfo nvrInfo = new NvrInfo();
|
|
nvrInfo.setNvrIp(camera.getIp());
|
|
nvrInfo.setServerPort(camera.getPort());
|
|
nvrInfo.setAccount(camera.getUserName());
|
|
nvrInfo.setPassword(camera.getPassword());
|
|
login_V40(nvrInfo);
|
|
lUserID = (Integer) redisService.redisTemplate.opsForValue().get(camera.getIp() + "_userId");
|
|
}
|
|
|
|
HCNetSDK.NET_DVR_JPEGPARA dvrJpegpara = new HCNetSDK.NET_DVR_JPEGPARA();
|
|
dvrJpegpara.wPicSize = 3;
|
|
dvrJpegpara.wPicQuality = 0;
|
|
dvrJpegpara.write();
|
|
|
|
// 2. 创建临时存储目录(系统临时目录更安全)
|
|
Path tempDir = Paths.get(System.getProperty("java.io.tmpdir"), "hik_capture");
|
|
if (!Files.exists(tempDir)) {
|
|
Files.createDirectories(tempDir);
|
|
}
|
|
// 3. 生成唯一文件名(IP+时间戳)
|
|
String fileName = String.format("%s_%s.jpg", camera.getIp(), DateUtils.dateTimeNow("yyyyMMddHHmmss"));
|
|
Path tempImagePath = tempDir.resolve(fileName);
|
|
|
|
boolean b = hcNetSDK.NET_DVR_CaptureJPEGPicture(lUserID, camera.getChannel(), dvrJpegpara,
|
|
tempImagePath.toString().getBytes("GBK"));
|
|
if (!b) {
|
|
System.out.println("设置设备进行抓图失败,错误码:" + hcNetSDK.NET_DVR_GetLastError());
|
|
return AjaxResult.error("设置设备进行抓图失败,错误码:" + hcNetSDK.NET_DVR_GetLastError());
|
|
}
|
|
|
|
try (InputStream inputStream = Files.newInputStream(tempImagePath)) {
|
|
picFtp("/2/" + fileName,
|
|
inputStream,
|
|
ftpUrlAddress,
|
|
ftpUrlPort,
|
|
ftpUrlAccount,
|
|
ftpUrlPwd
|
|
);
|
|
} catch (Exception e) {
|
|
log.error("抓图并上传失败:{}", e.getMessage());
|
|
} finally {
|
|
// 6. 确保删除临时文件
|
|
Files.deleteIfExists(tempImagePath);
|
|
}
|
|
return AjaxResult.success();
|
|
}
|
|
|
|
|
|
//预置位获取-海康
|
|
@Override
|
|
public String cameraYzwHikVision(Camera camera) {
|
|
CameraPresetPoint cameraPreset = new CameraPresetPoint();
|
|
int lUserID = (int) redisTemplate.opsForValue().get(camera.getNvrip() + "_userId");
|
|
|
|
HCNetSDK.NET_DVR_PRESET_NAME[] presetNames = new HCNetSDK.NET_DVR_PRESET_NAME[HCNetSDK.MAX_PRESET_V30];
|
|
for (int i = 0; i < presetNames.length; i++) {
|
|
presetNames[i] = new HCNetSDK.NET_DVR_PRESET_NAME();
|
|
presetNames[i].dwSize = presetNames[i].size();
|
|
presetNames[i].write();
|
|
}
|
|
Pointer lpOutBuffer = new Memory(presetNames.length * presetNames[0].size());
|
|
int dwOutBufferSize = presetNames.length * presetNames[0].size();
|
|
IntByReference lpBytesReturned = new IntByReference(0);
|
|
|
|
//boolean NET_DVR_GetDVRConfig(int lUserID, int dwCommand, int lChannel, Pointer lpOutBuffer, int dwOutBufferSize, IntByReference lpBytesReturned);
|
|
boolean presetList = hcNetSDK.NET_DVR_GetDVRConfig(lUserID, HCNetSDK.NET_DVR_GET_PRESET_NAME, camera.getChannel(), lpOutBuffer, dwOutBufferSize, lpBytesReturned);
|
|
if (!presetList) {
|
|
System.out.println("获取预置位数据失败,错误码:" + hcNetSDK.NET_DVR_GetLastError());
|
|
} else {
|
|
|
|
ByteBuffer byteBuffer = lpOutBuffer.getByteBuffer(0, lpBytesReturned.getValue());
|
|
byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // 设置字节顺序
|
|
String presetName = "";
|
|
for (int i = 0; i < HCNetSDK.MAX_PRESET_V30; i++) {
|
|
HCNetSDK.NET_DVR_PRESET_NAME presetNameStruct = new HCNetSDK.NET_DVR_PRESET_NAME();
|
|
|
|
presetNameStruct.dwSize = byteBuffer.getInt();
|
|
presetNameStruct.wPresetNum = byteBuffer.getShort();
|
|
byteBuffer.get(presetNameStruct.byRes1); // 读取保留字节
|
|
byteBuffer.get(presetNameStruct.byName); // 读取名称
|
|
presetNameStruct.wPanPos = byteBuffer.getShort();//水平参数
|
|
presetNameStruct.wTiltPos = byteBuffer.getShort();//垂直参数
|
|
presetNameStruct.wZoomPos = byteBuffer.getShort();//变倍参数
|
|
byteBuffer.get(presetNameStruct.byRes); // 读取保留字节
|
|
if (presetNameStruct.wPresetNum != 0)
|
|
// 输出预置位数据
|
|
{
|
|
try {
|
|
if (Integer.valueOf(presetNameStruct.wPanPos) != 0 && Integer.valueOf(presetNameStruct.wTiltPos) != 0) {
|
|
presetName = presetName + new String(presetNameStruct.byName, "GBK").trim() + ":" + presetNameStruct.wPresetNum + ",";
|
|
}
|
|
System.out.println("预置位 " + presetNameStruct.wPresetNum + " 名称:" + new String(presetNameStruct.byName, "GBK").trim());
|
|
} catch (UnsupportedEncodingException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
|
|
}
|