|
|
|
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();
|
|
|
|
|
|
|
|
}
|
|
|
|
} |
...
|
...
|
|