作者 钟来

模块整理

正在显示 22 个修改的文件 包含 1138 行增加124 行删除
... ... @@ -81,7 +81,7 @@ public class YudadaGrabTask {
fishPriceCollection.setCollection_source("鱼大大");
fishPriceCollection.setCollection_data(fishObject.toString());
if(maxTime>time)
if(maxTime>=time)
{
pageNo = -1;
break;
... ... @@ -92,7 +92,10 @@ public class YudadaGrabTask {
logger.error("数据解析错误:"+jsonArray.get(i).toString(),e);
}
}
if(null != fishPriceCollectionList && fishPriceCollectionList.size() !=0 )
{
publicService.insertAll(fishPriceCollectionList);
}
}
}
... ...
package com.zhonglai.luhui.device.analysis.comm.agreement;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.zhonglai.luhui.device.analysis.comm.factory.BusinessAgreement;
import com.zhonglai.luhui.device.analysis.comm.factory.BusinessAgreementFactory;
import com.zhonglai.luhui.device.analysis.comm.factory.Topic;
... ...
... ... @@ -37,6 +37,7 @@ public class CacheServiceImpl implements CacheService {
@Override
public boolean updateCache(Topic topic, ServerDto serverDto) {
IotDevice iotDevice = serverDto.getIotDevice();
if(null == iotDevice)
{
... ...
package com.zhonglai.luhui.mqtt;
import com.zhonglai.luhui.mqtt.comm.service.TerminalService;
import com.zhonglai.luhui.mqtt.service.ClienNoticeService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
... ... @@ -10,10 +13,10 @@ import org.springframework.context.annotation.ComponentScan;
@ComponentScan(basePackages = {
"com.zhonglai.luhui.device.analysis",
"com.zhonglai.luhui.mqtt.service",
"com.zhonglai.luhui.mqtt.comm.service",
"com.zhonglai.luhui.mqtt.comm.rocketMq",
"com.zhonglai.luhui.mqtt.config",
"com.zhonglai.luhui.mqtt.service",
"com.zhonglai.luhui.mqtt.controller",
})
@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class})
... ... @@ -24,7 +27,6 @@ public class MqttApplication {
log.info("启动服务");
SpringApplicationBuilder builder = new SpringApplicationBuilder(MqttApplication.class);
builder.run( args);
}
}
... ...
... ... @@ -6,6 +6,7 @@ import com.zhonglai.luhui.device.analysis.comm.dto.business.BusinessDtoClassNew;
import com.zhonglai.luhui.device.analysis.comm.service.CacheService;
import com.zhonglai.luhui.device.analysis.comm.service.DataPersistenceService;
import com.zhonglai.luhui.device.analysis.comm.util.ByteUtil;
import com.zhonglai.luhui.device.analysis.dto.topic.OnlineDto;
import com.zhonglai.luhui.device.domain.IotDevice;
import com.zhonglai.luhui.device.analysis.comm.factory.BusinessAgreement;
import com.zhonglai.luhui.device.analysis.comm.factory.BusinessAgreementFactory;
... ... @@ -104,6 +105,14 @@ public class MqttCallback implements MqttCallbackExtended {
BusinessAgreement businessAgreement = businessAgreementFactory.createBusinessAgreement(topic);
//解析为业务对象
ServerDto dto = businessAgreement.analysis(topic,businessAgreement.toData(businessDto));
if(dto instanceof OnlineDto)
{
OnlineDto onlineDto = (OnlineDto) dto;
if(1!=onlineDto.getState()) //离线
{
return;
}
}
if(null == dto)
{
terminalService.publish(TopicUtil.generateSendMessageTopic(topic),"2");
... ...
... ... @@ -46,7 +46,7 @@ mqtt:
clientId: ${random.uuid}
#公司id
roleid: 2
mqtt_usernames: 6_WP
mqtt_usernames: 6_WP,12_BPQ,10_TLJ,NWDB_2023,WLJ_1,YWB_A700E,12_ZNZY
#订阅的topic
topics: ADD_POST,ALL_POST,DB_TOPIC_DISTRIBUTE,GET/+,online,PUT_REQ/+,READ_REQ/+
sub_clientid: '+'
... ...
... ... @@ -33,5 +33,9 @@
<artifactId>slf4j-simple</artifactId>
</dependency>
<dependency>
<groupId>com.zhonglai.luhui</groupId>
<artifactId>ruoyi-common</artifactId>
</dependency>
</dependencies>
</project>
\ No newline at end of file
... ...
package com.zhonglai.luhui.smart.feeder.pureness.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
public class SysConfig {
private static final Logger log = LoggerFactory.getLogger(SysConfig.class);
private static Map<String,String> map = new HashMap<>();
private void loadconfig(String configpath) throws IOException {
log.info("加载系统配置文件:{}",configpath);
Properties p = new Properties();
//创建一个字节输入流对象读取文件默认在当前项目下查找
FileInputStream in = new FileInputStream(configpath);
//Properties类的load()方法进行配置文件的加载
p.load(in);
for(String key:p.stringPropertyNames())
{
p.getProperty(key);
}
}
public static String sys_srs_push_address;
public static String sys_mp4_file_path;
public static String mqtt_broke;
public static String mqtt_clientId;
public static String mqtt_topics;
public static String mqtt_username;
public static String mqtt_password;
public static String mqtt_client_operationTime;
}
... ...
package com.zhonglai.luhui.smart.feeder.pureness.service;
import cn.hutool.json.JSONObject;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.utils.ip.IpUtils;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.FileInputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
public class TerminalService {
private static final Logger log = LoggerFactory.getLogger(TerminalService.class);
private MqttClient mqttclient;
private MqttConnectOptions options;
private MqttCallback mqttCallback;
private String broker;
private String clientId;
private List<String> topics;
private List<String> mqtt_usernames;
private String username;
private String password;
public void startMqttListenerService() throws MqttException {
log.info("-----------开始启动mqtt监听服务--------------------");
init();
... ... @@ -39,11 +40,11 @@ public class TerminalService {
Map<String,Object> dmap = new HashMap<>();
Map<String,Object> map = new HashMap<>();
dmap.put("summary",map);
// map.put("localhostIp",IpUtils.getLocalHost());
map.put("localhostIp", IpUtils.getLocalHost());
JSONObject jsonObject = new JSONObject();
jsonObject.put("0",dmap);
String topic = "ADD_POST";
// publish(topic,jsonObject.toJSONString());
publish(topic,jsonObject.toJSONString());
}
... ... @@ -99,4 +100,5 @@ public class TerminalService {
log.error("关闭失败",e);
}
}
}
... ...
sys.srs_push_address=rtmp://119.23.218.181:21935/live/${mqtt.clientId}
sys.mp4_file_path=D:/lh-smart-feeder/2.mp4
mqtt.broker=tcp://175.24.61.68:1883
mqtt.clientId=70094a59d1d991d
mqtt.topics=PUT/+,GET_REQ/+, READ/+,POST_REQ/+
mqtt.username=12_ZNZY
mqtt.password=Luhui586
mqtt.client.operationTime=10
\ No newline at end of file
... ...
package com.zhonglai.luhui.smart.feeder.dto;
import org.bytedeco.javacv.OpenCVFrameConverter;
import org.opencv.core.Mat;
import java.io.Serializable;
... ... @@ -11,6 +12,16 @@ public class VeiwDto implements Serializable {
private Integer size; //面积大小
private Double absValue; //变化的斜率
private Integer push_camera;
public Integer getPush_camera() {
return push_camera;
}
public void setPush_camera(Integer push_camera) {
this.push_camera = push_camera;
}
public VeiwDto(Mat frame, Integer size) {
this.frame = frame;
this.size = size;
... ...
... ... @@ -6,6 +6,7 @@ import com.zhonglai.luhui.smart.feeder.dto.VeiwDto;
import com.zhonglai.luhui.smart.feeder.service.CameraService;
import com.zhonglai.luhui.smart.feeder.service.impl.HtmllVeiwServiceImpl;
import com.zhonglai.luhui.smart.feeder.service.impl.JFrameVeiwServiceImpl;
import org.bytedeco.javacv.FrameGrabber;
import org.opencv.core.*;
import org.opencv.highgui.HighGui;
import org.opencv.videoio.VideoCapture;
... ... @@ -13,6 +14,7 @@ import org.opencv.imgproc.Imgproc;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
... ... @@ -24,74 +26,49 @@ public class OpenCVUtil {
public static void main(String[] args) {
System.out.println(DESUtil.decode("5F06AAC657B2E2B287289D25D950A829", "EXU5RUhI1"));;
// OpenCVConfig.loadOpenCv(args);
// VideoCapture videoCapture = OpenCVUtil.readVideoCaptureForVideo(0);
// // 检查视频是否成功打开
// if (!videoCapture.isOpened()) {
// System.out.println("无法打开视频文件");
// return;
// }
//
// Mat previousFrame = new Mat();
// if (!videoCapture.read(previousFrame)) {
// System.out.println("无法读取视频帧");
// return;
// }
//
// JFrameVeiwServiceImpl dsplayVeiwService = new JFrameVeiwServiceImpl();
// // 逐帧处理视频
// Mat frame = new Mat();
// while (videoCapture.read(frame)) {
// dsplayVeiwService.veiw(new VeiwDto(frame,null,null));
// try {
// String str = new HtmllVeiwServiceImpl().matToString(frame,"jpg");
// System.out.println(str);
// } catch (IOException e) {
// throw new RuntimeException(e);
// }
// }
}
public static VideoCapture readVideoCaptureForVideo(int i)
{
logger.info("初始化摄像头");
// 创建VideoCapture对象
VideoCapture videoCapture = new VideoCapture();
try {
Thread.sleep(1000);
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
VideoCapture videoCapture = new VideoCapture();
boolean isopen = videoCapture.open(i);
if(isopen)
{
logger.info("打开化摄像头"+i+"成功");
return videoCapture;
}
}else {
logger.info("打开化摄像头"+i+"失败");
}
return null;
}
private static final String MP4_FILE_PATH = "D:/lh-smart-feeder/mp4/2.mp4";
public static VideoCapture openCapture()
{
for(int i=0;i<10;i++)
{
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
VideoCapture videoCapture = readVideoCaptureForVideo(i);
if(null != videoCapture)
{
return videoCapture; //拿到的第一个摄像头返回
}
VideoCapture videoCapture = new VideoCapture();
boolean isopen = videoCapture.open(i);
if(isopen)
}
logger.info("未检测到摄像头{},尝试打开本地视频",MP4_FILE_PATH);
//如果找不到摄像头就找本地视频文件
File file = new File(MP4_FILE_PATH);
if(file.exists() && file.isFile())
{
logger.info("打开化摄像头"+i+"成功");
VideoCapture videoCapture = OpenCVUtil.readVideoCaptureForVideo(MP4_FILE_PATH);
return videoCapture;
}else {
logger.info("打开化摄像头"+i+"失败");
}
}
throw new RuntimeException("未检测到摄像头");
logger.info("未检测到摄像头!!!");
return null;
}
public static VideoCapture readVideoCaptureForVideo(String videoPath )
... ...
package com.zhonglai.luhui.smart.feeder.opencv;
import lombok.extern.slf4j.Slf4j;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.ffmpeg.global.avutil;
import org.bytedeco.javacpp.Loader;
import org.bytedeco.javacv.*;
import org.bytedeco.opencv.opencv_core.IplImage;
import org.bytedeco.opencv.presets.opencv_objdetect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.*;
/**
* @author will
* @email zq2599@gmail.com
* @date 2021/11/19 8:07 上午
* @description 功能介绍
*/
public class PushCamera {
private static final Logger log = LoggerFactory.getLogger(PushCamera.class);
/**
* 保存MP4文件的完整路径(两分零五秒的视频)
*/
private static final String MP4_FILE_PATH = "/Users/zhaoqin/temp/202111/21/camera.mp4";
/**
* SRS的推流地址
*/
private static final String SRS_PUSH_ADDRESS = "rtmp://192.168.50.43:11935/live/livestream";
/**
* 摄像头序号,如果只有一个摄像头,那就是0
*/
private static final int CAMERA_INDEX = 0;
/**
* 本机窗口
*/
private CanvasFrame previewCanvas;
/**
* 帧抓取器
*/
private FrameGrabber grabber;
/**
* 帧录制器
*/
private FrameRecorder recorder;
/**
* 转换类
*/
private OpenCVFrameConverter.ToIplImage converter;
/**
* 输出帧率
*/
private static final double FRAME_RATE = 30.0;
/**
* 摄像头视频的宽
*/
private int cameraImageWidth;
/**
* 摄像头视频的高
*/
private int cameraImageHeight;
/**
* 每一次从摄像头抓取的帧都暂存在这里
*/
private IplImage grabbedImage;
/**
* 初始化帧抓取器
* @throws Exception
*/
private void initGrabber() throws Exception {
// 本机摄像头默认0,这里使用javacv的抓取器,至于使用的是ffmpeg还是opencv,请自行查看源码
grabber = FrameGrabber.createDefault(CAMERA_INDEX);
// 开启抓取器
grabber.start();
}
/**
* 初始化帧录制器
* @throws Exception
*/
private void initRecorder() throws Exception {
// 实例化帧录制器
recorder = FrameRecorder.createDefault(SRS_PUSH_ADDRESS, cameraImageWidth, cameraImageHeight);
// 设置编码器
recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
// 封装格式
recorder.setFormat("flv");
// 设置帧录制器的帧率
recorder.setFrameRate(FRAME_RATE);
// 初始化帧录制器
recorder.start();
}
/**
* 初始化转换器
* @throws Exception
*/
private void initConverter() throws Exception {
// 实例化转换器
converter = new OpenCVFrameConverter.ToIplImage();
// 抓取一帧视频并将其转换为图像,至于用这个图像用来做什么?加水印,人脸识别等等自行添加
grabbedImage = converter.convert(grabber.grab());
// 将视频图像的宽度存储在成员变量cameraImageWidth
cameraImageWidth = grabbedImage.width();
// 将视频图像的高度存储在成员变量cameraImageHeight
cameraImageHeight = grabbedImage.height();
}
/**
* 实例化、初始化窗口
*/
private void initWindow() {
previewCanvas = new CanvasFrame("摄像头预览", CanvasFrame.getDefaultGamma() / grabber.getGamma());
previewCanvas.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
previewCanvas.setAlwaysOnTop(true);
}
/**
* 预览和推送
* @throws Exception
*/
private void grabAndPush() throws Exception {
// 假设一秒钟15帧,那么两帧间隔就是(1000/15)毫秒
double interVal = 1000/ FRAME_RATE;
// 发送完一帧后sleep的时间,不能完全等于(1000/frameRate),不然会卡顿,
// 要更小一些,这里取八分之一
interVal/=8.0;
// 不知道为什么这里不做转换就不能推到rtmp
Frame rotatedFrame;
long startTime = System.currentTimeMillis();
while ((grabbedImage = converter.convert(grabber.grab())) != null) {
rotatedFrame = converter.convert(grabbedImage);
// 预览窗口上显示当前帧
// previewCanvas.showImage(rotatedFrame);
// 推送的时候,给当前帧加上时间戳
recorder.setTimestamp(1000 * (System.currentTimeMillis() - startTime));
// 推送到SRS
recorder.record(rotatedFrame);
Thread.sleep((int)interVal);
}
}
/**
* 释放所有资源
* @throws Exception
*/
private void safeRelease() {
if (null!= previewCanvas) {
previewCanvas.dispose();
}
if (null!=recorder) {
try {
recorder.close();
} catch (Exception exception) {
log.error("close recorder error", exception);
}
}
if (null!=grabber) {
try {
grabber.close();
} catch (Exception exception) {
log.error("close grabber error", exception);
}
}
}
/**
* 整合了所有初始化操作
* @throws Exception
*/
private void init() throws Exception {
long startTime = System.currentTimeMillis();
// 设置ffmepg日志级别
avutil.av_log_set_level(avutil.AV_LOG_INFO);
FFmpegLogCallback.set();
// 加载检测
Loader.load(opencv_objdetect.class);
// 实例化、初始化帧抓取器
initGrabber();
// 实例化、初始化转换工具,里面会取得摄像头图像的宽度和高度
initConverter();
// 实例化、初始化帧录制器
initRecorder();
// 实例化、初始化窗口
// initWindow();
log.info("初始化完成,耗时[{}]毫秒,图像宽度[{}],图像高度[{}]",
System.currentTimeMillis()-startTime,
cameraImageWidth,
cameraImageWidth);
}
/**
* 直播
*/
public void live() {
try {
// 初始化操作
init();
// 持续拉取和推送
grabAndPush();
} catch (Exception exception) {
log.error("execute live error", exception);
} finally {
// 无论如何都要释放资源
safeRelease();
}
}
public static void main(String[] args) {
new PushCamera().live();
}
}
\ No newline at end of file
... ...
package com.zhonglai.luhui.smart.feeder.opencv;
import lombok.extern.slf4j.Slf4j;
import org.bytedeco.ffmpeg.avcodec.AVCodecParameters;
import org.bytedeco.ffmpeg.avformat.AVFormatContext;
import org.bytedeco.ffmpeg.avformat.AVStream;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.ffmpeg.global.avutil;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.FFmpegLogCallback;
import org.bytedeco.javacv.Frame;
/**
* @author willzhao
* @version 1.0
* @description 读取指定的mp4文件,推送到SRS服务器
* @date 2021/11/19 8:49
*/
@Slf4j
public class PushMp4 {
/**
* 本地MP4文件的完整路径(两分零五秒的视频)
*/
// private static final String MP4_FILE_PATH = "/Users/zhaoqin/temp/202111/20/sample-mp4-file.mp4";
private static final String MP4_FILE_PATH = "C:\\Users\\123\\Videos\\抖音\\莱堃科技\\20230901\\f3bb11df0711125aefdd9a16e67323fb.mp4";
/**
* SRS的推流地址
*/
private static final String SRS_PUSH_ADDRESS = "rtmp://119.23.218.181:21935/live/f3bb11df0711125aefdd9a16e67323fb";
/**
* 读取指定的mp4文件,推送到SRS服务器
* @param sourceFilePath 视频文件的绝对路径
* @param PUSH_ADDRESS 推流地址
* @throws Exception
*/
private static void grabAndPush(String sourceFilePath, String PUSH_ADDRESS) throws Exception {
// ffmepg日志级别
avutil.av_log_set_level(avutil.AV_LOG_INFO);
FFmpegLogCallback.set();
// 实例化帧抓取器对象,将文件路径传入
FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(MP4_FILE_PATH);
long startTime = System.currentTimeMillis();
log.info("开始初始化帧抓取器");
// 初始化帧抓取器,例如数据结构(时间戳、编码器上下文、帧对象等),
// 如果入参等于true,还会调用avformat_find_stream_info方法获取流的信息,放入AVFormatContext类型的成员变量oc中
grabber.start(true);
log.info("帧抓取器初始化完成,耗时[{}]毫秒", System.currentTimeMillis()-startTime);
// grabber.start方法中,初始化的解码器信息存在放在grabber的成员变量oc中
AVFormatContext avFormatContext = grabber.getFormatContext();
// 文件内有几个媒体流(一般是视频流+音频流)
int streamNum = avFormatContext.nb_streams();
// 没有媒体流就不用继续了
if (streamNum<1) {
log.error("文件内不存在媒体流");
return;
}
// 取得视频的帧率
int frameRate = (int)grabber.getVideoFrameRate();
log.info("视频帧率[{}],视频时长[{}]秒,媒体流数量[{}]",
frameRate,
avFormatContext.duration()/1000000,
avFormatContext.nb_streams());
// 遍历每一个流,检查其类型
for (int i=0; i< streamNum; i++) {
AVStream avStream = avFormatContext.streams(i);
AVCodecParameters avCodecParameters = avStream.codecpar();
log.info("流的索引[{}],编码器类型[{}],编码器ID[{}]", i, avCodecParameters.codec_type(), avCodecParameters.codec_id());
}
// 视频宽度
int frameWidth = grabber.getImageWidth();
// 视频高度
int frameHeight = grabber.getImageHeight();
// 音频通道数量
int audioChannels = grabber.getAudioChannels();
log.info("视频宽度[{}],视频高度[{}],音频通道数[{}]",
frameWidth,
frameHeight,
audioChannels);
// 实例化FFmpegFrameRecorder,将SRS的推送地址传入
FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(SRS_PUSH_ADDRESS,
frameWidth,
frameHeight,
audioChannels);
// 设置编码格式
recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
// 设置封装格式
recorder.setFormat("flv");
// 一秒内的帧数
recorder.setFrameRate(frameRate);
// 两个关键帧之间的帧数
recorder.setGopSize(frameRate);
// 设置音频通道数,与视频源的通道数相等
recorder.setAudioChannels(grabber.getAudioChannels());
startTime = System.currentTimeMillis();
log.info("开始初始化帧抓取器");
// 初始化帧录制器,例如数据结构(音频流、视频流指针,编码器),
// 调用av_guess_format方法,确定视频输出时的封装方式,
// 媒体上下文对象的内存分配,
// 编码器的各项参数设置
recorder.start();
log.info("帧录制初始化完成,耗时[{}]毫秒", System.currentTimeMillis()-startTime);
Frame frame;
startTime = System.currentTimeMillis();
log.info("开始推流");
long videoTS = 0;
int videoFrameNum = 0;
int audioFrameNum = 0;
int dataFrameNum = 0;
// 假设一秒钟15帧,那么两帧间隔就是(1000/15)毫秒
int interVal = 1000/frameRate;
// 发送完一帧后sleep的时间,不能完全等于(1000/frameRate),不然会卡顿,
// 要更小一些,这里取八分之一
interVal/=8;
// 持续从视频源取帧
while (null!=(frame=grabber.grab())) {
videoTS = 1000 * (System.currentTimeMillis() - startTime);
// 时间戳
// recorder.setTimestamp(videoTS);
// 有图像,就把视频帧加一
if (null!=frame.image) {
videoFrameNum++;
}
// 有声音,就把音频帧加一
if (null!=frame.samples) {
audioFrameNum++;
}
// 有数据,就把数据帧加一
if (null!=frame.data) {
dataFrameNum++;
}
// 取出的每一帧,都推送到SRS
recorder.record(frame);
// 停顿一下再推送
Thread.sleep(interVal);
}
log.info("推送完成,视频帧[{}],音频帧[{}],数据帧[{}],耗时[{}]秒",
videoFrameNum,
audioFrameNum,
dataFrameNum,
(System.currentTimeMillis()-startTime)/1000);
// 关闭帧录制器
recorder.close();
// 关闭帧抓取器
grabber.close();
}
public static void main(String[] args) throws Exception {
grabAndPush(MP4_FILE_PATH, SRS_PUSH_ADDRESS);
}
}
... ...
... ... @@ -2,17 +2,21 @@ package com.zhonglai.luhui.smart.feeder.service;
import com.zhonglai.luhui.smart.feeder.dto.ConfigurationParameter;
import com.zhonglai.luhui.smart.feeder.opencv.OpenCVUtil;
import org.bytedeco.javacv.FrameGrabber;
import org.opencv.videoio.VideoCapture;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.net.DatagramSocket;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.io.IOException;
/**
* 摄像头
*/
... ... @@ -118,4 +122,125 @@ public class CameraService {
return videoIsOpen;
}
public static void main(String[] args) throws Exception{
MulticastSocket socket = null;
try {
// 创建 MulticastSocket 对象
socket = new MulticastSocket();
// 指定多播地址和端口
InetAddress group = InetAddress.getByName("239.255.255.250");
int port = 37020;
while (true)
{
// 创建要发送的消息
String message = "<?xml version=\"1.0\" encoding=\"utf-8\"?><Probe><Uuid>B0F5E9C7-EBD5-4A03-99F7-B069B141C619</Uuid><Types>inquiry</Types></Probe>";
byte[] buffer = message.getBytes();
// 创建 DatagramPacket 对象
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, group, port);
// 发送数据包
socket.send(packet);
Thread.sleep(10000);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (socket != null) {
socket.close();
}
}
}
private static void sendclien()
{
try {
// 创建组播Socket
MulticastSocket multicastSocket = new MulticastSocket();
// 创建组播地址
InetAddress group = InetAddress.getByName("239.255.255.250");
// 发送消息
String message = "<?xml version=\"1.0\" encoding=\"utf-8\"?><Probe><Uuid>B0F5E9C7-EBD5-4A03-99F7-B069B141C619</Uuid><Types>inquiry</Types></Probe>";
byte[] buffer = message.getBytes();
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, group, 37020);
multicastSocket.send(packet);
// 关闭Socket
multicastSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void onClien()
{
DatagramSocket socket = null;
try {
// 创建 DatagramSocket 对象,监听指定的端口
socket = new DatagramSocket(37020);
while (true) {
// 创建 DatagramPacket 对象,用于接收数据
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
// 接收数据
socket.receive(packet);
// 转换并打印接收到的数据
String received = new String(packet.getData(), 0, packet.getLength());
System.out.println("Received data: " + received);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (socket != null) {
socket.close();
}
}
}
public static void clien()
{
try {
// 创建组播Socket
MulticastSocket multicastSocket = new MulticastSocket(37020);
// 加入组播地址
InetAddress group = InetAddress.getByName("239.255.255.250");
multicastSocket.joinGroup(group);
boolean isip = true;
while (isip)
{
// 接收消息
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
multicastSocket.receive(packet);
// 处理消息
String message = new String(packet.getData(), packet.getOffset(), packet.getLength());
System.out.println("Received: " + message);
if(message.indexOf("ip")>=0)
{
isip = false;
}
}
// 关闭Socket
multicastSocket.leaveGroup(group);
multicastSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
... ...
... ... @@ -8,9 +8,11 @@ import com.zhonglai.luhui.smart.feeder.Main;
import com.zhonglai.luhui.smart.feeder.dto.ConfigurationParameter;
import com.zhonglai.luhui.smart.feeder.dto.ModbusDto;
import com.zhonglai.luhui.smart.feeder.dto.StateData;
import com.zhonglai.luhui.smart.feeder.dto.VeiwDto;
import com.zhonglai.luhui.smart.feeder.dto.commd.FeederCommd03Response;
import com.zhonglai.luhui.smart.feeder.dto.commd.FeederCommdDto;
import com.zhonglai.luhui.smart.feeder.util.FeederCommdUtil;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
... ... @@ -43,15 +45,46 @@ public class DateListenService {
@Autowired
private ConfigurationParameterService configurationParameterService;
@Autowired
private FishGroupImageRecognitionService fishGroupImageRecognitionService;
public void run()
{
scheduledExecutorService.scheduleAtFixedRate(() -> {
try {
gatherDevice0();
Thread.sleep(1000);
} catch (MqttException e) {
logger.error("采集主机信息失败",e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
try {
gatherDevice1();
Thread.sleep(1000);
} catch (MqttException e) {
logger.error("采集投料机数据失败",e);
}catch (InterruptedException e) {
throw new RuntimeException(e);
}
try {
gatherDevice2();
} catch (MqttException e) {
logger.error("采集摄像头信息失败",e);
}
},1,60, TimeUnit.SECONDS);
}
/**
* 采集投料机数据
*/
private void gatherDevice1() throws MqttException {
if(null == configurationParameterService.getConfig(ConfigurationParameter.ifUpLoadData) || !(Boolean) configurationParameterService.getConfig(ConfigurationParameter.ifUpLoadData))
{
return;
}
try {
ModbusDto modbusDto = serialPortService.sendHexData(FeederCommdUtil.readAll());
Map<String,Object> data = analysisDataService.analysis(modbusDto);
if(null != data && data.size() != 0)
... ... @@ -60,14 +93,41 @@ public class DateListenService {
configurationParameterService.setStateData(stateData);
JSONObject jsonObject = new JSONObject();
jsonObject.put("1",data);
terminalService.scheduledSubmissionData(jsonObject.toJSONString());
jsonObject.put("10_1",data);
String topic = "ALL_POST";
terminalService.publish(topic,jsonObject.toJSONString());
}
} catch (Exception e) {
logger.error("数据采集失败",e);
}
},1,60, TimeUnit.SECONDS);
/**
* 采集主机信息
*/
private void gatherDevice0() throws MqttException {
Map<String, Object> map = configurationParameterService.getAll();
if(null != map && map.size() !=0)
{
JSONObject jsonObject = new JSONObject();
jsonObject.put("0",map);
String topic = "ADD_POST";
terminalService.publish(topic,jsonObject.toJSONString());
}
}
/**
* 采集摄像头信息
*/
private void gatherDevice2() throws MqttException {
VeiwDto veiwDto = fishGroupImageRecognitionService.getVeiwDto();
if(null != veiwDto && BeanUtil.isNotEmpty(veiwDto,"size","absValue"))
{
veiwDto = BeanUtil.copyProperties(veiwDto,VeiwDto.class,"frame","binaryImage");
JSONObject jsonObject = new JSONObject();
jsonObject.put("1_1",veiwDto);
String topic = "ALL_POST";
terminalService.publish(topic,jsonObject.toJSONString());
}
}
}
... ...
... ... @@ -6,8 +6,6 @@ import com.zhonglai.luhui.smart.feeder.dto.VeiwDto;
import com.zhonglai.luhui.smart.feeder.dto.VeiwType;
import com.zhonglai.luhui.smart.feeder.opencv.OpenCVUtil;
import com.zhonglai.luhui.smart.feeder.service.impl.HtmllVeiwServiceImpl;
import com.zhonglai.luhui.smart.feeder.service.impl.JFrameVeiwServiceImpl;
import io.swagger.models.auth.In;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
import org.opencv.core.Scalar;
... ... @@ -19,12 +17,10 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
/**
... ... @@ -37,9 +33,6 @@ public class FishGroupImageRecognitionService {
@Autowired
private CameraService cameraService;
private DisplayVeiwService dsplayVeiwService;
@Autowired
private ScheduledExecutorService scheduledExecutorService;
... ... @@ -49,43 +42,29 @@ public class FishGroupImageRecognitionService {
@Autowired
private DeviceService deviceService;
private static Boolean isRun = false;
private VeiwDto veiwDto;
public void run()
{
scheduledExecutorService.scheduleWithFixedDelay(() -> {
if (!isRun)
{
start(VeiwType.html);
start();
}
},1,1,TimeUnit.SECONDS);
}
public void start(VeiwType veiwType)
public void start()
{
if(cameraService.getVideoIsOpen()) //摄像头打开才能识别
{
isRun = true;
configurationParameterService.setConfig(ConfigurationParameter.FishGroupImageRecognition,true);
switch (veiwType)
{
case html:
dsplayVeiwService = new HtmllVeiwServiceImpl(configurationParameterService);
break;
case jfram:
dsplayVeiwService = new JFrameVeiwServiceImpl(configurationParameterService);
break;
default:
dsplayVeiwService = new HtmllVeiwServiceImpl(configurationParameterService);
break;
}
VideoCapture videoCapture = cameraService.getVideoCapture();
brightnessIdentifyFishRegion(videoCapture);
}else {
logger.info("摄像头未打开");
}
}
... ... @@ -123,7 +102,6 @@ public class FishGroupImageRecognitionService {
return largestContour;
}
/**
* 亮度查找水面,透明度过滤鱼群
*/
... ... @@ -140,7 +118,7 @@ public class FishGroupImageRecognitionService {
// 获取水域轮廓
MatOfPoint largestContour = getDefaultMatOfPoint(previousFrame);
Long time =1000l;
Long time =66l;
if(null != configurationParameterService.getConfig(ConfigurationParameter.IdentificationFrequency))
{
time = (Long) configurationParameterService.getConfig(ConfigurationParameter.IdentificationFrequency);
... ... @@ -148,6 +126,7 @@ public class FishGroupImageRecognitionService {
// 逐帧处理视频
Mat frame = new Mat();
scheduledExecutorService.scheduleWithFixedDelay(() -> {
try {
Boolean fishGroupImageRecognition = ((Boolean)configurationParameterService.getConfig(ConfigurationParameter.FishGroupImageRecognition));
Boolean isread = videoCapture.read(frame);
logger.info("逐帧处理视频,开始处理的判断参数:鱼群图像识别是否开启 {}、摄像头是否可读取 {}",fishGroupImageRecognition,isread);
... ... @@ -165,11 +144,14 @@ public class FishGroupImageRecognitionService {
if (fishGroupImageRecognition && isread) {
identify(frame,largestContour);
}
},0,time, TimeUnit.MILLISECONDS);
}catch (Exception e)
{
logger.error("识别错误",e);
}
},0,time, TimeUnit.MILLISECONDS);
}
/**
* 识别
... ... @@ -206,13 +188,15 @@ public class FishGroupImageRecognitionService {
double absValue = deviceService.controlDevice(area);
configurationParameterService.setConfig(ConfigurationParameter.absValue,absValue);
veiwDto = new VeiwDto(frame,binaryImage,new Double(area).intValue(),absValue);
// 显示图像
logger.info("是否显示{},客户端数量{}",configurationParameterService.getConfig(ConfigurationParameter.ifVeiw),WebSocketClien.webSocketSet.size());
// 在图像上显示结果
logger.info("socket数量{}",WebSocketClien.webSocketSet.size());
if((Boolean)configurationParameterService.getConfig(ConfigurationParameter.ifVeiw) && WebSocketClien.webSocketSet.size()>0)
{
logger.info("socket数量{}",WebSocketClien.webSocketSet.size());
dsplayVeiwService.veiw(new VeiwDto(frame,binaryImage,new Double(area).intValue(),absValue));
new HtmllVeiwServiceImpl(configurationParameterService).veiw(veiwDto);
}
}
... ... @@ -267,4 +251,12 @@ public class FishGroupImageRecognitionService {
return binaryImage;
}
public VeiwDto getVeiwDto() {
return veiwDto;
}
public void setVeiwDto(VeiwDto veiwDto) {
this.veiwDto = veiwDto;
}
}
... ...
... ... @@ -3,38 +3,52 @@ package com.zhonglai.luhui.smart.feeder.service;
import com.google.gson.JsonObject;
import com.ruoyi.common.utils.GsonConstructor;
import com.zhonglai.luhui.smart.feeder.domain.Register;
import com.zhonglai.luhui.smart.feeder.dto.ConfigDto;
import com.zhonglai.luhui.smart.feeder.dto.VeiwDto;
import com.zhonglai.luhui.smart.feeder.dto.commd.FeederCommd06Response;
import com.zhonglai.luhui.smart.feeder.dto.commd.FeederCommdDto;
import com.zhonglai.luhui.smart.feeder.dto.commd.FeederTimer;
import com.zhonglai.luhui.smart.feeder.util.FeederCommdUtil;
import com.zhonglai.luhui.smart.feeder.util.PenetrateUtil;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.*;
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.stereotype.Component;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
@Component
public class MqttCallback implements MqttCallbackExtended {
private static final Logger log = LoggerFactory.getLogger(MqttCallback.class);
@Autowired
private ConfigurationParameterService configurationParameterService;
@Autowired
private SerialPortService serialPortService;
private static final Logger log = LoggerFactory.getLogger(MqttCallback.class);
@Autowired
private SrsService srsService;
private MqttClient mqttclient;
@Value("#{'${mqtt.topics}'.split(',')}")
private List<String> topics;
@Override
public void connectComplete(boolean b, String s) {
log.info("连接成功");
try {
subscribe();
} catch (MqttException e) {
throw new RuntimeException(e);
}
}
@Override
... ... @@ -42,6 +56,12 @@ public class MqttCallback implements MqttCallbackExtended {
log.error("连接丢失",cause);
}
public MqttCallback setMqttClient(MqttClient mqttclient)
{
this.mqttclient = mqttclient;
return this;
}
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
log.info("收到消息 {}",message);
... ... @@ -53,9 +73,9 @@ public class MqttCallback implements MqttCallbackExtended {
{
String str = new String(bs);
JsonObject jsonObject = GsonConstructor.get().fromJson(str, JsonObject.class);
if(jsonObject.has("1"))
if(jsonObject.has("10_1")) //投料机控制
{
JsonObject controlData = jsonObject.get("1").getAsJsonObject();
JsonObject controlData = jsonObject.get("10_1").getAsJsonObject();
Map<Integer, FeederTimer> timerMap = new HashMap<>();
for (String key:controlData.keySet())
... ... @@ -85,24 +105,23 @@ public class MqttCallback implements MqttCallbackExtended {
}
}
}
else if(jsonObject.has("armbian"))
else if(jsonObject.has("0")) //主机
{
JsonObject armbian = jsonObject.get("armbian").getAsJsonObject();
for (String key:armbian.keySet())
ConfigDto configDto = GsonConstructor.get().fromJson(jsonObject.get("0").toString(),ConfigDto.class);
configurationParameterService.setConfig(configDto.getConfigurationParameter(),configDto.getValue());
}
else if(jsonObject.has("1_1")) //探头
{
switch (key)
VeiwDto veiwDto = GsonConstructor.get().fromJson(jsonObject.get("1_1").toString(),VeiwDto.class);
if(null != veiwDto.getPush_camera())
{
case "penetrate":
int penetrate = armbian.get("penetrate").getAsInt();
switch (penetrate)
switch (veiwDto.getPush_camera())
{
case 0:
PenetrateUtil.stop();
srsService.stop();
break;
case 1:
PenetrateUtil.start();
break;
}
srsService.run(300);
break;
}
}
... ... @@ -117,4 +136,8 @@ public class MqttCallback implements MqttCallbackExtended {
// 成功发出消息
log.info("成功发出消息 messageid{}",token);
}
private void subscribe() throws MqttException {
mqttclient.subscribe(topics.toArray(new String[topics.size()]));
}
}
... ...
package com.zhonglai.luhui.smart.feeder.service;
import com.ruoyi.common.utils.DateUtils;
import com.zhonglai.luhui.smart.feeder.config.OpenCVConfig;
import com.zhonglai.luhui.smart.feeder.draw.FishRegionPanel;
import com.zhonglai.luhui.smart.feeder.dto.VeiwDto;
import com.zhonglai.luhui.smart.feeder.opencv.OpenCVUtil;
import com.zhonglai.luhui.smart.feeder.util.OpenCVUtils;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.javacv.*;
import org.bytedeco.javacv.Frame;
import org.opencv.core.*;
import org.opencv.core.Point;
import org.opencv.imgproc.Imgproc;
import org.opencv.videoio.VideoCapture;
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.stereotype.Service;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@Service
public class SrsService {
private static final Logger log = LoggerFactory.getLogger(SrsService.class);
private static final String MP4_FILE_PATH = "C:\\Users\\123\\Pictures\\2.mp4";
@Value("${sys.srs_push_address}")
private String SRS_PUSH_ADDRESS;
// private String SRS_PUSH_ADDRESS="rtmp://119.23.218.181:21935/live/70094a59d1d991d";
@Autowired
private ScheduledExecutorService scheduledExecutorService;
@Autowired
private FishGroupImageRecognitionService fishGroupImageRecognitionService;
private FFmpegFrameRecorder recorder;
private OpenCVFrameConverter.ToMat converter = new OpenCVFrameConverter.ToMat();
public Frame getOpencvFrame(Mat frame)
{
return converter.convert(frame);
}
private boolean isPush = false;
private int endTime = 0;
public void run(int time) throws Exception {
endTime = DateUtils.getNowTimeMilly()+time;
if(!isPush)
{
VeiwDto veiwDto = fishGroupImageRecognitionService.getVeiwDto();
init(veiwDto.getFrame().width(),veiwDto.getFrame().height()+200);
scheduledExecutorService.schedule(() -> {
while (endTime-DateUtils.getNowTimeMilly()>0)
{
Mat mat = drawChart(fishGroupImageRecognitionService.getVeiwDto().getFrame(),fishGroupImageRecognitionService.getVeiwDto().getAbsValue());
push(mat);
}
stop();
},1, TimeUnit.SECONDS);
}
}
public void stop()
{
endTime = 0;
isPush =false;
close();
}
public SrsService init(int frameWidth,int frameHeight) throws Exception
{
log.info("视频宽度[{}],视频高度[{}]",
frameWidth,
frameHeight
);
// 实例化FFmpegFrameRecorder,将SRS的推送地址传入
recorder = new FFmpegFrameRecorder(SRS_PUSH_ADDRESS,
frameWidth,
frameHeight);
// 设置编码格式
recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
// 设置封装格式
recorder.setFormat("flv");
// 初始化帧录制器,例如数据结构(音频流、视频流指针,编码器),
// 调用av_guess_format方法,确定视频输出时的封装方式,
// 媒体上下文对象的内存分配,
// 编码器的各项参数设置
recorder.start();
return this;
}
public Mat drawChart(Mat src,double area)
{
// 创建一个新的Mat对象,它的高度为200,它的宽度与原来的Mat对象相同
Mat curveArea = Mat.zeros(200, src.cols(), src.type());
// 计算曲线的y坐标
int y = (int) (200 - (area * 200) / (src.cols() * src.rows()));
System.out.println(y);
// 声明曲线的控制点
MatOfPoint curve = new MatOfPoint();
// 创建曲线的控制点数组
List<Point> points = addPoint(curveArea,area);
// 将控制点数组设置给曲线
Point[] pointArray = points.toArray(new Point[0]);
curve.fromArray(pointArray);
// 绘制曲线
List<MatOfPoint> curveList = new ArrayList<>();
curveList.add(curve);
Imgproc.polylines(curveArea, curveList, false, new Scalar(255, 255, 255), 2);
// 将curveArea拼接到原来的Mat对象上
Mat pushmat = new Mat();
List<Mat> mats = new ArrayList<>();
mats.add(src);
mats.add(curveArea);
Core.vconcat(mats, pushmat);
return pushmat;
}
public void push(Mat pushmat) {
OpenCVFrameConverter.ToMat converter = new OpenCVFrameConverter.ToMat();
Frame frame = converter.convert(pushmat);
push(frame);
}
public void push(Frame frame) {
// 取出的每一帧,都推送到SRS
try {
recorder.record(frame);
} catch (FrameRecorder.Exception e) {
throw new RuntimeException(e);
}
}
public void close()
{
if(null != recorder)
{
// 关闭帧录制器
try {
recorder.close();
} catch (FrameRecorder.Exception e) {
throw new RuntimeException(e);
}
recorder = null;
}
}
// 创建一个MatOfPoint对象来表示曲线
private List<Integer> listArea = new ArrayList<>();
/**
* 根据反光查找水面
* @return
*/
public Mat fish(Mat src) {
//读取和预处理图像
Mat gray = new Mat();
Imgproc.cvtColor(src, gray, Imgproc.COLOR_BGR2GRAY); // 转为灰度图像
//水面反射检测
Mat threshold = new Mat();
double maxValue = 255; // 阈值
Imgproc.threshold(gray, threshold,100, maxValue, Imgproc.THRESH_BINARY); // 阈值化
//鱼群检测
Mat hierarchy = new Mat();
List<MatOfPoint> contours = new ArrayList<>();
Imgproc.findContours(threshold, contours, hierarchy, Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE); // 寻找轮廓
//计算鱼群区域大小
double area = getArea(contours);
Mat mat = drawChart(src,area);
return mat;
}
private static Image convertMatToImage(Mat mat) {
BufferedImage bufferedImage = OpenCVUtils.matToBufferedImage(mat);
return bufferedImage.getScaledInstance(mat.width(), mat.height(), Image.SCALE_SMOOTH);
}
int maxSize = 100;
private List<Point> addPoint(Mat src, double area)
{
int panelWidth = src.width();
int panelHeight = src.height();
if(listArea.size()==maxSize)
{
listArea.remove(0);
}
int max = new Double(area).intValue();
int min = new Double(area).intValue();
if(listArea.size()>0)
{
max = listArea.stream().max(Integer::compare).get();
min = listArea.stream().min(Integer::compare).get();
}
List<Point> points= new ArrayList<>();
for (int i = 0; i < listArea.size(); i++) {
int dataPoint = listArea.get(i);
int x = (int) ((double) i / listArea.size() * panelWidth);
int y = (int) ((double) (dataPoint - min) / (max - min) * panelHeight);
if (i != 0) {
points.add(new Point(x,y));
}
}
listArea.add(new Double(area).intValue());
return points;
}
/**
* 计算鱼群面积
* @param contours
* @return
*/
private double getArea(List<MatOfPoint> contours) {
// 找到最大区域
double maxArea = 0;
int maxAreaIndex = -1;
double allArea = 0;
for (int i = 0; i < contours.size(); i++) {
double area = Imgproc.contourArea(contours.get(i));
if (area > maxArea) {
maxArea = area;
maxAreaIndex = i;
}
allArea += area;
}
//删除最大
if(-1 != maxAreaIndex)
{
contours.remove(maxAreaIndex);
}
// 返回总面积
return allArea;
}
public static void main(String[] args) {
OpenCVConfig.loadOpenCv(args);
SrsService srsService = new SrsService();
FishRegionPanel fishRegionPanel = new FishRegionPanel();
int i=0;
while (i++<10)
{
VideoCapture videoCapture = OpenCVUtil.readVideoCaptureForVideo("");
Mat previousFrame = new Mat();
if (!videoCapture.read(previousFrame)) {
System.out.println("无法读取视频帧");
return;
}
try {
if(null == srsService.recorder || !srsService.recorder.isInterleaved())
{
srsService.init(previousFrame.width(),previousFrame.height());
}
} catch (Exception e) {
throw new RuntimeException(e);
}
Mat src = new Mat();
while (videoCapture.read(src))
{
Mat mat = srsService.fish(src);
fishRegionPanel.getLblImage().setIcon(new ImageIcon(convertMatToImage(mat)));
fishRegionPanel.getFrame().repaint();
OpenCVFrameConverter.ToMat converter = new OpenCVFrameConverter.ToMat();
Frame frame = converter.convert(mat);
srsService.push(frame);
}
}
srsService.close();
}
}
... ...
... ... @@ -37,13 +37,6 @@ public class TerminalService {
@Value("${mqtt.clientId}")
private String clientId;
@Value("#{'${mqtt.topics}'.split(',')}")
private List<String> topics;
@Value("#{'${mqtt.mqtt_usernames}'.split(',')}")
private List<String> mqtt_usernames;
@Value("${mqtt.username}")
private String username;
@Value("${mqtt.password}")
... ... @@ -53,7 +46,6 @@ public class TerminalService {
log.info("-----------开始启动mqtt监听服务--------------------");
init();
connect();
subscribe();
Map<String,Object> dmap = new HashMap<>();
Map<String,Object> map = new HashMap<>();
... ... @@ -76,7 +68,7 @@ public class TerminalService {
options.setConnectionTimeout(15);
//设置断开后重新连接
options.setAutomaticReconnect(true);
mqttclient.setCallback(mqttCallback);
mqttclient.setCallback(mqttCallback.setMqttClient(mqttclient));
}
private void connect() throws MqttException {
... ... @@ -85,10 +77,6 @@ public class TerminalService {
mqttclient.connect(options);
}
public void subscribe() throws MqttException {
mqttclient.subscribe(topics.toArray(new String[topics.size()]));
}
public void publish(String topic, MqttMessage message) throws MqttException {
mqttclient.publish(topic,message);
}
... ... @@ -118,4 +106,5 @@ public class TerminalService {
log.error("关闭失败",e);
}
}
}
... ...
package com.zhonglai.luhui.smart.feeder.service.impl;
import com.zhonglai.luhui.smart.feeder.dto.VeiwDto;
import com.zhonglai.luhui.smart.feeder.service.ConfigurationParameterService;
import com.zhonglai.luhui.smart.feeder.service.DisplayVeiwService;
public class SrsVeiwServiceImpl implements DisplayVeiwService {
private ConfigurationParameterService configurationParameterService;
public SrsVeiwServiceImpl(ConfigurationParameterService configurationParameterService) {
this.configurationParameterService = configurationParameterService;
}
@Override
public void veiw(VeiwDto veiwDto) {
}
}
... ...
# 开发环境配置 server: # 服务器的HTTP端口,默认为8080 port: 8064 servlet: # 应用的访问路径 context-path: / tomcat: # tomcat的URI编码 uri-encoding: UTF-8 # 连接数满后的排队数,默认为100 accept-count: 1000 threads: # tomcat最大线程数,默认为200 max: 800 # Tomcat启动初始化的线程数,默认值10 min-spare: 100 # 日志配置 logging: level: com.ruoyi: debug org.springframework: warn # Swagger配置 swagger: # 是否开启swagger enabled: true # 请求前缀 pathMapping: /dev-api # 防止XSS攻击 xss: # 过滤开关 enabled: true # 排除链接(多个用逗号分隔) excludes: /system/notice # 匹配链接 urlPatterns: /system/*,/monitor/*,/tool/* sys: staticPath: "file:/opt/lh-smart-feeder/lh-smart-feeder/html/" # MyBatis配置 mybatis: # 搜索指定包别名 typeAliasesPackage: com.ruoyi.**.domain,com.zhonglai.**.domain # 配置mapper的扫描,找到所有的mapper.xml映射文件 mapperLocations: classpath*:mapper/**/*Mapper.xml # 加载全局的配置文件 configLocation: classpath:mybatis/mybatis-config.xml # 数据源配置 spring: # autoconfigure: # exclude: org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration datasource: type: com.alibaba.druid.pool.DruidDataSource driverClassName: org.sqlite.JDBC druid: # 主库数据源 master: url: jdbc:sqlite:db/my.db username: password: # 从库数据源 slave: # 从数据源开关/默认关闭 enabled: false url: username: password: # 初始连接数 initialSize: 5 # 最小连接池数量 minIdle: 10 # 最大连接池数量 maxActive: 20 # 配置获取连接等待超时的时间 maxWait: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 timeBetweenEvictionRunsMillis: 60000 # 配置一个连接在池中最小生存的时间,单位是毫秒 minEvictableIdleTimeMillis: 300000 # 配置一个连接在池中最大生存的时间,单位是毫秒 maxEvictableIdleTimeMillis: 900000 # 配置检测连接是否有效 validationQuery: SELECT 1 testWhileIdle: true testOnBorrow: false testOnReturn: false webStatFilter: enabled: true statViewServlet: enabled: true # 设置白名单,不填则允许所有访问 allow: url-pattern: /druid/* # 控制台管理用户名和密码 login-username: ruoyi login-password: 123456 filter: stat: enabled: true # 慢SQL记录 log-slow-sql: true slow-sql-millis: 1000 merge-sql: true wall: config: multi-statement-allow: true ## 数据源配置 #spring: # datasource: # type: com.alibaba.druid.pool.DruidDataSource # driverClassName: com.mysql.cj.jdbc.Driver # druid: # # 主库数据源 # master: # url: jdbc:mysql://rm-wz9740un21f09iokuao.mysql.rds.aliyuncs.com:3306/mqtt_broker?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 # username: luhui # password: Luhui586 # # 从库数据源 # slave: # # 从数据源开关/默认关闭 # enabled: true # url: jdbc:mysql://119.23.218.181:3306/lh-server-ops?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 # username: luhui # password: Luhui586 # # 初始连接数 # initialSize: 5 # # 最小连接池数量 # minIdle: 10 # # 最大连接池数量 # maxActive: 20 # # 配置获取连接等待超时的时间 # maxWait: 60000 # # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 # timeBetweenEvictionRunsMillis: 60000 # # 配置一个连接在池中最小生存的时间,单位是毫秒 # minEvictableIdleTimeMillis: 300000 # # 配置一个连接在池中最大生存的时间,单位是毫秒 # maxEvictableIdleTimeMillis: 900000 # # 配置检测连接是否有效 # validationQuery: SELECT 1 FROM DUAL # testWhileIdle: true # testOnBorrow: false # testOnReturn: false # webStatFilter: # enabled: true # statViewServlet: # enabled: true # # 设置白名单,不填则允许所有访问 # allow: # url-pattern: /druid/* # # 控制台管理用户名和密码 # login-username: ruoyi # login-password: 123456 # filter: # stat: # enabled: true # # 慢SQL记录 # log-slow-sql: true # slow-sql-millis: 1000 # merge-sql: true # wall: # config: # multi-statement-allow: true mqtt: #链接地址 broker: tcp://175.24.61.68:1883 #唯一标识 clientId: 70094a59d1d991d #公司id roleid: 2 mqtt_usernames: 12_ZNZY #订阅的topic topics: PUT/+,GET_REQ/+, READ/+,POST_REQ/+ username: 12_ZNZY password: Luhui586 client: #客户端操作时间 operationTime: 10
\ No newline at end of file
# 开发环境配置 server: # 服务器的HTTP端口,默认为8080 port: 8064 servlet: # 应用的访问路径 context-path: / tomcat: # tomcat的URI编码 uri-encoding: UTF-8 # 连接数满后的排队数,默认为100 accept-count: 1000 threads: # tomcat最大线程数,默认为200 max: 800 # Tomcat启动初始化的线程数,默认值10 min-spare: 100 # 日志配置 logging: level: com.ruoyi: debug org.springframework: warn # Swagger配置 swagger: # 是否开启swagger enabled: true # 请求前缀 pathMapping: /dev-api # 防止XSS攻击 xss: # 过滤开关 enabled: true # 排除链接(多个用逗号分隔) excludes: /system/notice # 匹配链接 urlPatterns: /system/*,/monitor/*,/tool/* sys: staticPath: "file:/opt/lh-smart-feeder/lh-smart-feeder/html/" srs_push_address: rtmp://119.23.218.181:21935/live/${mqtt.clientId} mp4_file_path: D:/lh-smart-feeder/2.mp4 # MyBatis配置 mybatis: # 搜索指定包别名 typeAliasesPackage: com.ruoyi.**.domain,com.zhonglai.**.domain # 配置mapper的扫描,找到所有的mapper.xml映射文件 mapperLocations: classpath*:mapper/**/*Mapper.xml # 加载全局的配置文件 configLocation: classpath:mybatis/mybatis-config.xml # 数据源配置 spring: # autoconfigure: # exclude: org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration datasource: type: com.alibaba.druid.pool.DruidDataSource driverClassName: org.sqlite.JDBC druid: # 主库数据源 master: url: jdbc:sqlite:db/my.db username: password: # 从库数据源 slave: # 从数据源开关/默认关闭 enabled: false url: username: password: # 初始连接数 initialSize: 5 # 最小连接池数量 minIdle: 10 # 最大连接池数量 maxActive: 20 # 配置获取连接等待超时的时间 maxWait: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 timeBetweenEvictionRunsMillis: 60000 # 配置一个连接在池中最小生存的时间,单位是毫秒 minEvictableIdleTimeMillis: 300000 # 配置一个连接在池中最大生存的时间,单位是毫秒 maxEvictableIdleTimeMillis: 900000 # 配置检测连接是否有效 validationQuery: SELECT 1 testWhileIdle: true testOnBorrow: false testOnReturn: false webStatFilter: enabled: true statViewServlet: enabled: true # 设置白名单,不填则允许所有访问 allow: url-pattern: /druid/* # 控制台管理用户名和密码 login-username: ruoyi login-password: 123456 filter: stat: enabled: true # 慢SQL记录 log-slow-sql: true slow-sql-millis: 1000 merge-sql: true wall: config: multi-statement-allow: true mqtt: #链接地址 broker: tcp://175.24.61.68:1883 #唯一标识 clientId: 70094a59d1d991d #订阅的topic topics: PUT/+,GET_REQ/+, READ/+,POST_REQ/+ username: 12_ZNZY password: Luhui586 client: #客户端操作时间 operationTime: 10
\ No newline at end of file
... ...