作者 钟来

模块整理

package com.zhonglai.luhui.smart.feeder.opencv;
import com.ruoyi.common.utils.DESUtil;
import com.ruoyi.common.utils.StringUtils;
import com.zhonglai.luhui.smart.feeder.config.OpenCVConfig;
import com.zhonglai.luhui.smart.feeder.dto.VeiwDto;
import com.zhonglai.luhui.smart.feeder.service.CameraService;
import com.zhonglai.luhui.smart.feeder.service.FFmCameraService;
import com.zhonglai.luhui.smart.feeder.service.impl.HtmllVeiwServiceImpl;
import com.zhonglai.luhui.smart.feeder.service.impl.JFrameVeiwServiceImpl;
import org.bytedeco.javacv.FrameGrabber;
... ... @@ -22,12 +24,43 @@ import java.util.List;
public class OpenCVUtil {
private static String MAC = "78-a6-a0-d2-bd-e1";
private static final Logger logger = LoggerFactory.getLogger(OpenCVUtil.class);
public static void main(String[] args) {
System.out.println(DESUtil.decode("5F06AAC657B2E2B287289D25D950A829", "EXU5RUhI1"));;
}
public static VideoCapture readVideoCaptureForRtsp()
{
FFmCameraService fFmCameraService = new FFmCameraService();
String ip = fFmCameraService.findCameraIp();
if(StringUtils.isEmpty(ip))
{
logger.info("未检测到摄像头{},尝试打开本地视频",MP4_FILE_PATH);
//如果找不到摄像头就找本地视频文件
File file = new File(MP4_FILE_PATH);
if(file.exists() && file.isFile())
{
VideoCapture videoCapture = OpenCVUtil.readVideoCaptureForVideo(MP4_FILE_PATH);
return videoCapture;
}
logger.info("未检测到摄像头!!!");
}
String rtspUrl = "rtsp://admin:Luhui586@"+ip+":554/h264/ch1/main/av_stream";
VideoCapture videoCapture = new VideoCapture(rtspUrl);
while (!videoCapture.isOpened())
{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
return videoCapture;
}
public static VideoCapture readVideoCaptureForVideo(int i)
{
logger.info("初始化摄像头");
... ... @@ -92,7 +125,7 @@ public class OpenCVUtil {
Mat extractedRegion = Mat.zeros(frame.size(), frame.type());
// 将指定的轮廓绘制到新的Mat上
Imgproc.drawContours(extractedRegion, Collections.singletonList(largestContour), 0, new Scalar(255, 255, 255), -1);
Imgproc.drawContours(extractedRegion,Collections.singletonList(largestContour) , 0, new Scalar(255, 255, 255), -1);
// 使用按位与操作提取对应的图像区域
Mat extractedImage = new Mat();
... ... @@ -119,6 +152,9 @@ public class OpenCVUtil {
Mat hierarchy = new Mat();
Imgproc.findContours(binary, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
gray.release();
binary.release();
hierarchy.release();
return contours;
}
... ...
... ... @@ -40,7 +40,7 @@ public class CameraService {
*/
private void openCapture()
{
videoCapture = OpenCVUtil.openCapture();
videoCapture = OpenCVUtil.readVideoCaptureForRtsp();
if(null == videoCapture)
{
return;
... ... @@ -70,7 +70,7 @@ public class CameraService {
{
if(null == scheduledFuture || scheduledFuture.isDone())
{
scheduledFuture = scheduledExecutorService.scheduleAtFixedRate(() -> {
scheduledFuture = scheduledExecutorService.scheduleWithFixedDelay(() -> {
if(!videoIsOpen)
{
openCapture();
... ...
package com.zhonglai.luhui.smart.feeder.service;
import org.bytedeco.javacv.CanvasFrame;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.RuntimeUtil;
import com.ruoyi.common.utils.StringUtils;
import org.bytedeco.ffmpeg.global.avutil;
import org.bytedeco.javacv.*;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.FrameGrabber;
import org.springframework.stereotype.Service;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
@Service
public class FFmCameraService {
public static void main(String[] args) {
// int maxCameraIndex = 10; // 最大尝试的摄像头索引数量
// for (int cameraIndex = 0; cameraIndex < maxCameraIndex; ++cameraIndex) {
// try {
// FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(cameraIndex);
// grabber.start(); // 尝试开始,如果失败将抛出异常
// try {
// // 创建一个窗口用于显示摄像头的视频流
// CanvasFrame frame = new CanvasFrame("Webcam");
//
// // 判断窗口是否关闭
// while (frame.isVisible()) {
// // 抓取一帧视频并将其放在窗口上显示,该操作会阻塞程序,直到下一帧视频可用
// Frame grabbedFrame = grabber.grab();
// frame.showImage(grabbedFrame);
// }
//
// // 关闭窗口
// frame.dispose();
// } finally {
// // 停止抓取
// grabber.stop();
// }
// break; // 如果找到了摄像头并成功打开,就结束循环
// } catch (FrameGrabber.Exception e) {
// // 如果失败,就继续尝试下一个摄像头
// System.out.println("Failed to start the camera with device index: " + cameraIndex);
// }
// }
private FFmpegFrameGrabber grabber;
private static String MAC = "78-a6-a0-d2-bd-e1";
/**
* 查找摄像头
* @return
*/
public String findCameraIp()
{
List<String> list = RuntimeUtil.execForLines("arp", "-a");
for (String str:list)
{
if(str.indexOf(MAC)>=0)
{
// 使用Hutool提取字符串中的IP地址
List<String> ips = ReUtil.findAll("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}", str, 0, new ArrayList<>());
if(null != ips && ips.size()!=0)
{
return ips.get(0);
}
}
}
return null;
}
/**
* 加载摄像头
*/
public void loadCamera()
{
String ip = findCameraIp();
if(StringUtils.isEmpty(ip))
{
System.out.println("没有找到摄像头:"+MAC);
return;
}
String rtspUrl = "rtsp://admin:Luhui586@"+ip+":554/h264/ch1/main/av_stream";
try {
FFmpegFrameGrabber.tryLoad();
} catch (Exception e) {
throw new RuntimeException("Failed to load FFmpeg", e);
}
grabber = new FFmpegFrameGrabber(rtspUrl);
grabber.setVideoOption("fflags", "nobuffer"); // 禁用缓冲
grabber.setVideoOption("rtsp_transport", "tcp"); // 使用TCP传输
avutil.av_log_set_level(avutil.AV_LOG_ERROR); // 设置日志级别
try {
grabber.start();
} catch (Exception e) {
close();
e.printStackTrace();
}
}
public Boolean isOk()
{
try {
return null!=grabber && grabber.grab() != null;
} catch (FrameGrabber.Exception e) {
return false;
}
}
public void close()
{
if(null != grabber)
{
try {
grabber.stop();
grabber.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void display(Frame frame) throws FrameGrabber.Exception {
CanvasFrame canvasFrame = new CanvasFrame("Key Frame Capture", CanvasFrame.getDefaultGamma() / grabber.getGamma());
canvasFrame.dispose();
while (true) {
canvasFrame.showImage(dream(getFrame()));
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
String formattedDateTime = now.format(formatter);
System.out.println("当前时间: " + formattedDateTime);
}
}
public Frame getFrame() {
Frame frame = null;
try {
frame = grabber.grabImage();
if (frame == null) {
//TODO:连续n次为null,进行重连
System.out.println("frame is null");
return null;
}
else{
return frame;
}
} catch (FrameGrabber.Exception e) {
return null;
}
}
private int maxX = 200;
private int POINT_RADIUS = 3;
private int quHeight = 200;
private java.util.List<Double> points = new ArrayList<>();
private BufferedImage dream(Frame frame)
{
BufferedImage image = Java2DFrameUtils.toBufferedImage(frame);
double point = Math.random();
points.add(point);
if (points.size() > maxX) {
points.remove(0);
}
BufferedImage curveImage = new BufferedImage(image.getWidth(), image.getHeight()+quHeight,image.getType());
Graphics2D g2d = curveImage.createGraphics();
// 在图像上绘制曲线
g2d.setColor(Color.RED);
g2d.setStroke(new BasicStroke(POINT_RADIUS));
Double maxY = ArrayUtil.max(points.toArray(new Double[0]));
int vx = image.getWidth()/maxX;
Double vy = quHeight/maxY;
// 绘制动态曲线
for(int i=0;i<points.size()-1;i++)
{
int x = i*vx;
int y = new Double(points.get(i)*vy).intValue();
g2d.drawLine(x, y+image.getHeight(), x+vx, new Double(points.get(i+1)*vy).intValue()+image.getHeight());
}
// 将第一个帧绘制到合并图像的上方
curveImage.createGraphics().drawImage(image, 0, 0, null);
g2d.dispose();
return curveImage;
}
}
... ...
... ... @@ -3,11 +3,12 @@ package com.zhonglai.luhui.smart.feeder.service;
import com.zhonglai.luhui.smart.feeder.config.WebSocketClien;
import com.zhonglai.luhui.smart.feeder.dto.ConfigurationParameter;
import com.zhonglai.luhui.smart.feeder.dto.VeiwDto;
import com.zhonglai.luhui.smart.feeder.dto.VeiwType;
import com.zhonglai.luhui.smart.feeder.opencv.OpenCVUtil;
import com.zhonglai.luhui.smart.feeder.service.impl.HtmllVeiwServiceImpl;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameUtils;
import org.bytedeco.javacv.OpenCVFrameConverter;
import org.bytedeco.opencv.opencv_core.IplImage;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
import org.opencv.core.Scalar;
... ... @@ -65,7 +66,7 @@ public class FishGroupImageRecognitionService {
},1,1,TimeUnit.SECONDS);
}
// 创建FrameConverter对象
public void start()
{
if(cameraService.getVideoIsOpen()) //摄像头打开才能识别
... ... @@ -105,13 +106,15 @@ public class FishGroupImageRecognitionService {
if (area > maxArea) {
maxArea = area;
maxAreaIndex = i;
}else{
matOfPoint.release();
}
}
// 获取最大区域的轮廓
MatOfPoint largestContour = contours.get(maxAreaIndex);
contours.remove(maxAreaIndex);
for(MatOfPoint matOfPoint:contours)
{
matOfPoint.release();
}
firstBinaryImage.release();
hierarchy.release();
... ... @@ -158,8 +161,8 @@ public class FishGroupImageRecognitionService {
logger.info("重新初始化");
cameraService.clean();
}
frame.release();
return;
}
if (fishGroupImageRecognition && isread) {
identify(frame);
... ...