正在显示
22 个修改的文件
包含
1138 行增加
和
124 行删除
| @@ -81,7 +81,7 @@ public class YudadaGrabTask { | @@ -81,7 +81,7 @@ public class YudadaGrabTask { | ||
| 81 | fishPriceCollection.setCollection_source("鱼大大"); | 81 | fishPriceCollection.setCollection_source("鱼大大"); |
| 82 | fishPriceCollection.setCollection_data(fishObject.toString()); | 82 | fishPriceCollection.setCollection_data(fishObject.toString()); |
| 83 | 83 | ||
| 84 | - if(maxTime>time) | 84 | + if(maxTime>=time) |
| 85 | { | 85 | { |
| 86 | pageNo = -1; | 86 | pageNo = -1; |
| 87 | break; | 87 | break; |
| @@ -92,7 +92,10 @@ public class YudadaGrabTask { | @@ -92,7 +92,10 @@ public class YudadaGrabTask { | ||
| 92 | logger.error("数据解析错误:"+jsonArray.get(i).toString(),e); | 92 | logger.error("数据解析错误:"+jsonArray.get(i).toString(),e); |
| 93 | } | 93 | } |
| 94 | } | 94 | } |
| 95 | + if(null != fishPriceCollectionList && fishPriceCollectionList.size() !=0 ) | ||
| 96 | + { | ||
| 95 | publicService.insertAll(fishPriceCollectionList); | 97 | publicService.insertAll(fishPriceCollectionList); |
| 98 | + } | ||
| 96 | 99 | ||
| 97 | } | 100 | } |
| 98 | } | 101 | } |
| 1 | package com.zhonglai.luhui.device.analysis.comm.agreement; | 1 | package com.zhonglai.luhui.device.analysis.comm.agreement; |
| 2 | 2 | ||
| 3 | +import com.ruoyi.common.utils.bean.BeanUtils; | ||
| 3 | import com.zhonglai.luhui.device.analysis.comm.factory.BusinessAgreement; | 4 | import com.zhonglai.luhui.device.analysis.comm.factory.BusinessAgreement; |
| 4 | import com.zhonglai.luhui.device.analysis.comm.factory.BusinessAgreementFactory; | 5 | import com.zhonglai.luhui.device.analysis.comm.factory.BusinessAgreementFactory; |
| 5 | import com.zhonglai.luhui.device.analysis.comm.factory.Topic; | 6 | import com.zhonglai.luhui.device.analysis.comm.factory.Topic; |
| @@ -37,6 +37,7 @@ public class CacheServiceImpl implements CacheService { | @@ -37,6 +37,7 @@ public class CacheServiceImpl implements CacheService { | ||
| 37 | 37 | ||
| 38 | @Override | 38 | @Override |
| 39 | public boolean updateCache(Topic topic, ServerDto serverDto) { | 39 | public boolean updateCache(Topic topic, ServerDto serverDto) { |
| 40 | + | ||
| 40 | IotDevice iotDevice = serverDto.getIotDevice(); | 41 | IotDevice iotDevice = serverDto.getIotDevice(); |
| 41 | if(null == iotDevice) | 42 | if(null == iotDevice) |
| 42 | { | 43 | { |
| 1 | package com.zhonglai.luhui.mqtt; | 1 | package com.zhonglai.luhui.mqtt; |
| 2 | 2 | ||
| 3 | +import com.zhonglai.luhui.mqtt.comm.service.TerminalService; | ||
| 4 | +import com.zhonglai.luhui.mqtt.service.ClienNoticeService; | ||
| 3 | import org.slf4j.Logger; | 5 | import org.slf4j.Logger; |
| 4 | import org.slf4j.LoggerFactory; | 6 | import org.slf4j.LoggerFactory; |
| 7 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; | 8 | import org.springframework.boot.autoconfigure.SpringBootApplication; |
| 6 | import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; | 9 | import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; |
| 7 | import org.springframework.boot.builder.SpringApplicationBuilder; | 10 | import org.springframework.boot.builder.SpringApplicationBuilder; |
| @@ -10,10 +13,10 @@ import org.springframework.context.annotation.ComponentScan; | @@ -10,10 +13,10 @@ import org.springframework.context.annotation.ComponentScan; | ||
| 10 | 13 | ||
| 11 | @ComponentScan(basePackages = { | 14 | @ComponentScan(basePackages = { |
| 12 | "com.zhonglai.luhui.device.analysis", | 15 | "com.zhonglai.luhui.device.analysis", |
| 16 | + "com.zhonglai.luhui.mqtt.service", | ||
| 13 | "com.zhonglai.luhui.mqtt.comm.service", | 17 | "com.zhonglai.luhui.mqtt.comm.service", |
| 14 | "com.zhonglai.luhui.mqtt.comm.rocketMq", | 18 | "com.zhonglai.luhui.mqtt.comm.rocketMq", |
| 15 | "com.zhonglai.luhui.mqtt.config", | 19 | "com.zhonglai.luhui.mqtt.config", |
| 16 | - "com.zhonglai.luhui.mqtt.service", | ||
| 17 | "com.zhonglai.luhui.mqtt.controller", | 20 | "com.zhonglai.luhui.mqtt.controller", |
| 18 | }) | 21 | }) |
| 19 | @SpringBootApplication(exclude= {DataSourceAutoConfiguration.class}) | 22 | @SpringBootApplication(exclude= {DataSourceAutoConfiguration.class}) |
| @@ -24,7 +27,6 @@ public class MqttApplication { | @@ -24,7 +27,6 @@ public class MqttApplication { | ||
| 24 | log.info("启动服务"); | 27 | log.info("启动服务"); |
| 25 | SpringApplicationBuilder builder = new SpringApplicationBuilder(MqttApplication.class); | 28 | SpringApplicationBuilder builder = new SpringApplicationBuilder(MqttApplication.class); |
| 26 | builder.run( args); | 29 | builder.run( args); |
| 27 | - | ||
| 28 | } | 30 | } |
| 29 | 31 | ||
| 30 | } | 32 | } |
| @@ -6,6 +6,7 @@ import com.zhonglai.luhui.device.analysis.comm.dto.business.BusinessDtoClassNew; | @@ -6,6 +6,7 @@ import com.zhonglai.luhui.device.analysis.comm.dto.business.BusinessDtoClassNew; | ||
| 6 | import com.zhonglai.luhui.device.analysis.comm.service.CacheService; | 6 | import com.zhonglai.luhui.device.analysis.comm.service.CacheService; |
| 7 | import com.zhonglai.luhui.device.analysis.comm.service.DataPersistenceService; | 7 | import com.zhonglai.luhui.device.analysis.comm.service.DataPersistenceService; |
| 8 | import com.zhonglai.luhui.device.analysis.comm.util.ByteUtil; | 8 | import com.zhonglai.luhui.device.analysis.comm.util.ByteUtil; |
| 9 | +import com.zhonglai.luhui.device.analysis.dto.topic.OnlineDto; | ||
| 9 | import com.zhonglai.luhui.device.domain.IotDevice; | 10 | import com.zhonglai.luhui.device.domain.IotDevice; |
| 10 | import com.zhonglai.luhui.device.analysis.comm.factory.BusinessAgreement; | 11 | import com.zhonglai.luhui.device.analysis.comm.factory.BusinessAgreement; |
| 11 | import com.zhonglai.luhui.device.analysis.comm.factory.BusinessAgreementFactory; | 12 | import com.zhonglai.luhui.device.analysis.comm.factory.BusinessAgreementFactory; |
| @@ -104,6 +105,14 @@ public class MqttCallback implements MqttCallbackExtended { | @@ -104,6 +105,14 @@ public class MqttCallback implements MqttCallbackExtended { | ||
| 104 | BusinessAgreement businessAgreement = businessAgreementFactory.createBusinessAgreement(topic); | 105 | BusinessAgreement businessAgreement = businessAgreementFactory.createBusinessAgreement(topic); |
| 105 | //解析为业务对象 | 106 | //解析为业务对象 |
| 106 | ServerDto dto = businessAgreement.analysis(topic,businessAgreement.toData(businessDto)); | 107 | ServerDto dto = businessAgreement.analysis(topic,businessAgreement.toData(businessDto)); |
| 108 | + if(dto instanceof OnlineDto) | ||
| 109 | + { | ||
| 110 | + OnlineDto onlineDto = (OnlineDto) dto; | ||
| 111 | + if(1!=onlineDto.getState()) //离线 | ||
| 112 | + { | ||
| 113 | + return; | ||
| 114 | + } | ||
| 115 | + } | ||
| 107 | if(null == dto) | 116 | if(null == dto) |
| 108 | { | 117 | { |
| 109 | terminalService.publish(TopicUtil.generateSendMessageTopic(topic),"2"); | 118 | terminalService.publish(TopicUtil.generateSendMessageTopic(topic),"2"); |
| @@ -46,7 +46,7 @@ mqtt: | @@ -46,7 +46,7 @@ mqtt: | ||
| 46 | clientId: ${random.uuid} | 46 | clientId: ${random.uuid} |
| 47 | #公司id | 47 | #公司id |
| 48 | roleid: 2 | 48 | roleid: 2 |
| 49 | - mqtt_usernames: 6_WP | 49 | + mqtt_usernames: 6_WP,12_BPQ,10_TLJ,NWDB_2023,WLJ_1,YWB_A700E,12_ZNZY |
| 50 | #订阅的topic | 50 | #订阅的topic |
| 51 | topics: ADD_POST,ALL_POST,DB_TOPIC_DISTRIBUTE,GET/+,online,PUT_REQ/+,READ_REQ/+ | 51 | topics: ADD_POST,ALL_POST,DB_TOPIC_DISTRIBUTE,GET/+,online,PUT_REQ/+,READ_REQ/+ |
| 52 | sub_clientid: '+' | 52 | sub_clientid: '+' |
| @@ -33,5 +33,9 @@ | @@ -33,5 +33,9 @@ | ||
| 33 | <artifactId>slf4j-simple</artifactId> | 33 | <artifactId>slf4j-simple</artifactId> |
| 34 | </dependency> | 34 | </dependency> |
| 35 | 35 | ||
| 36 | + <dependency> | ||
| 37 | + <groupId>com.zhonglai.luhui</groupId> | ||
| 38 | + <artifactId>ruoyi-common</artifactId> | ||
| 39 | + </dependency> | ||
| 36 | </dependencies> | 40 | </dependencies> |
| 37 | </project> | 41 | </project> |
| 1 | +package com.zhonglai.luhui.smart.feeder.pureness.config; | ||
| 2 | + | ||
| 3 | +import org.slf4j.Logger; | ||
| 4 | +import org.slf4j.LoggerFactory; | ||
| 5 | + | ||
| 6 | +import java.io.FileInputStream; | ||
| 7 | +import java.io.IOException; | ||
| 8 | +import java.util.HashMap; | ||
| 9 | +import java.util.Map; | ||
| 10 | +import java.util.Properties; | ||
| 11 | + | ||
| 12 | +public class SysConfig { | ||
| 13 | + private static final Logger log = LoggerFactory.getLogger(SysConfig.class); | ||
| 14 | + private static Map<String,String> map = new HashMap<>(); | ||
| 15 | + | ||
| 16 | + private void loadconfig(String configpath) throws IOException { | ||
| 17 | + log.info("加载系统配置文件:{}",configpath); | ||
| 18 | + Properties p = new Properties(); | ||
| 19 | + //创建一个字节输入流对象读取文件默认在当前项目下查找 | ||
| 20 | + FileInputStream in = new FileInputStream(configpath); | ||
| 21 | + //Properties类的load()方法进行配置文件的加载 | ||
| 22 | + p.load(in); | ||
| 23 | + | ||
| 24 | + for(String key:p.stringPropertyNames()) | ||
| 25 | + { | ||
| 26 | + | ||
| 27 | + p.getProperty(key); | ||
| 28 | + | ||
| 29 | + } | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + public static String sys_srs_push_address; | ||
| 33 | + public static String sys_mp4_file_path; | ||
| 34 | + | ||
| 35 | + public static String mqtt_broke; | ||
| 36 | + public static String mqtt_clientId; | ||
| 37 | + public static String mqtt_topics; | ||
| 38 | + public static String mqtt_username; | ||
| 39 | + public static String mqtt_password; | ||
| 40 | + public static String mqtt_client_operationTime; | ||
| 41 | + | ||
| 42 | + | ||
| 43 | +} |
| 1 | package com.zhonglai.luhui.smart.feeder.pureness.service; | 1 | package com.zhonglai.luhui.smart.feeder.pureness.service; |
| 2 | 2 | ||
| 3 | -import cn.hutool.json.JSONObject; | 3 | +import com.alibaba.fastjson.JSONObject; |
| 4 | +import com.ruoyi.common.utils.ip.IpUtils; | ||
| 4 | import org.eclipse.paho.client.mqttv3.*; | 5 | import org.eclipse.paho.client.mqttv3.*; |
| 5 | import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; | 6 | import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; |
| 6 | 7 | ||
| 7 | import org.slf4j.Logger; | 8 | import org.slf4j.Logger; |
| 8 | import org.slf4j.LoggerFactory; | 9 | import org.slf4j.LoggerFactory; |
| 9 | 10 | ||
| 11 | +import java.io.FileInputStream; | ||
| 10 | import java.util.HashMap; | 12 | import java.util.HashMap; |
| 11 | import java.util.List; | 13 | import java.util.List; |
| 12 | import java.util.Map; | 14 | import java.util.Map; |
| 15 | +import java.util.Properties; | ||
| 13 | 16 | ||
| 14 | public class TerminalService { | 17 | public class TerminalService { |
| 15 | private static final Logger log = LoggerFactory.getLogger(TerminalService.class); | 18 | private static final Logger log = LoggerFactory.getLogger(TerminalService.class); |
| 16 | 19 | ||
| 17 | private MqttClient mqttclient; | 20 | private MqttClient mqttclient; |
| 18 | private MqttConnectOptions options; | 21 | private MqttConnectOptions options; |
| 19 | - | ||
| 20 | private MqttCallback mqttCallback; | 22 | private MqttCallback mqttCallback; |
| 21 | - | ||
| 22 | private String broker; | 23 | private String broker; |
| 23 | private String clientId; | 24 | private String clientId; |
| 24 | - | ||
| 25 | private List<String> topics; | 25 | private List<String> topics; |
| 26 | 26 | ||
| 27 | - | ||
| 28 | private List<String> mqtt_usernames; | 27 | private List<String> mqtt_usernames; |
| 29 | 28 | ||
| 30 | private String username; | 29 | private String username; |
| 31 | private String password; | 30 | private String password; |
| 32 | 31 | ||
| 32 | + | ||
| 33 | + | ||
| 33 | public void startMqttListenerService() throws MqttException { | 34 | public void startMqttListenerService() throws MqttException { |
| 34 | log.info("-----------开始启动mqtt监听服务--------------------"); | 35 | log.info("-----------开始启动mqtt监听服务--------------------"); |
| 35 | init(); | 36 | init(); |
| @@ -39,11 +40,11 @@ public class TerminalService { | @@ -39,11 +40,11 @@ public class TerminalService { | ||
| 39 | Map<String,Object> dmap = new HashMap<>(); | 40 | Map<String,Object> dmap = new HashMap<>(); |
| 40 | Map<String,Object> map = new HashMap<>(); | 41 | Map<String,Object> map = new HashMap<>(); |
| 41 | dmap.put("summary",map); | 42 | dmap.put("summary",map); |
| 42 | -// map.put("localhostIp",IpUtils.getLocalHost()); | 43 | + map.put("localhostIp", IpUtils.getLocalHost()); |
| 43 | JSONObject jsonObject = new JSONObject(); | 44 | JSONObject jsonObject = new JSONObject(); |
| 44 | jsonObject.put("0",dmap); | 45 | jsonObject.put("0",dmap); |
| 45 | String topic = "ADD_POST"; | 46 | String topic = "ADD_POST"; |
| 46 | -// publish(topic,jsonObject.toJSONString()); | 47 | + publish(topic,jsonObject.toJSONString()); |
| 47 | } | 48 | } |
| 48 | 49 | ||
| 49 | 50 | ||
| @@ -99,4 +100,5 @@ public class TerminalService { | @@ -99,4 +100,5 @@ public class TerminalService { | ||
| 99 | log.error("关闭失败",e); | 100 | log.error("关闭失败",e); |
| 100 | } | 101 | } |
| 101 | } | 102 | } |
| 103 | + | ||
| 102 | } | 104 | } |
| 1 | +sys.srs_push_address=rtmp://119.23.218.181:21935/live/${mqtt.clientId} | ||
| 2 | +sys.mp4_file_path=D:/lh-smart-feeder/2.mp4 | ||
| 3 | + | ||
| 4 | + | ||
| 5 | +mqtt.broker=tcp://175.24.61.68:1883 | ||
| 6 | +mqtt.clientId=70094a59d1d991d | ||
| 7 | +mqtt.topics=PUT/+,GET_REQ/+, READ/+,POST_REQ/+ | ||
| 8 | +mqtt.username=12_ZNZY | ||
| 9 | +mqtt.password=Luhui586 | ||
| 10 | +mqtt.client.operationTime=10 |
| 1 | package com.zhonglai.luhui.smart.feeder.dto; | 1 | package com.zhonglai.luhui.smart.feeder.dto; |
| 2 | 2 | ||
| 3 | +import org.bytedeco.javacv.OpenCVFrameConverter; | ||
| 3 | import org.opencv.core.Mat; | 4 | import org.opencv.core.Mat; |
| 4 | 5 | ||
| 5 | import java.io.Serializable; | 6 | import java.io.Serializable; |
| @@ -11,6 +12,16 @@ public class VeiwDto implements Serializable { | @@ -11,6 +12,16 @@ public class VeiwDto implements Serializable { | ||
| 11 | private Integer size; //面积大小 | 12 | private Integer size; //面积大小 |
| 12 | private Double absValue; //变化的斜率 | 13 | private Double absValue; //变化的斜率 |
| 13 | 14 | ||
| 15 | + private Integer push_camera; | ||
| 16 | + | ||
| 17 | + public Integer getPush_camera() { | ||
| 18 | + return push_camera; | ||
| 19 | + } | ||
| 20 | + | ||
| 21 | + public void setPush_camera(Integer push_camera) { | ||
| 22 | + this.push_camera = push_camera; | ||
| 23 | + } | ||
| 24 | + | ||
| 14 | public VeiwDto(Mat frame, Integer size) { | 25 | public VeiwDto(Mat frame, Integer size) { |
| 15 | this.frame = frame; | 26 | this.frame = frame; |
| 16 | this.size = size; | 27 | this.size = size; |
| @@ -6,6 +6,7 @@ import com.zhonglai.luhui.smart.feeder.dto.VeiwDto; | @@ -6,6 +6,7 @@ import com.zhonglai.luhui.smart.feeder.dto.VeiwDto; | ||
| 6 | import com.zhonglai.luhui.smart.feeder.service.CameraService; | 6 | import com.zhonglai.luhui.smart.feeder.service.CameraService; |
| 7 | import com.zhonglai.luhui.smart.feeder.service.impl.HtmllVeiwServiceImpl; | 7 | import com.zhonglai.luhui.smart.feeder.service.impl.HtmllVeiwServiceImpl; |
| 8 | import com.zhonglai.luhui.smart.feeder.service.impl.JFrameVeiwServiceImpl; | 8 | import com.zhonglai.luhui.smart.feeder.service.impl.JFrameVeiwServiceImpl; |
| 9 | +import org.bytedeco.javacv.FrameGrabber; | ||
| 9 | import org.opencv.core.*; | 10 | import org.opencv.core.*; |
| 10 | import org.opencv.highgui.HighGui; | 11 | import org.opencv.highgui.HighGui; |
| 11 | import org.opencv.videoio.VideoCapture; | 12 | import org.opencv.videoio.VideoCapture; |
| @@ -13,6 +14,7 @@ import org.opencv.imgproc.Imgproc; | @@ -13,6 +14,7 @@ import org.opencv.imgproc.Imgproc; | ||
| 13 | import org.slf4j.Logger; | 14 | import org.slf4j.Logger; |
| 14 | import org.slf4j.LoggerFactory; | 15 | import org.slf4j.LoggerFactory; |
| 15 | 16 | ||
| 17 | +import java.io.File; | ||
| 16 | import java.io.IOException; | 18 | import java.io.IOException; |
| 17 | import java.util.ArrayList; | 19 | import java.util.ArrayList; |
| 18 | import java.util.Collections; | 20 | import java.util.Collections; |
| @@ -24,74 +26,49 @@ public class OpenCVUtil { | @@ -24,74 +26,49 @@ public class OpenCVUtil { | ||
| 24 | 26 | ||
| 25 | public static void main(String[] args) { | 27 | public static void main(String[] args) { |
| 26 | System.out.println(DESUtil.decode("5F06AAC657B2E2B287289D25D950A829", "EXU5RUhI1"));; | 28 | System.out.println(DESUtil.decode("5F06AAC657B2E2B287289D25D950A829", "EXU5RUhI1"));; |
| 27 | -// OpenCVConfig.loadOpenCv(args); | ||
| 28 | -// VideoCapture videoCapture = OpenCVUtil.readVideoCaptureForVideo(0); | ||
| 29 | -// // 检查视频是否成功打开 | ||
| 30 | -// if (!videoCapture.isOpened()) { | ||
| 31 | -// System.out.println("无法打开视频文件"); | ||
| 32 | -// return; | ||
| 33 | -// } | ||
| 34 | -// | ||
| 35 | -// Mat previousFrame = new Mat(); | ||
| 36 | -// if (!videoCapture.read(previousFrame)) { | ||
| 37 | -// System.out.println("无法读取视频帧"); | ||
| 38 | -// return; | ||
| 39 | -// } | ||
| 40 | -// | ||
| 41 | -// JFrameVeiwServiceImpl dsplayVeiwService = new JFrameVeiwServiceImpl(); | ||
| 42 | -// // 逐帧处理视频 | ||
| 43 | -// Mat frame = new Mat(); | ||
| 44 | -// while (videoCapture.read(frame)) { | ||
| 45 | -// dsplayVeiwService.veiw(new VeiwDto(frame,null,null)); | ||
| 46 | -// try { | ||
| 47 | -// String str = new HtmllVeiwServiceImpl().matToString(frame,"jpg"); | ||
| 48 | -// System.out.println(str); | ||
| 49 | -// } catch (IOException e) { | ||
| 50 | -// throw new RuntimeException(e); | ||
| 51 | -// } | ||
| 52 | -// } | ||
| 53 | } | 29 | } |
| 54 | 30 | ||
| 55 | public static VideoCapture readVideoCaptureForVideo(int i) | 31 | public static VideoCapture readVideoCaptureForVideo(int i) |
| 56 | { | 32 | { |
| 57 | logger.info("初始化摄像头"); | 33 | logger.info("初始化摄像头"); |
| 58 | - // 创建VideoCapture对象 | ||
| 59 | - VideoCapture videoCapture = new VideoCapture(); | ||
| 60 | try { | 34 | try { |
| 61 | - Thread.sleep(1000); | 35 | + Thread.sleep(3000); |
| 62 | } catch (InterruptedException e) { | 36 | } catch (InterruptedException e) { |
| 63 | throw new RuntimeException(e); | 37 | throw new RuntimeException(e); |
| 64 | } | 38 | } |
| 39 | + VideoCapture videoCapture = new VideoCapture(); | ||
| 65 | boolean isopen = videoCapture.open(i); | 40 | boolean isopen = videoCapture.open(i); |
| 66 | if(isopen) | 41 | if(isopen) |
| 67 | { | 42 | { |
| 68 | logger.info("打开化摄像头"+i+"成功"); | 43 | logger.info("打开化摄像头"+i+"成功"); |
| 69 | return videoCapture; | 44 | return videoCapture; |
| 70 | - } | 45 | + }else { |
| 71 | logger.info("打开化摄像头"+i+"失败"); | 46 | logger.info("打开化摄像头"+i+"失败"); |
| 47 | + } | ||
| 72 | return null; | 48 | return null; |
| 73 | } | 49 | } |
| 74 | - | 50 | + private static final String MP4_FILE_PATH = "D:/lh-smart-feeder/mp4/2.mp4"; |
| 75 | public static VideoCapture openCapture() | 51 | public static VideoCapture openCapture() |
| 76 | { | 52 | { |
| 77 | for(int i=0;i<10;i++) | 53 | for(int i=0;i<10;i++) |
| 78 | { | 54 | { |
| 79 | - try { | ||
| 80 | - Thread.sleep(3000); | ||
| 81 | - } catch (InterruptedException e) { | ||
| 82 | - throw new RuntimeException(e); | 55 | + VideoCapture videoCapture = readVideoCaptureForVideo(i); |
| 56 | + if(null != videoCapture) | ||
| 57 | + { | ||
| 58 | + return videoCapture; //拿到的第一个摄像头返回 | ||
| 83 | } | 59 | } |
| 84 | - VideoCapture videoCapture = new VideoCapture(); | ||
| 85 | - boolean isopen = videoCapture.open(i); | ||
| 86 | - if(isopen) | 60 | + } |
| 61 | + logger.info("未检测到摄像头{},尝试打开本地视频",MP4_FILE_PATH); | ||
| 62 | + //如果找不到摄像头就找本地视频文件 | ||
| 63 | + File file = new File(MP4_FILE_PATH); | ||
| 64 | + if(file.exists() && file.isFile()) | ||
| 87 | { | 65 | { |
| 88 | - logger.info("打开化摄像头"+i+"成功"); | 66 | + VideoCapture videoCapture = OpenCVUtil.readVideoCaptureForVideo(MP4_FILE_PATH); |
| 89 | return videoCapture; | 67 | return videoCapture; |
| 90 | - }else { | ||
| 91 | - logger.info("打开化摄像头"+i+"失败"); | ||
| 92 | - } | ||
| 93 | } | 68 | } |
| 94 | - throw new RuntimeException("未检测到摄像头"); | 69 | + |
| 70 | + logger.info("未检测到摄像头!!!"); | ||
| 71 | + return null; | ||
| 95 | } | 72 | } |
| 96 | 73 | ||
| 97 | public static VideoCapture readVideoCaptureForVideo(String videoPath ) | 74 | public static VideoCapture readVideoCaptureForVideo(String videoPath ) |
lh-modules/lh-smart-feeder/src/main/java/com/zhonglai/luhui/smart/feeder/opencv/PushCamera.java
0 → 100644
| 1 | +package com.zhonglai.luhui.smart.feeder.opencv; | ||
| 2 | + | ||
| 3 | +import lombok.extern.slf4j.Slf4j; | ||
| 4 | +import org.bytedeco.ffmpeg.global.avcodec; | ||
| 5 | +import org.bytedeco.ffmpeg.global.avutil; | ||
| 6 | +import org.bytedeco.javacpp.Loader; | ||
| 7 | +import org.bytedeco.javacv.*; | ||
| 8 | +import org.bytedeco.opencv.opencv_core.IplImage; | ||
| 9 | +import org.bytedeco.opencv.presets.opencv_objdetect; | ||
| 10 | +import org.slf4j.Logger; | ||
| 11 | +import org.slf4j.LoggerFactory; | ||
| 12 | + | ||
| 13 | +import javax.swing.*; | ||
| 14 | + | ||
| 15 | +/** | ||
| 16 | + * @author will | ||
| 17 | + * @email zq2599@gmail.com | ||
| 18 | + * @date 2021/11/19 8:07 上午 | ||
| 19 | + * @description 功能介绍 | ||
| 20 | + */ | ||
| 21 | +public class PushCamera { | ||
| 22 | + private static final Logger log = LoggerFactory.getLogger(PushCamera.class); | ||
| 23 | + /** | ||
| 24 | + * 保存MP4文件的完整路径(两分零五秒的视频) | ||
| 25 | + */ | ||
| 26 | + private static final String MP4_FILE_PATH = "/Users/zhaoqin/temp/202111/21/camera.mp4"; | ||
| 27 | + | ||
| 28 | + /** | ||
| 29 | + * SRS的推流地址 | ||
| 30 | + */ | ||
| 31 | + private static final String SRS_PUSH_ADDRESS = "rtmp://192.168.50.43:11935/live/livestream"; | ||
| 32 | + | ||
| 33 | + /** | ||
| 34 | + * 摄像头序号,如果只有一个摄像头,那就是0 | ||
| 35 | + */ | ||
| 36 | + private static final int CAMERA_INDEX = 0; | ||
| 37 | + | ||
| 38 | + /** | ||
| 39 | + * 本机窗口 | ||
| 40 | + */ | ||
| 41 | + private CanvasFrame previewCanvas; | ||
| 42 | + | ||
| 43 | + /** | ||
| 44 | + * 帧抓取器 | ||
| 45 | + */ | ||
| 46 | + private FrameGrabber grabber; | ||
| 47 | + | ||
| 48 | + /** | ||
| 49 | + * 帧录制器 | ||
| 50 | + */ | ||
| 51 | + private FrameRecorder recorder; | ||
| 52 | + | ||
| 53 | + /** | ||
| 54 | + * 转换类 | ||
| 55 | + */ | ||
| 56 | + private OpenCVFrameConverter.ToIplImage converter; | ||
| 57 | + | ||
| 58 | + /** | ||
| 59 | + * 输出帧率 | ||
| 60 | + */ | ||
| 61 | + private static final double FRAME_RATE = 30.0; | ||
| 62 | + | ||
| 63 | + /** | ||
| 64 | + * 摄像头视频的宽 | ||
| 65 | + */ | ||
| 66 | + private int cameraImageWidth; | ||
| 67 | + | ||
| 68 | + /** | ||
| 69 | + * 摄像头视频的高 | ||
| 70 | + */ | ||
| 71 | + private int cameraImageHeight; | ||
| 72 | + | ||
| 73 | + /** | ||
| 74 | + * 每一次从摄像头抓取的帧都暂存在这里 | ||
| 75 | + */ | ||
| 76 | + private IplImage grabbedImage; | ||
| 77 | + | ||
| 78 | + /** | ||
| 79 | + * 初始化帧抓取器 | ||
| 80 | + * @throws Exception | ||
| 81 | + */ | ||
| 82 | + private void initGrabber() throws Exception { | ||
| 83 | + // 本机摄像头默认0,这里使用javacv的抓取器,至于使用的是ffmpeg还是opencv,请自行查看源码 | ||
| 84 | + grabber = FrameGrabber.createDefault(CAMERA_INDEX); | ||
| 85 | + | ||
| 86 | + // 开启抓取器 | ||
| 87 | + grabber.start(); | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + /** | ||
| 91 | + * 初始化帧录制器 | ||
| 92 | + * @throws Exception | ||
| 93 | + */ | ||
| 94 | + private void initRecorder() throws Exception { | ||
| 95 | + // 实例化帧录制器 | ||
| 96 | + recorder = FrameRecorder.createDefault(SRS_PUSH_ADDRESS, cameraImageWidth, cameraImageHeight); | ||
| 97 | + | ||
| 98 | + // 设置编码器 | ||
| 99 | + recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); | ||
| 100 | + | ||
| 101 | + // 封装格式 | ||
| 102 | + recorder.setFormat("flv"); | ||
| 103 | + | ||
| 104 | + // 设置帧录制器的帧率 | ||
| 105 | + recorder.setFrameRate(FRAME_RATE); | ||
| 106 | + | ||
| 107 | + // 初始化帧录制器 | ||
| 108 | + recorder.start(); | ||
| 109 | + } | ||
| 110 | + | ||
| 111 | + /** | ||
| 112 | + * 初始化转换器 | ||
| 113 | + * @throws Exception | ||
| 114 | + */ | ||
| 115 | + private void initConverter() throws Exception { | ||
| 116 | + // 实例化转换器 | ||
| 117 | + converter = new OpenCVFrameConverter.ToIplImage(); | ||
| 118 | + | ||
| 119 | + // 抓取一帧视频并将其转换为图像,至于用这个图像用来做什么?加水印,人脸识别等等自行添加 | ||
| 120 | + grabbedImage = converter.convert(grabber.grab()); | ||
| 121 | + | ||
| 122 | + // 将视频图像的宽度存储在成员变量cameraImageWidth | ||
| 123 | + cameraImageWidth = grabbedImage.width(); | ||
| 124 | + | ||
| 125 | + // 将视频图像的高度存储在成员变量cameraImageHeight | ||
| 126 | + cameraImageHeight = grabbedImage.height(); | ||
| 127 | + } | ||
| 128 | + | ||
| 129 | + /** | ||
| 130 | + * 实例化、初始化窗口 | ||
| 131 | + */ | ||
| 132 | + private void initWindow() { | ||
| 133 | + previewCanvas = new CanvasFrame("摄像头预览", CanvasFrame.getDefaultGamma() / grabber.getGamma()); | ||
| 134 | + previewCanvas.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); | ||
| 135 | + previewCanvas.setAlwaysOnTop(true); | ||
| 136 | + } | ||
| 137 | + | ||
| 138 | + /** | ||
| 139 | + * 预览和推送 | ||
| 140 | + * @throws Exception | ||
| 141 | + */ | ||
| 142 | + private void grabAndPush() throws Exception { | ||
| 143 | + // 假设一秒钟15帧,那么两帧间隔就是(1000/15)毫秒 | ||
| 144 | + double interVal = 1000/ FRAME_RATE; | ||
| 145 | + // 发送完一帧后sleep的时间,不能完全等于(1000/frameRate),不然会卡顿, | ||
| 146 | + // 要更小一些,这里取八分之一 | ||
| 147 | + interVal/=8.0; | ||
| 148 | + | ||
| 149 | + // 不知道为什么这里不做转换就不能推到rtmp | ||
| 150 | + Frame rotatedFrame; | ||
| 151 | + long startTime = System.currentTimeMillis(); | ||
| 152 | + | ||
| 153 | + while ((grabbedImage = converter.convert(grabber.grab())) != null) { | ||
| 154 | + rotatedFrame = converter.convert(grabbedImage); | ||
| 155 | + | ||
| 156 | + // 预览窗口上显示当前帧 | ||
| 157 | +// previewCanvas.showImage(rotatedFrame); | ||
| 158 | + | ||
| 159 | + // 推送的时候,给当前帧加上时间戳 | ||
| 160 | + recorder.setTimestamp(1000 * (System.currentTimeMillis() - startTime)); | ||
| 161 | + | ||
| 162 | + // 推送到SRS | ||
| 163 | + recorder.record(rotatedFrame); | ||
| 164 | + | ||
| 165 | + Thread.sleep((int)interVal); | ||
| 166 | + } | ||
| 167 | + } | ||
| 168 | + | ||
| 169 | + /** | ||
| 170 | + * 释放所有资源 | ||
| 171 | + * @throws Exception | ||
| 172 | + */ | ||
| 173 | + private void safeRelease() { | ||
| 174 | + if (null!= previewCanvas) { | ||
| 175 | + previewCanvas.dispose(); | ||
| 176 | + } | ||
| 177 | + | ||
| 178 | + if (null!=recorder) { | ||
| 179 | + try { | ||
| 180 | + recorder.close(); | ||
| 181 | + } catch (Exception exception) { | ||
| 182 | + log.error("close recorder error", exception); | ||
| 183 | + } | ||
| 184 | + } | ||
| 185 | + | ||
| 186 | + if (null!=grabber) { | ||
| 187 | + try { | ||
| 188 | + grabber.close(); | ||
| 189 | + } catch (Exception exception) { | ||
| 190 | + log.error("close grabber error", exception); | ||
| 191 | + } | ||
| 192 | + } | ||
| 193 | + } | ||
| 194 | + | ||
| 195 | + /** | ||
| 196 | + * 整合了所有初始化操作 | ||
| 197 | + * @throws Exception | ||
| 198 | + */ | ||
| 199 | + private void init() throws Exception { | ||
| 200 | + long startTime = System.currentTimeMillis(); | ||
| 201 | + | ||
| 202 | + // 设置ffmepg日志级别 | ||
| 203 | + avutil.av_log_set_level(avutil.AV_LOG_INFO); | ||
| 204 | + FFmpegLogCallback.set(); | ||
| 205 | + | ||
| 206 | + // 加载检测 | ||
| 207 | + Loader.load(opencv_objdetect.class); | ||
| 208 | + | ||
| 209 | + // 实例化、初始化帧抓取器 | ||
| 210 | + initGrabber(); | ||
| 211 | + | ||
| 212 | + // 实例化、初始化转换工具,里面会取得摄像头图像的宽度和高度 | ||
| 213 | + initConverter(); | ||
| 214 | + | ||
| 215 | + // 实例化、初始化帧录制器 | ||
| 216 | + initRecorder(); | ||
| 217 | + | ||
| 218 | + // 实例化、初始化窗口 | ||
| 219 | +// initWindow(); | ||
| 220 | + | ||
| 221 | + log.info("初始化完成,耗时[{}]毫秒,图像宽度[{}],图像高度[{}]", | ||
| 222 | + System.currentTimeMillis()-startTime, | ||
| 223 | + cameraImageWidth, | ||
| 224 | + cameraImageWidth); | ||
| 225 | + } | ||
| 226 | + | ||
| 227 | + /** | ||
| 228 | + * 直播 | ||
| 229 | + */ | ||
| 230 | + public void live() { | ||
| 231 | + try { | ||
| 232 | + // 初始化操作 | ||
| 233 | + init(); | ||
| 234 | + // 持续拉取和推送 | ||
| 235 | + grabAndPush(); | ||
| 236 | + } catch (Exception exception) { | ||
| 237 | + log.error("execute live error", exception); | ||
| 238 | + } finally { | ||
| 239 | + // 无论如何都要释放资源 | ||
| 240 | + safeRelease(); | ||
| 241 | + } | ||
| 242 | + } | ||
| 243 | + | ||
| 244 | + public static void main(String[] args) { | ||
| 245 | + new PushCamera().live(); | ||
| 246 | + } | ||
| 247 | +} |
lh-modules/lh-smart-feeder/src/main/java/com/zhonglai/luhui/smart/feeder/opencv/PushMp4.java
0 → 100644
| 1 | +package com.zhonglai.luhui.smart.feeder.opencv; | ||
| 2 | + | ||
| 3 | +import lombok.extern.slf4j.Slf4j; | ||
| 4 | +import org.bytedeco.ffmpeg.avcodec.AVCodecParameters; | ||
| 5 | +import org.bytedeco.ffmpeg.avformat.AVFormatContext; | ||
| 6 | +import org.bytedeco.ffmpeg.avformat.AVStream; | ||
| 7 | +import org.bytedeco.ffmpeg.global.avcodec; | ||
| 8 | +import org.bytedeco.ffmpeg.global.avutil; | ||
| 9 | +import org.bytedeco.javacv.FFmpegFrameGrabber; | ||
| 10 | +import org.bytedeco.javacv.FFmpegFrameRecorder; | ||
| 11 | +import org.bytedeco.javacv.FFmpegLogCallback; | ||
| 12 | +import org.bytedeco.javacv.Frame; | ||
| 13 | + | ||
| 14 | +/** | ||
| 15 | + * @author willzhao | ||
| 16 | + * @version 1.0 | ||
| 17 | + * @description 读取指定的mp4文件,推送到SRS服务器 | ||
| 18 | + * @date 2021/11/19 8:49 | ||
| 19 | + */ | ||
| 20 | +@Slf4j | ||
| 21 | +public class PushMp4 { | ||
| 22 | + /** | ||
| 23 | + * 本地MP4文件的完整路径(两分零五秒的视频) | ||
| 24 | + */ | ||
| 25 | +// private static final String MP4_FILE_PATH = "/Users/zhaoqin/temp/202111/20/sample-mp4-file.mp4"; | ||
| 26 | + private static final String MP4_FILE_PATH = "C:\\Users\\123\\Videos\\抖音\\莱堃科技\\20230901\\f3bb11df0711125aefdd9a16e67323fb.mp4"; | ||
| 27 | + | ||
| 28 | + /** | ||
| 29 | + * SRS的推流地址 | ||
| 30 | + */ | ||
| 31 | + private static final String SRS_PUSH_ADDRESS = "rtmp://119.23.218.181:21935/live/f3bb11df0711125aefdd9a16e67323fb"; | ||
| 32 | + | ||
| 33 | + /** | ||
| 34 | + * 读取指定的mp4文件,推送到SRS服务器 | ||
| 35 | + * @param sourceFilePath 视频文件的绝对路径 | ||
| 36 | + * @param PUSH_ADDRESS 推流地址 | ||
| 37 | + * @throws Exception | ||
| 38 | + */ | ||
| 39 | + private static void grabAndPush(String sourceFilePath, String PUSH_ADDRESS) throws Exception { | ||
| 40 | + // ffmepg日志级别 | ||
| 41 | + avutil.av_log_set_level(avutil.AV_LOG_INFO); | ||
| 42 | + FFmpegLogCallback.set(); | ||
| 43 | + | ||
| 44 | + // 实例化帧抓取器对象,将文件路径传入 | ||
| 45 | + FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(MP4_FILE_PATH); | ||
| 46 | + | ||
| 47 | + long startTime = System.currentTimeMillis(); | ||
| 48 | + | ||
| 49 | + log.info("开始初始化帧抓取器"); | ||
| 50 | + | ||
| 51 | + // 初始化帧抓取器,例如数据结构(时间戳、编码器上下文、帧对象等), | ||
| 52 | + // 如果入参等于true,还会调用avformat_find_stream_info方法获取流的信息,放入AVFormatContext类型的成员变量oc中 | ||
| 53 | + grabber.start(true); | ||
| 54 | + | ||
| 55 | + log.info("帧抓取器初始化完成,耗时[{}]毫秒", System.currentTimeMillis()-startTime); | ||
| 56 | + | ||
| 57 | + // grabber.start方法中,初始化的解码器信息存在放在grabber的成员变量oc中 | ||
| 58 | + AVFormatContext avFormatContext = grabber.getFormatContext(); | ||
| 59 | + | ||
| 60 | + // 文件内有几个媒体流(一般是视频流+音频流) | ||
| 61 | + int streamNum = avFormatContext.nb_streams(); | ||
| 62 | + | ||
| 63 | + // 没有媒体流就不用继续了 | ||
| 64 | + if (streamNum<1) { | ||
| 65 | + log.error("文件内不存在媒体流"); | ||
| 66 | + return; | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + // 取得视频的帧率 | ||
| 70 | + int frameRate = (int)grabber.getVideoFrameRate(); | ||
| 71 | + | ||
| 72 | + log.info("视频帧率[{}],视频时长[{}]秒,媒体流数量[{}]", | ||
| 73 | + frameRate, | ||
| 74 | + avFormatContext.duration()/1000000, | ||
| 75 | + avFormatContext.nb_streams()); | ||
| 76 | + | ||
| 77 | + // 遍历每一个流,检查其类型 | ||
| 78 | + for (int i=0; i< streamNum; i++) { | ||
| 79 | + AVStream avStream = avFormatContext.streams(i); | ||
| 80 | + AVCodecParameters avCodecParameters = avStream.codecpar(); | ||
| 81 | + log.info("流的索引[{}],编码器类型[{}],编码器ID[{}]", i, avCodecParameters.codec_type(), avCodecParameters.codec_id()); | ||
| 82 | + } | ||
| 83 | + | ||
| 84 | + // 视频宽度 | ||
| 85 | + int frameWidth = grabber.getImageWidth(); | ||
| 86 | + // 视频高度 | ||
| 87 | + int frameHeight = grabber.getImageHeight(); | ||
| 88 | + // 音频通道数量 | ||
| 89 | + int audioChannels = grabber.getAudioChannels(); | ||
| 90 | + | ||
| 91 | + log.info("视频宽度[{}],视频高度[{}],音频通道数[{}]", | ||
| 92 | + frameWidth, | ||
| 93 | + frameHeight, | ||
| 94 | + audioChannels); | ||
| 95 | + | ||
| 96 | + // 实例化FFmpegFrameRecorder,将SRS的推送地址传入 | ||
| 97 | + FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(SRS_PUSH_ADDRESS, | ||
| 98 | + frameWidth, | ||
| 99 | + frameHeight, | ||
| 100 | + audioChannels); | ||
| 101 | + | ||
| 102 | + // 设置编码格式 | ||
| 103 | + recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); | ||
| 104 | + | ||
| 105 | + // 设置封装格式 | ||
| 106 | + recorder.setFormat("flv"); | ||
| 107 | + | ||
| 108 | + // 一秒内的帧数 | ||
| 109 | + recorder.setFrameRate(frameRate); | ||
| 110 | + | ||
| 111 | + // 两个关键帧之间的帧数 | ||
| 112 | + recorder.setGopSize(frameRate); | ||
| 113 | + | ||
| 114 | + // 设置音频通道数,与视频源的通道数相等 | ||
| 115 | + recorder.setAudioChannels(grabber.getAudioChannels()); | ||
| 116 | + | ||
| 117 | + startTime = System.currentTimeMillis(); | ||
| 118 | + log.info("开始初始化帧抓取器"); | ||
| 119 | + | ||
| 120 | + // 初始化帧录制器,例如数据结构(音频流、视频流指针,编码器), | ||
| 121 | + // 调用av_guess_format方法,确定视频输出时的封装方式, | ||
| 122 | + // 媒体上下文对象的内存分配, | ||
| 123 | + // 编码器的各项参数设置 | ||
| 124 | + recorder.start(); | ||
| 125 | + | ||
| 126 | + log.info("帧录制初始化完成,耗时[{}]毫秒", System.currentTimeMillis()-startTime); | ||
| 127 | + | ||
| 128 | + Frame frame; | ||
| 129 | + | ||
| 130 | + startTime = System.currentTimeMillis(); | ||
| 131 | + | ||
| 132 | + log.info("开始推流"); | ||
| 133 | + | ||
| 134 | + long videoTS = 0; | ||
| 135 | + | ||
| 136 | + int videoFrameNum = 0; | ||
| 137 | + int audioFrameNum = 0; | ||
| 138 | + int dataFrameNum = 0; | ||
| 139 | + | ||
| 140 | + // 假设一秒钟15帧,那么两帧间隔就是(1000/15)毫秒 | ||
| 141 | + int interVal = 1000/frameRate; | ||
| 142 | + // 发送完一帧后sleep的时间,不能完全等于(1000/frameRate),不然会卡顿, | ||
| 143 | + // 要更小一些,这里取八分之一 | ||
| 144 | + interVal/=8; | ||
| 145 | + | ||
| 146 | + // 持续从视频源取帧 | ||
| 147 | + while (null!=(frame=grabber.grab())) { | ||
| 148 | + videoTS = 1000 * (System.currentTimeMillis() - startTime); | ||
| 149 | + | ||
| 150 | + // 时间戳 | ||
| 151 | +// recorder.setTimestamp(videoTS); | ||
| 152 | + | ||
| 153 | + // 有图像,就把视频帧加一 | ||
| 154 | + if (null!=frame.image) { | ||
| 155 | + videoFrameNum++; | ||
| 156 | + } | ||
| 157 | + | ||
| 158 | + // 有声音,就把音频帧加一 | ||
| 159 | + if (null!=frame.samples) { | ||
| 160 | + audioFrameNum++; | ||
| 161 | + } | ||
| 162 | + | ||
| 163 | + // 有数据,就把数据帧加一 | ||
| 164 | + if (null!=frame.data) { | ||
| 165 | + dataFrameNum++; | ||
| 166 | + } | ||
| 167 | + | ||
| 168 | + // 取出的每一帧,都推送到SRS | ||
| 169 | + recorder.record(frame); | ||
| 170 | + | ||
| 171 | + // 停顿一下再推送 | ||
| 172 | + Thread.sleep(interVal); | ||
| 173 | + } | ||
| 174 | + | ||
| 175 | + log.info("推送完成,视频帧[{}],音频帧[{}],数据帧[{}],耗时[{}]秒", | ||
| 176 | + videoFrameNum, | ||
| 177 | + audioFrameNum, | ||
| 178 | + dataFrameNum, | ||
| 179 | + (System.currentTimeMillis()-startTime)/1000); | ||
| 180 | + | ||
| 181 | + // 关闭帧录制器 | ||
| 182 | + recorder.close(); | ||
| 183 | + // 关闭帧抓取器 | ||
| 184 | + grabber.close(); | ||
| 185 | + } | ||
| 186 | + | ||
| 187 | + public static void main(String[] args) throws Exception { | ||
| 188 | + grabAndPush(MP4_FILE_PATH, SRS_PUSH_ADDRESS); | ||
| 189 | + } | ||
| 190 | +} |
| @@ -2,17 +2,21 @@ package com.zhonglai.luhui.smart.feeder.service; | @@ -2,17 +2,21 @@ package com.zhonglai.luhui.smart.feeder.service; | ||
| 2 | 2 | ||
| 3 | import com.zhonglai.luhui.smart.feeder.dto.ConfigurationParameter; | 3 | import com.zhonglai.luhui.smart.feeder.dto.ConfigurationParameter; |
| 4 | import com.zhonglai.luhui.smart.feeder.opencv.OpenCVUtil; | 4 | import com.zhonglai.luhui.smart.feeder.opencv.OpenCVUtil; |
| 5 | +import org.bytedeco.javacv.FrameGrabber; | ||
| 5 | import org.opencv.videoio.VideoCapture; | 6 | import org.opencv.videoio.VideoCapture; |
| 6 | import org.slf4j.Logger; | 7 | import org.slf4j.Logger; |
| 7 | import org.slf4j.LoggerFactory; | 8 | import org.slf4j.LoggerFactory; |
| 8 | import org.springframework.beans.factory.annotation.Autowired; | 9 | import org.springframework.beans.factory.annotation.Autowired; |
| 9 | import org.springframework.stereotype.Service; | 10 | import org.springframework.stereotype.Service; |
| 10 | 11 | ||
| 12 | +import java.net.DatagramSocket; | ||
| 11 | import java.util.concurrent.ScheduledExecutorService; | 13 | import java.util.concurrent.ScheduledExecutorService; |
| 12 | import java.util.concurrent.ScheduledFuture; | 14 | import java.util.concurrent.ScheduledFuture; |
| 13 | import java.util.concurrent.TimeUnit; | 15 | import java.util.concurrent.TimeUnit; |
| 14 | - | ||
| 15 | - | 16 | +import java.net.DatagramPacket; |
| 17 | +import java.net.InetAddress; | ||
| 18 | +import java.net.MulticastSocket; | ||
| 19 | +import java.io.IOException; | ||
| 16 | /** | 20 | /** |
| 17 | * 摄像头 | 21 | * 摄像头 |
| 18 | */ | 22 | */ |
| @@ -118,4 +122,125 @@ public class CameraService { | @@ -118,4 +122,125 @@ public class CameraService { | ||
| 118 | return videoIsOpen; | 122 | return videoIsOpen; |
| 119 | } | 123 | } |
| 120 | 124 | ||
| 125 | + | ||
| 126 | + public static void main(String[] args) throws Exception{ | ||
| 127 | + | ||
| 128 | + MulticastSocket socket = null; | ||
| 129 | + try { | ||
| 130 | + // 创建 MulticastSocket 对象 | ||
| 131 | + socket = new MulticastSocket(); | ||
| 132 | + | ||
| 133 | + // 指定多播地址和端口 | ||
| 134 | + InetAddress group = InetAddress.getByName("239.255.255.250"); | ||
| 135 | + int port = 37020; | ||
| 136 | + | ||
| 137 | + while (true) | ||
| 138 | + { | ||
| 139 | + // 创建要发送的消息 | ||
| 140 | + String message = "<?xml version=\"1.0\" encoding=\"utf-8\"?><Probe><Uuid>B0F5E9C7-EBD5-4A03-99F7-B069B141C619</Uuid><Types>inquiry</Types></Probe>"; | ||
| 141 | + byte[] buffer = message.getBytes(); | ||
| 142 | + | ||
| 143 | + // 创建 DatagramPacket 对象 | ||
| 144 | + DatagramPacket packet = new DatagramPacket(buffer, buffer.length, group, port); | ||
| 145 | + | ||
| 146 | + // 发送数据包 | ||
| 147 | + socket.send(packet); | ||
| 148 | + | ||
| 149 | + Thread.sleep(10000); | ||
| 150 | + } | ||
| 151 | + | ||
| 152 | + } catch (IOException e) { | ||
| 153 | + e.printStackTrace(); | ||
| 154 | + } finally { | ||
| 155 | + if (socket != null) { | ||
| 156 | + socket.close(); | ||
| 157 | + } | ||
| 158 | + } | ||
| 159 | + } | ||
| 160 | + | ||
| 161 | + private static void sendclien() | ||
| 162 | + { | ||
| 163 | + try { | ||
| 164 | + // 创建组播Socket | ||
| 165 | + MulticastSocket multicastSocket = new MulticastSocket(); | ||
| 166 | + | ||
| 167 | + // 创建组播地址 | ||
| 168 | + InetAddress group = InetAddress.getByName("239.255.255.250"); | ||
| 169 | + // 发送消息 | ||
| 170 | + String message = "<?xml version=\"1.0\" encoding=\"utf-8\"?><Probe><Uuid>B0F5E9C7-EBD5-4A03-99F7-B069B141C619</Uuid><Types>inquiry</Types></Probe>"; | ||
| 171 | + byte[] buffer = message.getBytes(); | ||
| 172 | + DatagramPacket packet = new DatagramPacket(buffer, buffer.length, group, 37020); | ||
| 173 | + multicastSocket.send(packet); | ||
| 174 | + // 关闭Socket | ||
| 175 | + multicastSocket.close(); | ||
| 176 | + } catch (IOException e) { | ||
| 177 | + e.printStackTrace(); | ||
| 178 | + } | ||
| 179 | + } | ||
| 180 | + | ||
| 181 | + public static void onClien() | ||
| 182 | + { | ||
| 183 | + DatagramSocket socket = null; | ||
| 184 | + try { | ||
| 185 | + // 创建 DatagramSocket 对象,监听指定的端口 | ||
| 186 | + socket = new DatagramSocket(37020); | ||
| 187 | + | ||
| 188 | + while (true) { | ||
| 189 | + // 创建 DatagramPacket 对象,用于接收数据 | ||
| 190 | + byte[] buffer = new byte[1024]; | ||
| 191 | + DatagramPacket packet = new DatagramPacket(buffer, buffer.length); | ||
| 192 | + | ||
| 193 | + // 接收数据 | ||
| 194 | + socket.receive(packet); | ||
| 195 | + | ||
| 196 | + // 转换并打印接收到的数据 | ||
| 197 | + String received = new String(packet.getData(), 0, packet.getLength()); | ||
| 198 | + System.out.println("Received data: " + received); | ||
| 199 | + } | ||
| 200 | + } catch (IOException e) { | ||
| 201 | + e.printStackTrace(); | ||
| 202 | + } finally { | ||
| 203 | + if (socket != null) { | ||
| 204 | + socket.close(); | ||
| 205 | + } | ||
| 206 | + } | ||
| 207 | + } | ||
| 208 | + | ||
| 209 | + public static void clien() | ||
| 210 | + { | ||
| 211 | + try { | ||
| 212 | + // 创建组播Socket | ||
| 213 | + MulticastSocket multicastSocket = new MulticastSocket(37020); | ||
| 214 | + | ||
| 215 | + // 加入组播地址 | ||
| 216 | + InetAddress group = InetAddress.getByName("239.255.255.250"); | ||
| 217 | + multicastSocket.joinGroup(group); | ||
| 218 | + | ||
| 219 | + boolean isip = true; | ||
| 220 | + while (isip) | ||
| 221 | + { | ||
| 222 | + // 接收消息 | ||
| 223 | + byte[] buffer = new byte[1024]; | ||
| 224 | + DatagramPacket packet = new DatagramPacket(buffer, buffer.length); | ||
| 225 | + multicastSocket.receive(packet); | ||
| 226 | + | ||
| 227 | + // 处理消息 | ||
| 228 | + String message = new String(packet.getData(), packet.getOffset(), packet.getLength()); | ||
| 229 | + System.out.println("Received: " + message); | ||
| 230 | + | ||
| 231 | + if(message.indexOf("ip")>=0) | ||
| 232 | + { | ||
| 233 | + isip = false; | ||
| 234 | + } | ||
| 235 | + | ||
| 236 | + } | ||
| 237 | + | ||
| 238 | + // 关闭Socket | ||
| 239 | + multicastSocket.leaveGroup(group); | ||
| 240 | + multicastSocket.close(); | ||
| 241 | + } catch (IOException e) { | ||
| 242 | + e.printStackTrace(); | ||
| 243 | + } | ||
| 244 | + } | ||
| 245 | + | ||
| 121 | } | 246 | } |
| @@ -8,9 +8,11 @@ import com.zhonglai.luhui.smart.feeder.Main; | @@ -8,9 +8,11 @@ import com.zhonglai.luhui.smart.feeder.Main; | ||
| 8 | import com.zhonglai.luhui.smart.feeder.dto.ConfigurationParameter; | 8 | import com.zhonglai.luhui.smart.feeder.dto.ConfigurationParameter; |
| 9 | import com.zhonglai.luhui.smart.feeder.dto.ModbusDto; | 9 | import com.zhonglai.luhui.smart.feeder.dto.ModbusDto; |
| 10 | import com.zhonglai.luhui.smart.feeder.dto.StateData; | 10 | import com.zhonglai.luhui.smart.feeder.dto.StateData; |
| 11 | +import com.zhonglai.luhui.smart.feeder.dto.VeiwDto; | ||
| 11 | import com.zhonglai.luhui.smart.feeder.dto.commd.FeederCommd03Response; | 12 | import com.zhonglai.luhui.smart.feeder.dto.commd.FeederCommd03Response; |
| 12 | import com.zhonglai.luhui.smart.feeder.dto.commd.FeederCommdDto; | 13 | import com.zhonglai.luhui.smart.feeder.dto.commd.FeederCommdDto; |
| 13 | import com.zhonglai.luhui.smart.feeder.util.FeederCommdUtil; | 14 | import com.zhonglai.luhui.smart.feeder.util.FeederCommdUtil; |
| 15 | +import org.eclipse.paho.client.mqttv3.MqttException; | ||
| 14 | import org.slf4j.Logger; | 16 | import org.slf4j.Logger; |
| 15 | import org.slf4j.LoggerFactory; | 17 | import org.slf4j.LoggerFactory; |
| 16 | import org.springframework.beans.factory.annotation.Autowired; | 18 | import org.springframework.beans.factory.annotation.Autowired; |
| @@ -43,15 +45,46 @@ public class DateListenService { | @@ -43,15 +45,46 @@ public class DateListenService { | ||
| 43 | @Autowired | 45 | @Autowired |
| 44 | private ConfigurationParameterService configurationParameterService; | 46 | private ConfigurationParameterService configurationParameterService; |
| 45 | 47 | ||
| 48 | + @Autowired | ||
| 49 | + private FishGroupImageRecognitionService fishGroupImageRecognitionService; | ||
| 50 | + | ||
| 46 | public void run() | 51 | public void run() |
| 47 | { | 52 | { |
| 48 | scheduledExecutorService.scheduleAtFixedRate(() -> { | 53 | scheduledExecutorService.scheduleAtFixedRate(() -> { |
| 49 | 54 | ||
| 55 | + try { | ||
| 56 | + gatherDevice0(); | ||
| 57 | + Thread.sleep(1000); | ||
| 58 | + } catch (MqttException e) { | ||
| 59 | + logger.error("采集主机信息失败",e); | ||
| 60 | + } catch (InterruptedException e) { | ||
| 61 | + throw new RuntimeException(e); | ||
| 62 | + } | ||
| 63 | + try { | ||
| 64 | + gatherDevice1(); | ||
| 65 | + Thread.sleep(1000); | ||
| 66 | + } catch (MqttException e) { | ||
| 67 | + logger.error("采集投料机数据失败",e); | ||
| 68 | + }catch (InterruptedException e) { | ||
| 69 | + throw new RuntimeException(e); | ||
| 70 | + } | ||
| 71 | + try { | ||
| 72 | + gatherDevice2(); | ||
| 73 | + } catch (MqttException e) { | ||
| 74 | + logger.error("采集摄像头信息失败",e); | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + },1,60, TimeUnit.SECONDS); | ||
| 78 | + } | ||
| 79 | + | ||
| 80 | + /** | ||
| 81 | + * 采集投料机数据 | ||
| 82 | + */ | ||
| 83 | + private void gatherDevice1() throws MqttException { | ||
| 50 | if(null == configurationParameterService.getConfig(ConfigurationParameter.ifUpLoadData) || !(Boolean) configurationParameterService.getConfig(ConfigurationParameter.ifUpLoadData)) | 84 | if(null == configurationParameterService.getConfig(ConfigurationParameter.ifUpLoadData) || !(Boolean) configurationParameterService.getConfig(ConfigurationParameter.ifUpLoadData)) |
| 51 | { | 85 | { |
| 52 | return; | 86 | return; |
| 53 | } | 87 | } |
| 54 | - try { | ||
| 55 | ModbusDto modbusDto = serialPortService.sendHexData(FeederCommdUtil.readAll()); | 88 | ModbusDto modbusDto = serialPortService.sendHexData(FeederCommdUtil.readAll()); |
| 56 | Map<String,Object> data = analysisDataService.analysis(modbusDto); | 89 | Map<String,Object> data = analysisDataService.analysis(modbusDto); |
| 57 | if(null != data && data.size() != 0) | 90 | if(null != data && data.size() != 0) |
| @@ -60,14 +93,41 @@ public class DateListenService { | @@ -60,14 +93,41 @@ public class DateListenService { | ||
| 60 | configurationParameterService.setStateData(stateData); | 93 | configurationParameterService.setStateData(stateData); |
| 61 | 94 | ||
| 62 | JSONObject jsonObject = new JSONObject(); | 95 | JSONObject jsonObject = new JSONObject(); |
| 63 | - jsonObject.put("1",data); | ||
| 64 | - terminalService.scheduledSubmissionData(jsonObject.toJSONString()); | 96 | + jsonObject.put("10_1",data); |
| 97 | + String topic = "ALL_POST"; | ||
| 98 | + terminalService.publish(topic,jsonObject.toJSONString()); | ||
| 65 | } | 99 | } |
| 66 | - } catch (Exception e) { | ||
| 67 | - logger.error("数据采集失败",e); | ||
| 68 | } | 100 | } |
| 69 | 101 | ||
| 70 | - },1,60, TimeUnit.SECONDS); | 102 | + /** |
| 103 | + * 采集主机信息 | ||
| 104 | + */ | ||
| 105 | + private void gatherDevice0() throws MqttException { | ||
| 106 | + Map<String, Object> map = configurationParameterService.getAll(); | ||
| 107 | + | ||
| 108 | + if(null != map && map.size() !=0) | ||
| 109 | + { | ||
| 110 | + JSONObject jsonObject = new JSONObject(); | ||
| 111 | + jsonObject.put("0",map); | ||
| 112 | + String topic = "ADD_POST"; | ||
| 113 | + terminalService.publish(topic,jsonObject.toJSONString()); | ||
| 114 | + } | ||
| 71 | } | 115 | } |
| 72 | 116 | ||
| 117 | + /** | ||
| 118 | + * 采集摄像头信息 | ||
| 119 | + */ | ||
| 120 | + private void gatherDevice2() throws MqttException { | ||
| 121 | + VeiwDto veiwDto = fishGroupImageRecognitionService.getVeiwDto(); | ||
| 122 | + if(null != veiwDto && BeanUtil.isNotEmpty(veiwDto,"size","absValue")) | ||
| 123 | + { | ||
| 124 | + veiwDto = BeanUtil.copyProperties(veiwDto,VeiwDto.class,"frame","binaryImage"); | ||
| 125 | + | ||
| 126 | + JSONObject jsonObject = new JSONObject(); | ||
| 127 | + jsonObject.put("1_1",veiwDto); | ||
| 128 | + String topic = "ALL_POST"; | ||
| 129 | + terminalService.publish(topic,jsonObject.toJSONString()); | ||
| 130 | + } | ||
| 131 | + | ||
| 132 | + } | ||
| 73 | } | 133 | } |
| @@ -6,8 +6,6 @@ import com.zhonglai.luhui.smart.feeder.dto.VeiwDto; | @@ -6,8 +6,6 @@ import com.zhonglai.luhui.smart.feeder.dto.VeiwDto; | ||
| 6 | import com.zhonglai.luhui.smart.feeder.dto.VeiwType; | 6 | import com.zhonglai.luhui.smart.feeder.dto.VeiwType; |
| 7 | import com.zhonglai.luhui.smart.feeder.opencv.OpenCVUtil; | 7 | import com.zhonglai.luhui.smart.feeder.opencv.OpenCVUtil; |
| 8 | import com.zhonglai.luhui.smart.feeder.service.impl.HtmllVeiwServiceImpl; | 8 | import com.zhonglai.luhui.smart.feeder.service.impl.HtmllVeiwServiceImpl; |
| 9 | -import com.zhonglai.luhui.smart.feeder.service.impl.JFrameVeiwServiceImpl; | ||
| 10 | -import io.swagger.models.auth.In; | ||
| 11 | import org.opencv.core.Mat; | 9 | import org.opencv.core.Mat; |
| 12 | import org.opencv.core.MatOfPoint; | 10 | import org.opencv.core.MatOfPoint; |
| 13 | import org.opencv.core.Scalar; | 11 | import org.opencv.core.Scalar; |
| @@ -19,12 +17,10 @@ import org.slf4j.LoggerFactory; | @@ -19,12 +17,10 @@ import org.slf4j.LoggerFactory; | ||
| 19 | import org.springframework.beans.factory.annotation.Autowired; | 17 | import org.springframework.beans.factory.annotation.Autowired; |
| 20 | import org.springframework.stereotype.Service; | 18 | import org.springframework.stereotype.Service; |
| 21 | 19 | ||
| 22 | -import javax.annotation.PostConstruct; | ||
| 23 | import java.util.ArrayList; | 20 | import java.util.ArrayList; |
| 24 | import java.util.Arrays; | 21 | import java.util.Arrays; |
| 25 | import java.util.List; | 22 | import java.util.List; |
| 26 | import java.util.concurrent.ScheduledExecutorService; | 23 | import java.util.concurrent.ScheduledExecutorService; |
| 27 | -import java.util.concurrent.ScheduledFuture; | ||
| 28 | import java.util.concurrent.TimeUnit; | 24 | import java.util.concurrent.TimeUnit; |
| 29 | 25 | ||
| 30 | /** | 26 | /** |
| @@ -37,9 +33,6 @@ public class FishGroupImageRecognitionService { | @@ -37,9 +33,6 @@ public class FishGroupImageRecognitionService { | ||
| 37 | @Autowired | 33 | @Autowired |
| 38 | private CameraService cameraService; | 34 | private CameraService cameraService; |
| 39 | 35 | ||
| 40 | - private DisplayVeiwService dsplayVeiwService; | ||
| 41 | - | ||
| 42 | - | ||
| 43 | @Autowired | 36 | @Autowired |
| 44 | private ScheduledExecutorService scheduledExecutorService; | 37 | private ScheduledExecutorService scheduledExecutorService; |
| 45 | 38 | ||
| @@ -49,43 +42,29 @@ public class FishGroupImageRecognitionService { | @@ -49,43 +42,29 @@ public class FishGroupImageRecognitionService { | ||
| 49 | @Autowired | 42 | @Autowired |
| 50 | private DeviceService deviceService; | 43 | private DeviceService deviceService; |
| 51 | 44 | ||
| 52 | - | ||
| 53 | private static Boolean isRun = false; | 45 | private static Boolean isRun = false; |
| 54 | 46 | ||
| 47 | + private VeiwDto veiwDto; | ||
| 55 | 48 | ||
| 56 | public void run() | 49 | public void run() |
| 57 | { | 50 | { |
| 58 | scheduledExecutorService.scheduleWithFixedDelay(() -> { | 51 | scheduledExecutorService.scheduleWithFixedDelay(() -> { |
| 59 | if (!isRun) | 52 | if (!isRun) |
| 60 | { | 53 | { |
| 61 | - start(VeiwType.html); | 54 | + start(); |
| 62 | } | 55 | } |
| 63 | },1,1,TimeUnit.SECONDS); | 56 | },1,1,TimeUnit.SECONDS); |
| 64 | 57 | ||
| 65 | } | 58 | } |
| 66 | 59 | ||
| 67 | - public void start(VeiwType veiwType) | 60 | + public void start() |
| 68 | { | 61 | { |
| 69 | if(cameraService.getVideoIsOpen()) //摄像头打开才能识别 | 62 | if(cameraService.getVideoIsOpen()) //摄像头打开才能识别 |
| 70 | { | 63 | { |
| 71 | isRun = true; | 64 | isRun = true; |
| 72 | configurationParameterService.setConfig(ConfigurationParameter.FishGroupImageRecognition,true); | 65 | configurationParameterService.setConfig(ConfigurationParameter.FishGroupImageRecognition,true); |
| 73 | - switch (veiwType) | ||
| 74 | - { | ||
| 75 | - case html: | ||
| 76 | - dsplayVeiwService = new HtmllVeiwServiceImpl(configurationParameterService); | ||
| 77 | - break; | ||
| 78 | - case jfram: | ||
| 79 | - dsplayVeiwService = new JFrameVeiwServiceImpl(configurationParameterService); | ||
| 80 | - break; | ||
| 81 | - default: | ||
| 82 | - dsplayVeiwService = new HtmllVeiwServiceImpl(configurationParameterService); | ||
| 83 | - break; | ||
| 84 | - } | ||
| 85 | VideoCapture videoCapture = cameraService.getVideoCapture(); | 66 | VideoCapture videoCapture = cameraService.getVideoCapture(); |
| 86 | brightnessIdentifyFishRegion(videoCapture); | 67 | brightnessIdentifyFishRegion(videoCapture); |
| 87 | - }else { | ||
| 88 | - logger.info("摄像头未打开"); | ||
| 89 | } | 68 | } |
| 90 | } | 69 | } |
| 91 | 70 | ||
| @@ -123,7 +102,6 @@ public class FishGroupImageRecognitionService { | @@ -123,7 +102,6 @@ public class FishGroupImageRecognitionService { | ||
| 123 | return largestContour; | 102 | return largestContour; |
| 124 | } | 103 | } |
| 125 | 104 | ||
| 126 | - | ||
| 127 | /** | 105 | /** |
| 128 | * 亮度查找水面,透明度过滤鱼群 | 106 | * 亮度查找水面,透明度过滤鱼群 |
| 129 | */ | 107 | */ |
| @@ -140,7 +118,7 @@ public class FishGroupImageRecognitionService { | @@ -140,7 +118,7 @@ public class FishGroupImageRecognitionService { | ||
| 140 | // 获取水域轮廓 | 118 | // 获取水域轮廓 |
| 141 | MatOfPoint largestContour = getDefaultMatOfPoint(previousFrame); | 119 | MatOfPoint largestContour = getDefaultMatOfPoint(previousFrame); |
| 142 | 120 | ||
| 143 | - Long time =1000l; | 121 | + Long time =66l; |
| 144 | if(null != configurationParameterService.getConfig(ConfigurationParameter.IdentificationFrequency)) | 122 | if(null != configurationParameterService.getConfig(ConfigurationParameter.IdentificationFrequency)) |
| 145 | { | 123 | { |
| 146 | time = (Long) configurationParameterService.getConfig(ConfigurationParameter.IdentificationFrequency); | 124 | time = (Long) configurationParameterService.getConfig(ConfigurationParameter.IdentificationFrequency); |
| @@ -148,6 +126,7 @@ public class FishGroupImageRecognitionService { | @@ -148,6 +126,7 @@ public class FishGroupImageRecognitionService { | ||
| 148 | // 逐帧处理视频 | 126 | // 逐帧处理视频 |
| 149 | Mat frame = new Mat(); | 127 | Mat frame = new Mat(); |
| 150 | scheduledExecutorService.scheduleWithFixedDelay(() -> { | 128 | scheduledExecutorService.scheduleWithFixedDelay(() -> { |
| 129 | + try { | ||
| 151 | Boolean fishGroupImageRecognition = ((Boolean)configurationParameterService.getConfig(ConfigurationParameter.FishGroupImageRecognition)); | 130 | Boolean fishGroupImageRecognition = ((Boolean)configurationParameterService.getConfig(ConfigurationParameter.FishGroupImageRecognition)); |
| 152 | Boolean isread = videoCapture.read(frame); | 131 | Boolean isread = videoCapture.read(frame); |
| 153 | logger.info("逐帧处理视频,开始处理的判断参数:鱼群图像识别是否开启 {}、摄像头是否可读取 {}",fishGroupImageRecognition,isread); | 132 | logger.info("逐帧处理视频,开始处理的判断参数:鱼群图像识别是否开启 {}、摄像头是否可读取 {}",fishGroupImageRecognition,isread); |
| @@ -165,11 +144,14 @@ public class FishGroupImageRecognitionService { | @@ -165,11 +144,14 @@ public class FishGroupImageRecognitionService { | ||
| 165 | if (fishGroupImageRecognition && isread) { | 144 | if (fishGroupImageRecognition && isread) { |
| 166 | identify(frame,largestContour); | 145 | identify(frame,largestContour); |
| 167 | } | 146 | } |
| 168 | - },0,time, TimeUnit.MILLISECONDS); | ||
| 169 | - | 147 | + }catch (Exception e) |
| 148 | + { | ||
| 149 | + logger.error("识别错误",e); | ||
| 170 | } | 150 | } |
| 171 | 151 | ||
| 152 | + },0,time, TimeUnit.MILLISECONDS); | ||
| 172 | 153 | ||
| 154 | + } | ||
| 173 | 155 | ||
| 174 | /** | 156 | /** |
| 175 | * 识别 | 157 | * 识别 |
| @@ -206,13 +188,15 @@ public class FishGroupImageRecognitionService { | @@ -206,13 +188,15 @@ public class FishGroupImageRecognitionService { | ||
| 206 | double absValue = deviceService.controlDevice(area); | 188 | double absValue = deviceService.controlDevice(area); |
| 207 | configurationParameterService.setConfig(ConfigurationParameter.absValue,absValue); | 189 | configurationParameterService.setConfig(ConfigurationParameter.absValue,absValue); |
| 208 | 190 | ||
| 191 | + veiwDto = new VeiwDto(frame,binaryImage,new Double(area).intValue(),absValue); | ||
| 192 | + | ||
| 209 | // 显示图像 | 193 | // 显示图像 |
| 210 | logger.info("是否显示{},客户端数量{}",configurationParameterService.getConfig(ConfigurationParameter.ifVeiw),WebSocketClien.webSocketSet.size()); | 194 | logger.info("是否显示{},客户端数量{}",configurationParameterService.getConfig(ConfigurationParameter.ifVeiw),WebSocketClien.webSocketSet.size()); |
| 211 | // 在图像上显示结果 | 195 | // 在图像上显示结果 |
| 196 | + logger.info("socket数量{}",WebSocketClien.webSocketSet.size()); | ||
| 212 | if((Boolean)configurationParameterService.getConfig(ConfigurationParameter.ifVeiw) && WebSocketClien.webSocketSet.size()>0) | 197 | if((Boolean)configurationParameterService.getConfig(ConfigurationParameter.ifVeiw) && WebSocketClien.webSocketSet.size()>0) |
| 213 | { | 198 | { |
| 214 | - logger.info("socket数量{}",WebSocketClien.webSocketSet.size()); | ||
| 215 | - dsplayVeiwService.veiw(new VeiwDto(frame,binaryImage,new Double(area).intValue(),absValue)); | 199 | + new HtmllVeiwServiceImpl(configurationParameterService).veiw(veiwDto); |
| 216 | } | 200 | } |
| 217 | } | 201 | } |
| 218 | 202 | ||
| @@ -267,4 +251,12 @@ public class FishGroupImageRecognitionService { | @@ -267,4 +251,12 @@ public class FishGroupImageRecognitionService { | ||
| 267 | 251 | ||
| 268 | return binaryImage; | 252 | return binaryImage; |
| 269 | } | 253 | } |
| 254 | + | ||
| 255 | + public VeiwDto getVeiwDto() { | ||
| 256 | + return veiwDto; | ||
| 257 | + } | ||
| 258 | + | ||
| 259 | + public void setVeiwDto(VeiwDto veiwDto) { | ||
| 260 | + this.veiwDto = veiwDto; | ||
| 261 | + } | ||
| 270 | } | 262 | } |
| @@ -3,38 +3,52 @@ package com.zhonglai.luhui.smart.feeder.service; | @@ -3,38 +3,52 @@ package com.zhonglai.luhui.smart.feeder.service; | ||
| 3 | import com.google.gson.JsonObject; | 3 | import com.google.gson.JsonObject; |
| 4 | import com.ruoyi.common.utils.GsonConstructor; | 4 | import com.ruoyi.common.utils.GsonConstructor; |
| 5 | import com.zhonglai.luhui.smart.feeder.domain.Register; | 5 | import com.zhonglai.luhui.smart.feeder.domain.Register; |
| 6 | +import com.zhonglai.luhui.smart.feeder.dto.ConfigDto; | ||
| 7 | +import com.zhonglai.luhui.smart.feeder.dto.VeiwDto; | ||
| 6 | import com.zhonglai.luhui.smart.feeder.dto.commd.FeederCommd06Response; | 8 | import com.zhonglai.luhui.smart.feeder.dto.commd.FeederCommd06Response; |
| 7 | import com.zhonglai.luhui.smart.feeder.dto.commd.FeederCommdDto; | 9 | import com.zhonglai.luhui.smart.feeder.dto.commd.FeederCommdDto; |
| 8 | import com.zhonglai.luhui.smart.feeder.dto.commd.FeederTimer; | 10 | import com.zhonglai.luhui.smart.feeder.dto.commd.FeederTimer; |
| 9 | import com.zhonglai.luhui.smart.feeder.util.FeederCommdUtil; | 11 | import com.zhonglai.luhui.smart.feeder.util.FeederCommdUtil; |
| 10 | import com.zhonglai.luhui.smart.feeder.util.PenetrateUtil; | 12 | import com.zhonglai.luhui.smart.feeder.util.PenetrateUtil; |
| 11 | -import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; | ||
| 12 | -import org.eclipse.paho.client.mqttv3.MqttCallbackExtended; | ||
| 13 | -import org.eclipse.paho.client.mqttv3.MqttException; | ||
| 14 | -import org.eclipse.paho.client.mqttv3.MqttMessage; | 13 | +import org.eclipse.paho.client.mqttv3.*; |
| 15 | import org.slf4j.Logger; | 14 | import org.slf4j.Logger; |
| 16 | import org.slf4j.LoggerFactory; | 15 | import org.slf4j.LoggerFactory; |
| 17 | import org.springframework.beans.factory.annotation.Autowired; | 16 | import org.springframework.beans.factory.annotation.Autowired; |
| 17 | +import org.springframework.beans.factory.annotation.Value; | ||
| 18 | import org.springframework.stereotype.Component; | 18 | import org.springframework.stereotype.Component; |
| 19 | 19 | ||
| 20 | import java.util.HashMap; | 20 | import java.util.HashMap; |
| 21 | import java.util.List; | 21 | import java.util.List; |
| 22 | import java.util.Map; | 22 | import java.util.Map; |
| 23 | +import java.util.concurrent.ScheduledExecutorService; | ||
| 23 | 24 | ||
| 24 | @Component | 25 | @Component |
| 25 | public class MqttCallback implements MqttCallbackExtended { | 26 | public class MqttCallback implements MqttCallbackExtended { |
| 26 | 27 | ||
| 28 | + private static final Logger log = LoggerFactory.getLogger(MqttCallback.class); | ||
| 27 | @Autowired | 29 | @Autowired |
| 28 | private ConfigurationParameterService configurationParameterService; | 30 | private ConfigurationParameterService configurationParameterService; |
| 29 | 31 | ||
| 30 | @Autowired | 32 | @Autowired |
| 31 | private SerialPortService serialPortService; | 33 | private SerialPortService serialPortService; |
| 32 | 34 | ||
| 33 | - private static final Logger log = LoggerFactory.getLogger(MqttCallback.class); | 35 | + @Autowired |
| 36 | + private SrsService srsService; | ||
| 37 | + | ||
| 38 | + private MqttClient mqttclient; | ||
| 39 | + | ||
| 40 | + | ||
| 41 | + @Value("#{'${mqtt.topics}'.split(',')}") | ||
| 42 | + private List<String> topics; | ||
| 34 | 43 | ||
| 35 | @Override | 44 | @Override |
| 36 | public void connectComplete(boolean b, String s) { | 45 | public void connectComplete(boolean b, String s) { |
| 37 | log.info("连接成功"); | 46 | log.info("连接成功"); |
| 47 | + try { | ||
| 48 | + subscribe(); | ||
| 49 | + } catch (MqttException e) { | ||
| 50 | + throw new RuntimeException(e); | ||
| 51 | + } | ||
| 38 | } | 52 | } |
| 39 | 53 | ||
| 40 | @Override | 54 | @Override |
| @@ -42,6 +56,12 @@ public class MqttCallback implements MqttCallbackExtended { | @@ -42,6 +56,12 @@ public class MqttCallback implements MqttCallbackExtended { | ||
| 42 | log.error("连接丢失",cause); | 56 | log.error("连接丢失",cause); |
| 43 | } | 57 | } |
| 44 | 58 | ||
| 59 | + public MqttCallback setMqttClient(MqttClient mqttclient) | ||
| 60 | + { | ||
| 61 | + this.mqttclient = mqttclient; | ||
| 62 | + return this; | ||
| 63 | + } | ||
| 64 | + | ||
| 45 | @Override | 65 | @Override |
| 46 | public void messageArrived(String topic, MqttMessage message) throws Exception { | 66 | public void messageArrived(String topic, MqttMessage message) throws Exception { |
| 47 | log.info("收到消息 {}",message); | 67 | log.info("收到消息 {}",message); |
| @@ -53,9 +73,9 @@ public class MqttCallback implements MqttCallbackExtended { | @@ -53,9 +73,9 @@ public class MqttCallback implements MqttCallbackExtended { | ||
| 53 | { | 73 | { |
| 54 | String str = new String(bs); | 74 | String str = new String(bs); |
| 55 | JsonObject jsonObject = GsonConstructor.get().fromJson(str, JsonObject.class); | 75 | JsonObject jsonObject = GsonConstructor.get().fromJson(str, JsonObject.class); |
| 56 | - if(jsonObject.has("1")) | 76 | + if(jsonObject.has("10_1")) //投料机控制 |
| 57 | { | 77 | { |
| 58 | - JsonObject controlData = jsonObject.get("1").getAsJsonObject(); | 78 | + JsonObject controlData = jsonObject.get("10_1").getAsJsonObject(); |
| 59 | 79 | ||
| 60 | Map<Integer, FeederTimer> timerMap = new HashMap<>(); | 80 | Map<Integer, FeederTimer> timerMap = new HashMap<>(); |
| 61 | for (String key:controlData.keySet()) | 81 | for (String key:controlData.keySet()) |
| @@ -85,24 +105,23 @@ public class MqttCallback implements MqttCallbackExtended { | @@ -85,24 +105,23 @@ public class MqttCallback implements MqttCallbackExtended { | ||
| 85 | } | 105 | } |
| 86 | } | 106 | } |
| 87 | } | 107 | } |
| 88 | - else if(jsonObject.has("armbian")) | 108 | + else if(jsonObject.has("0")) //主机 |
| 89 | { | 109 | { |
| 90 | - JsonObject armbian = jsonObject.get("armbian").getAsJsonObject(); | ||
| 91 | - for (String key:armbian.keySet()) | 110 | + ConfigDto configDto = GsonConstructor.get().fromJson(jsonObject.get("0").toString(),ConfigDto.class); |
| 111 | + configurationParameterService.setConfig(configDto.getConfigurationParameter(),configDto.getValue()); | ||
| 112 | + } | ||
| 113 | + else if(jsonObject.has("1_1")) //探头 | ||
| 92 | { | 114 | { |
| 93 | - switch (key) | 115 | + VeiwDto veiwDto = GsonConstructor.get().fromJson(jsonObject.get("1_1").toString(),VeiwDto.class); |
| 116 | + if(null != veiwDto.getPush_camera()) | ||
| 94 | { | 117 | { |
| 95 | - case "penetrate": | ||
| 96 | - int penetrate = armbian.get("penetrate").getAsInt(); | ||
| 97 | - switch (penetrate) | 118 | + switch (veiwDto.getPush_camera()) |
| 98 | { | 119 | { |
| 99 | case 0: | 120 | case 0: |
| 100 | - PenetrateUtil.stop(); | 121 | + srsService.stop(); |
| 101 | break; | 122 | break; |
| 102 | case 1: | 123 | case 1: |
| 103 | - PenetrateUtil.start(); | ||
| 104 | - break; | ||
| 105 | - } | 124 | + srsService.run(300); |
| 106 | break; | 125 | break; |
| 107 | } | 126 | } |
| 108 | } | 127 | } |
| @@ -117,4 +136,8 @@ public class MqttCallback implements MqttCallbackExtended { | @@ -117,4 +136,8 @@ public class MqttCallback implements MqttCallbackExtended { | ||
| 117 | // 成功发出消息 | 136 | // 成功发出消息 |
| 118 | log.info("成功发出消息 messageid{}",token); | 137 | log.info("成功发出消息 messageid{}",token); |
| 119 | } | 138 | } |
| 139 | + | ||
| 140 | + private void subscribe() throws MqttException { | ||
| 141 | + mqttclient.subscribe(topics.toArray(new String[topics.size()])); | ||
| 142 | + } | ||
| 120 | } | 143 | } |
lh-modules/lh-smart-feeder/src/main/java/com/zhonglai/luhui/smart/feeder/service/SrsService.java
0 → 100644
| 1 | +package com.zhonglai.luhui.smart.feeder.service; | ||
| 2 | + | ||
| 3 | +import com.ruoyi.common.utils.DateUtils; | ||
| 4 | +import com.zhonglai.luhui.smart.feeder.config.OpenCVConfig; | ||
| 5 | +import com.zhonglai.luhui.smart.feeder.draw.FishRegionPanel; | ||
| 6 | +import com.zhonglai.luhui.smart.feeder.dto.VeiwDto; | ||
| 7 | +import com.zhonglai.luhui.smart.feeder.opencv.OpenCVUtil; | ||
| 8 | +import com.zhonglai.luhui.smart.feeder.util.OpenCVUtils; | ||
| 9 | +import org.bytedeco.ffmpeg.global.avcodec; | ||
| 10 | +import org.bytedeco.javacv.*; | ||
| 11 | +import org.bytedeco.javacv.Frame; | ||
| 12 | +import org.opencv.core.*; | ||
| 13 | +import org.opencv.core.Point; | ||
| 14 | +import org.opencv.imgproc.Imgproc; | ||
| 15 | +import org.opencv.videoio.VideoCapture; | ||
| 16 | +import org.slf4j.Logger; | ||
| 17 | +import org.slf4j.LoggerFactory; | ||
| 18 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 19 | +import org.springframework.beans.factory.annotation.Value; | ||
| 20 | +import org.springframework.stereotype.Service; | ||
| 21 | + | ||
| 22 | +import javax.swing.*; | ||
| 23 | +import java.awt.*; | ||
| 24 | +import java.awt.image.BufferedImage; | ||
| 25 | +import java.util.ArrayList; | ||
| 26 | +import java.util.List; | ||
| 27 | +import java.util.concurrent.ScheduledExecutorService; | ||
| 28 | +import java.util.concurrent.TimeUnit; | ||
| 29 | + | ||
| 30 | +@Service | ||
| 31 | +public class SrsService { | ||
| 32 | + private static final Logger log = LoggerFactory.getLogger(SrsService.class); | ||
| 33 | + | ||
| 34 | + private static final String MP4_FILE_PATH = "C:\\Users\\123\\Pictures\\2.mp4"; | ||
| 35 | + @Value("${sys.srs_push_address}") | ||
| 36 | + private String SRS_PUSH_ADDRESS; | ||
| 37 | +// private String SRS_PUSH_ADDRESS="rtmp://119.23.218.181:21935/live/70094a59d1d991d"; | ||
| 38 | + @Autowired | ||
| 39 | + private ScheduledExecutorService scheduledExecutorService; | ||
| 40 | + | ||
| 41 | + @Autowired | ||
| 42 | + private FishGroupImageRecognitionService fishGroupImageRecognitionService; | ||
| 43 | + | ||
| 44 | + private FFmpegFrameRecorder recorder; | ||
| 45 | + | ||
| 46 | + private OpenCVFrameConverter.ToMat converter = new OpenCVFrameConverter.ToMat(); | ||
| 47 | + public Frame getOpencvFrame(Mat frame) | ||
| 48 | + { | ||
| 49 | + return converter.convert(frame); | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + | ||
| 53 | + private boolean isPush = false; | ||
| 54 | + | ||
| 55 | + private int endTime = 0; | ||
| 56 | + public void run(int time) throws Exception { | ||
| 57 | + endTime = DateUtils.getNowTimeMilly()+time; | ||
| 58 | + if(!isPush) | ||
| 59 | + { | ||
| 60 | + VeiwDto veiwDto = fishGroupImageRecognitionService.getVeiwDto(); | ||
| 61 | + init(veiwDto.getFrame().width(),veiwDto.getFrame().height()+200); | ||
| 62 | + scheduledExecutorService.schedule(() -> { | ||
| 63 | + while (endTime-DateUtils.getNowTimeMilly()>0) | ||
| 64 | + { | ||
| 65 | + Mat mat = drawChart(fishGroupImageRecognitionService.getVeiwDto().getFrame(),fishGroupImageRecognitionService.getVeiwDto().getAbsValue()); | ||
| 66 | + push(mat); | ||
| 67 | + } | ||
| 68 | + stop(); | ||
| 69 | + },1, TimeUnit.SECONDS); | ||
| 70 | + } | ||
| 71 | + } | ||
| 72 | + public void stop() | ||
| 73 | + { | ||
| 74 | + endTime = 0; | ||
| 75 | + isPush =false; | ||
| 76 | + close(); | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + | ||
| 80 | + public SrsService init(int frameWidth,int frameHeight) throws Exception | ||
| 81 | + { | ||
| 82 | + log.info("视频宽度[{}],视频高度[{}]", | ||
| 83 | + frameWidth, | ||
| 84 | + frameHeight | ||
| 85 | + ); | ||
| 86 | + | ||
| 87 | + // 实例化FFmpegFrameRecorder,将SRS的推送地址传入 | ||
| 88 | + recorder = new FFmpegFrameRecorder(SRS_PUSH_ADDRESS, | ||
| 89 | + frameWidth, | ||
| 90 | + frameHeight); | ||
| 91 | + | ||
| 92 | + // 设置编码格式 | ||
| 93 | + recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); | ||
| 94 | + | ||
| 95 | + // 设置封装格式 | ||
| 96 | + recorder.setFormat("flv"); | ||
| 97 | + | ||
| 98 | + // 初始化帧录制器,例如数据结构(音频流、视频流指针,编码器), | ||
| 99 | + // 调用av_guess_format方法,确定视频输出时的封装方式, | ||
| 100 | + // 媒体上下文对象的内存分配, | ||
| 101 | + // 编码器的各项参数设置 | ||
| 102 | + recorder.start(); | ||
| 103 | + | ||
| 104 | + return this; | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + public Mat drawChart(Mat src,double area) | ||
| 108 | + { | ||
| 109 | + // 创建一个新的Mat对象,它的高度为200,它的宽度与原来的Mat对象相同 | ||
| 110 | + Mat curveArea = Mat.zeros(200, src.cols(), src.type()); | ||
| 111 | + | ||
| 112 | + // 计算曲线的y坐标 | ||
| 113 | + int y = (int) (200 - (area * 200) / (src.cols() * src.rows())); | ||
| 114 | + | ||
| 115 | + System.out.println(y); | ||
| 116 | + // 声明曲线的控制点 | ||
| 117 | + MatOfPoint curve = new MatOfPoint(); | ||
| 118 | + | ||
| 119 | + // 创建曲线的控制点数组 | ||
| 120 | + List<Point> points = addPoint(curveArea,area); | ||
| 121 | + | ||
| 122 | + // 将控制点数组设置给曲线 | ||
| 123 | + Point[] pointArray = points.toArray(new Point[0]); | ||
| 124 | + curve.fromArray(pointArray); | ||
| 125 | + | ||
| 126 | + // 绘制曲线 | ||
| 127 | + List<MatOfPoint> curveList = new ArrayList<>(); | ||
| 128 | + curveList.add(curve); | ||
| 129 | + Imgproc.polylines(curveArea, curveList, false, new Scalar(255, 255, 255), 2); | ||
| 130 | + | ||
| 131 | + // 将curveArea拼接到原来的Mat对象上 | ||
| 132 | + Mat pushmat = new Mat(); | ||
| 133 | + List<Mat> mats = new ArrayList<>(); | ||
| 134 | + mats.add(src); | ||
| 135 | + mats.add(curveArea); | ||
| 136 | + Core.vconcat(mats, pushmat); | ||
| 137 | + return pushmat; | ||
| 138 | + } | ||
| 139 | + | ||
| 140 | + public void push(Mat pushmat) { | ||
| 141 | + OpenCVFrameConverter.ToMat converter = new OpenCVFrameConverter.ToMat(); | ||
| 142 | + Frame frame = converter.convert(pushmat); | ||
| 143 | + push(frame); | ||
| 144 | + } | ||
| 145 | + | ||
| 146 | + public void push(Frame frame) { | ||
| 147 | + // 取出的每一帧,都推送到SRS | ||
| 148 | + try { | ||
| 149 | + recorder.record(frame); | ||
| 150 | + } catch (FrameRecorder.Exception e) { | ||
| 151 | + throw new RuntimeException(e); | ||
| 152 | + } | ||
| 153 | + } | ||
| 154 | + | ||
| 155 | + public void close() | ||
| 156 | + { | ||
| 157 | + if(null != recorder) | ||
| 158 | + { | ||
| 159 | + // 关闭帧录制器 | ||
| 160 | + try { | ||
| 161 | + recorder.close(); | ||
| 162 | + } catch (FrameRecorder.Exception e) { | ||
| 163 | + throw new RuntimeException(e); | ||
| 164 | + } | ||
| 165 | + recorder = null; | ||
| 166 | + } | ||
| 167 | + | ||
| 168 | + } | ||
| 169 | + // 创建一个MatOfPoint对象来表示曲线 | ||
| 170 | + private List<Integer> listArea = new ArrayList<>(); | ||
| 171 | + | ||
| 172 | + /** | ||
| 173 | + * 根据反光查找水面 | ||
| 174 | + * @return | ||
| 175 | + */ | ||
| 176 | + public Mat fish(Mat src) { | ||
| 177 | + | ||
| 178 | + //读取和预处理图像 | ||
| 179 | + Mat gray = new Mat(); | ||
| 180 | + Imgproc.cvtColor(src, gray, Imgproc.COLOR_BGR2GRAY); // 转为灰度图像 | ||
| 181 | + | ||
| 182 | + //水面反射检测 | ||
| 183 | + Mat threshold = new Mat(); | ||
| 184 | + double maxValue = 255; // 阈值 | ||
| 185 | + Imgproc.threshold(gray, threshold,100, maxValue, Imgproc.THRESH_BINARY); // 阈值化 | ||
| 186 | + | ||
| 187 | + //鱼群检测 | ||
| 188 | + Mat hierarchy = new Mat(); | ||
| 189 | + List<MatOfPoint> contours = new ArrayList<>(); | ||
| 190 | + Imgproc.findContours(threshold, contours, hierarchy, Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE); // 寻找轮廓 | ||
| 191 | + | ||
| 192 | + //计算鱼群区域大小 | ||
| 193 | + double area = getArea(contours); | ||
| 194 | + | ||
| 195 | + Mat mat = drawChart(src,area); | ||
| 196 | + | ||
| 197 | + return mat; | ||
| 198 | + } | ||
| 199 | + | ||
| 200 | + private static Image convertMatToImage(Mat mat) { | ||
| 201 | + BufferedImage bufferedImage = OpenCVUtils.matToBufferedImage(mat); | ||
| 202 | + return bufferedImage.getScaledInstance(mat.width(), mat.height(), Image.SCALE_SMOOTH); | ||
| 203 | + } | ||
| 204 | + | ||
| 205 | + int maxSize = 100; | ||
| 206 | + | ||
| 207 | + private List<Point> addPoint(Mat src, double area) | ||
| 208 | + { | ||
| 209 | + int panelWidth = src.width(); | ||
| 210 | + int panelHeight = src.height(); | ||
| 211 | + if(listArea.size()==maxSize) | ||
| 212 | + { | ||
| 213 | + listArea.remove(0); | ||
| 214 | + } | ||
| 215 | + | ||
| 216 | + int max = new Double(area).intValue(); | ||
| 217 | + int min = new Double(area).intValue(); | ||
| 218 | + if(listArea.size()>0) | ||
| 219 | + { | ||
| 220 | + max = listArea.stream().max(Integer::compare).get(); | ||
| 221 | + min = listArea.stream().min(Integer::compare).get(); | ||
| 222 | + } | ||
| 223 | + | ||
| 224 | + List<Point> points= new ArrayList<>(); | ||
| 225 | + | ||
| 226 | + for (int i = 0; i < listArea.size(); i++) { | ||
| 227 | + int dataPoint = listArea.get(i); | ||
| 228 | + int x = (int) ((double) i / listArea.size() * panelWidth); | ||
| 229 | + int y = (int) ((double) (dataPoint - min) / (max - min) * panelHeight); | ||
| 230 | + | ||
| 231 | + if (i != 0) { | ||
| 232 | + points.add(new Point(x,y)); | ||
| 233 | + } | ||
| 234 | + } | ||
| 235 | + listArea.add(new Double(area).intValue()); | ||
| 236 | + return points; | ||
| 237 | + | ||
| 238 | + } | ||
| 239 | + | ||
| 240 | + /** | ||
| 241 | + * 计算鱼群面积 | ||
| 242 | + * @param contours | ||
| 243 | + * @return | ||
| 244 | + */ | ||
| 245 | + private double getArea(List<MatOfPoint> contours) { | ||
| 246 | + // 找到最大区域 | ||
| 247 | + double maxArea = 0; | ||
| 248 | + int maxAreaIndex = -1; | ||
| 249 | + double allArea = 0; | ||
| 250 | + for (int i = 0; i < contours.size(); i++) { | ||
| 251 | + double area = Imgproc.contourArea(contours.get(i)); | ||
| 252 | + if (area > maxArea) { | ||
| 253 | + maxArea = area; | ||
| 254 | + maxAreaIndex = i; | ||
| 255 | + } | ||
| 256 | + allArea += area; | ||
| 257 | + } | ||
| 258 | + | ||
| 259 | + //删除最大 | ||
| 260 | + if(-1 != maxAreaIndex) | ||
| 261 | + { | ||
| 262 | + contours.remove(maxAreaIndex); | ||
| 263 | + } | ||
| 264 | + | ||
| 265 | + // 返回总面积 | ||
| 266 | + return allArea; | ||
| 267 | + } | ||
| 268 | + | ||
| 269 | + | ||
| 270 | + public static void main(String[] args) { | ||
| 271 | + OpenCVConfig.loadOpenCv(args); | ||
| 272 | + SrsService srsService = new SrsService(); | ||
| 273 | + FishRegionPanel fishRegionPanel = new FishRegionPanel(); | ||
| 274 | + int i=0; | ||
| 275 | + while (i++<10) | ||
| 276 | + { | ||
| 277 | + VideoCapture videoCapture = OpenCVUtil.readVideoCaptureForVideo(""); | ||
| 278 | + Mat previousFrame = new Mat(); | ||
| 279 | + if (!videoCapture.read(previousFrame)) { | ||
| 280 | + System.out.println("无法读取视频帧"); | ||
| 281 | + return; | ||
| 282 | + } | ||
| 283 | + | ||
| 284 | + try { | ||
| 285 | + if(null == srsService.recorder || !srsService.recorder.isInterleaved()) | ||
| 286 | + { | ||
| 287 | + srsService.init(previousFrame.width(),previousFrame.height()); | ||
| 288 | + } | ||
| 289 | + } catch (Exception e) { | ||
| 290 | + throw new RuntimeException(e); | ||
| 291 | + } | ||
| 292 | + | ||
| 293 | + Mat src = new Mat(); | ||
| 294 | + while (videoCapture.read(src)) | ||
| 295 | + { | ||
| 296 | + Mat mat = srsService.fish(src); | ||
| 297 | + fishRegionPanel.getLblImage().setIcon(new ImageIcon(convertMatToImage(mat))); | ||
| 298 | + fishRegionPanel.getFrame().repaint(); | ||
| 299 | + OpenCVFrameConverter.ToMat converter = new OpenCVFrameConverter.ToMat(); | ||
| 300 | + Frame frame = converter.convert(mat); | ||
| 301 | + srsService.push(frame); | ||
| 302 | + } | ||
| 303 | + | ||
| 304 | + } | ||
| 305 | + srsService.close(); | ||
| 306 | + | ||
| 307 | + } | ||
| 308 | +} |
| @@ -37,13 +37,6 @@ public class TerminalService { | @@ -37,13 +37,6 @@ public class TerminalService { | ||
| 37 | @Value("${mqtt.clientId}") | 37 | @Value("${mqtt.clientId}") |
| 38 | private String clientId; | 38 | private String clientId; |
| 39 | 39 | ||
| 40 | - @Value("#{'${mqtt.topics}'.split(',')}") | ||
| 41 | - private List<String> topics; | ||
| 42 | - | ||
| 43 | - | ||
| 44 | - @Value("#{'${mqtt.mqtt_usernames}'.split(',')}") | ||
| 45 | - private List<String> mqtt_usernames; | ||
| 46 | - | ||
| 47 | @Value("${mqtt.username}") | 40 | @Value("${mqtt.username}") |
| 48 | private String username; | 41 | private String username; |
| 49 | @Value("${mqtt.password}") | 42 | @Value("${mqtt.password}") |
| @@ -53,7 +46,6 @@ public class TerminalService { | @@ -53,7 +46,6 @@ public class TerminalService { | ||
| 53 | log.info("-----------开始启动mqtt监听服务--------------------"); | 46 | log.info("-----------开始启动mqtt监听服务--------------------"); |
| 54 | init(); | 47 | init(); |
| 55 | connect(); | 48 | connect(); |
| 56 | - subscribe(); | ||
| 57 | 49 | ||
| 58 | Map<String,Object> dmap = new HashMap<>(); | 50 | Map<String,Object> dmap = new HashMap<>(); |
| 59 | Map<String,Object> map = new HashMap<>(); | 51 | Map<String,Object> map = new HashMap<>(); |
| @@ -76,7 +68,7 @@ public class TerminalService { | @@ -76,7 +68,7 @@ public class TerminalService { | ||
| 76 | options.setConnectionTimeout(15); | 68 | options.setConnectionTimeout(15); |
| 77 | //设置断开后重新连接 | 69 | //设置断开后重新连接 |
| 78 | options.setAutomaticReconnect(true); | 70 | options.setAutomaticReconnect(true); |
| 79 | - mqttclient.setCallback(mqttCallback); | 71 | + mqttclient.setCallback(mqttCallback.setMqttClient(mqttclient)); |
| 80 | } | 72 | } |
| 81 | 73 | ||
| 82 | private void connect() throws MqttException { | 74 | private void connect() throws MqttException { |
| @@ -85,10 +77,6 @@ public class TerminalService { | @@ -85,10 +77,6 @@ public class TerminalService { | ||
| 85 | mqttclient.connect(options); | 77 | mqttclient.connect(options); |
| 86 | } | 78 | } |
| 87 | 79 | ||
| 88 | - public void subscribe() throws MqttException { | ||
| 89 | - mqttclient.subscribe(topics.toArray(new String[topics.size()])); | ||
| 90 | - } | ||
| 91 | - | ||
| 92 | public void publish(String topic, MqttMessage message) throws MqttException { | 80 | public void publish(String topic, MqttMessage message) throws MqttException { |
| 93 | mqttclient.publish(topic,message); | 81 | mqttclient.publish(topic,message); |
| 94 | } | 82 | } |
| @@ -118,4 +106,5 @@ public class TerminalService { | @@ -118,4 +106,5 @@ public class TerminalService { | ||
| 118 | log.error("关闭失败",e); | 106 | log.error("关闭失败",e); |
| 119 | } | 107 | } |
| 120 | } | 108 | } |
| 109 | + | ||
| 121 | } | 110 | } |
| 1 | +package com.zhonglai.luhui.smart.feeder.service.impl; | ||
| 2 | + | ||
| 3 | +import com.zhonglai.luhui.smart.feeder.dto.VeiwDto; | ||
| 4 | +import com.zhonglai.luhui.smart.feeder.service.ConfigurationParameterService; | ||
| 5 | +import com.zhonglai.luhui.smart.feeder.service.DisplayVeiwService; | ||
| 6 | + | ||
| 7 | +public class SrsVeiwServiceImpl implements DisplayVeiwService { | ||
| 8 | + private ConfigurationParameterService configurationParameterService; | ||
| 9 | + | ||
| 10 | + public SrsVeiwServiceImpl(ConfigurationParameterService configurationParameterService) { | ||
| 11 | + this.configurationParameterService = configurationParameterService; | ||
| 12 | + } | ||
| 13 | + @Override | ||
| 14 | + public void veiw(VeiwDto veiwDto) { | ||
| 15 | + | ||
| 16 | + } | ||
| 17 | +} |
| 1 | -# 开发环境配置 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 | ||
| 1 | +# 开发环境配置 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 |
-
请 注册 或 登录 后发表评论