OpenCV 获取 RTSP 摄像头视频流保存至本地

介绍

Java OpenCV 是一个强大的开源计算机视觉库,它提供了丰富的图像处理和分析功能,越来越多的应用需要使用摄像头来获取实时视频流进行处理和分析。

在 Java 中使用 OpenCV 打开摄像头的基本步骤如下:

  • 确保已经安装了OpenCV库
  • 使用 OpenCV 的 VideoCapture 类来打开摄像头
  • 使用 Mat 类来存储每一帧的图像
  • 使用循环来不断从摄像头中读取帧,并显示这些帧
  • 处理完毕后,释放摄像头资源

安装 OpenCV

下载地址:https://opencv.org/releases

在这里插入图片描述

从 OpenCV 官网下载适合自己操作系统版本的,然后双击安装(实质就是解压),解压完打开文件夹是:

build/
sources/
LICENSE.txt
LICENSE_FFMPEG.txt
README.md.txt

build 是 OpenCV 使用时要用到的一些库文件,而 sources 中则是 OpenCV 官方为我们提供的一些 demo 示例源码

配置环境变量可以不用配置,直接将用到的 dll(opencv_java411.dllopencv_world411.dllopencv_videoio_ffmpeg411_64.dll) 文件复制到 C:\Windows\System32 下即可。

编码实现

将 OpenCV 库添加到 Java 项目的构建路径中,使用 VideoCapture 类来打开摄像头。

添加依赖

<!--openCV 依赖包-->
<dependency>
    <groupId>org.opencv</groupId>
    <artifactId>opencv</artifactId>
    <version>4.1.1</version>
    <scope>system</scope>
    <systemPath>${project.basedir}/src/main/resources/lib/opencv-411.jar</systemPath>
</dependency>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <fork>true</fork> <!-- 如果没有该配置,devtools不会生效 -->
                <includeSystemScope>true</includeSystemScope>
            </configuration>
        </plugin>
    </plugins>
</build>

注:fork、includeSystemScope 不配置,打包不生效。

打开摄像头

package com.demo.utils;

import lombok.extern.slf4j.Slf4j;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.videoio.VideoCapture;
import org.opencv.videoio.VideoWriter;

import static org.opencv.videoio.Videoio.CAP_PROP_FRAME_HEIGHT;
import static org.opencv.videoio.Videoio.CAP_PROP_FRAME_WIDTH;

@Slf4j
public class RtspRecordingUtil {

    public static void main(String[] args) {
        init();
    }

    public static void init() {
        // 加载库
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        
        VideoCapture capture = new VideoCapture();
        capture.open("rtsp://admin:123456@192.168.1.11/Streaming/Channels/101");

        log.info("=======isOpen:{}========", capture.isOpened());
        if (capture.isOpened()) {
            Mat mat = new Mat();
            VideoWriter vw = new VideoWriter();
            Size size = new Size();
            size.width = capture.get(CAP_PROP_FRAME_WIDTH);
            size.height = capture.get(CAP_PROP_FRAME_HEIGHT);

            boolean t = vw.open("F:\\test.avi", VideoWriter.fourcc('M', 'P', '4', '2'), 30, size);
        
            // 录制
            while (capture.read(mat)) {
                vw.write(mat);
            }
            capture.release();
            vw.release();
        }
        log.info("=======结束======");
    }

}

上述示例代码首先加载了 OpenCV 库,并创建了一个 VideoCapture 对象,打开默认摄像头。然后使用一个循环读取每一帧图像写到 VideoWriter 中保存。

打开多个摄像头

要打开多个摄像头,我们可以通过创建多个线程来拉取不同的视频流。

package com.demo.util;

import lombok.extern.slf4j.Slf4j;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.videoio.VideoCapture;
import org.opencv.videoio.VideoWriter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.Duration;
import java.time.Instant;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static org.opencv.videoio.Videoio.CAP_PROP_FRAME_HEIGHT;
import static org.opencv.videoio.Videoio.CAP_PROP_FRAME_WIDTH;

@Slf4j
@Component
public class RtspRecordingUtil {

    // 视频保存地址
    @Value("${video.video-path}")
    private String videoPath;

    // 录制视频的默认时长
    @Value("${video.video-recording-duration}")
    private Long videoRecordingDuration;

    // 默认开启十个线程
    private String DEFAULT_THREAD_POOL = 10;

    ExecutorService executorService = Executors.newFixedThreadPool(DEFAULT_THREAD_POOL);

    {
        /**
         * 将以下三个文件:
         * opencv_java411.dll、
         * opencv_world411.dll、
         * opencv_videoio_ffmpeg411_64.dll
         * 文件拷贝到 C:\Windows\System32 目录下
         */

        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

        // 本地运行可以,打包后找不到文件
        /**
        String path = this.getClass().getClassLoader().getResource("").getPath();
        System.load(path + "lib/dll/opencv_java411.dll");
        System.load(path + "lib/dll/opencv_world411.dll");
        System.load(path + "lib/dll/opencv_videoio_ffmpeg411_64.dll");
        */
    }

    public String recording(String username, String password, String ip, Integer chanelId, String videoName, Integer duration) {
        executorService.submit(new VideoCaptureTask(username, password, ip, chanelId, videoName, duration));
        return "ok";
    }

    class VideoCaptureTask implements Runnable {

        // 设备用户名
        private String username;
        // 设备密码
        private String password;
        // 设备IP
        private String ip;
        // 设备通道号
        private Integer chanelId;
        // 视频名称
        private String videoName;
        // 录制时长
        private Integer duration;

        public VideoCaptureTask(String username, String password, String ip, Integer chanelId, String videoName, Integer duration) {
            this.username = username;
            this.password = password;
            this.ip = ip;
            this.chanelId = chanelId;
            this.videoName = videoName;
            this.duration = duration;
        }

        @Override
        public void run() {
            VideoCapture capture = null;
            VideoWriter vw = null;
            try {

                capture = new VideoCapture(videoName);

                String url = "rtsp://" + username + ":" + password + "@" + ip + "/Streaming/Channels/" + (Objects.nonNull(chanelId) ? chanelId : "1");
                capture.open(url);
                
                log.info("==== VideoCapture 开始....URL: {} ======= isOpened:{}=====", url, capture.isOpened());

                if (capture.isOpened()) {
                    Mat mat = new Mat();
                    Size size = new Size(capture.get(CAP_PROP_FRAME_WIDTH), capture.get(CAP_PROP_FRAME_HEIGHT));

                    // 视频存储地址
                    vw = new VideoWriter();

                    // 判断存储目录是否存在
                    if (Files.notExists(Paths.get(videoPath))) {
                        Files.createDirectories(Paths.get(videoPath));
                    }
                    vw.open(videoPath + videoName + ".avi", VideoWriter.fourcc('M', 'P', '4', '2'), 30, size);

                    Instant start = Instant.now();
                    long seconds = 0;
                    long _duration = Objects.nonNull(duration) ? duration : videoRecordingDuration;
                    while (capture.read(mat) && seconds <= _duration) {
                        vw.write(mat);
                        seconds = Duration.between(start, Instant.now()).getSeconds();
                    }
                } 

                log.info("==== VideoCapture 结束....URL: {} =====", url);
            } catch (Exception e) {
                log.error("==== VideoCapture 异常:{}", e);
            } finally {
                if (Objects.nonNull(capture)) capture.release();
                if (Objects.nonNull(vw)) vw.release();
            }
        }
    }

}

需要处理不同摄像头之间分辨率和帧率的不匹配问题,以及考虑如何有效地管理多个 VideoCapture 实例问题,这里使用视频名称作为摄像头的索引(new VideoCapture(videoName))防止重复实例化。

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 使用OpenCV在Java中获取RTSP视频流可以通过使用OpenCV的VideoCapture类实现。首先,您需要创建一个VideoCapture对象,并使用它的open()方法打开RTSP URL:VideoCapture capture = new VideoCapture(); capture.open("rtsp://<username>:<password>@<ip_address>:<port>/<path>"); 然后,您可以使用read()方法从视频流读取帧:Mat frame = new Mat(); capture.read(frame); ### 回答2: 在Java中使用OpenCV获取RTSP视频流的步骤如下: 1. 首先,确保你已经安装了OpenCV库,并且已经在你的Java项目中引入了相关的库文件。 2. 创建一个新的Java类,并在类中导入OpenCV库: ``` import org.opencv.core.*; import org.opencv.videoio.*; ``` 3. 在代码中创建一个VideoCapture对象,并将RTSP视频流的URL传递给它: ``` String rtspUrl = "rtsp://your_rtsp_video_stream_url"; VideoCapture capture = new VideoCapture(rtspUrl); ``` 4. 检查VideoCapture对象是否已经成功打开了RTSP视频流: ``` if (!capture.isOpened()) { System.out.println("无法打开RTSP视频流!"); return; } ``` 5. 进入一个循环,读取视频帧并进行处理: ``` Mat frame = new Mat(); while (true) { if (capture.read(frame)) { // 在这里对视频帧进行处理,比如显示、保存等 // ... } else { System.out.println("无法读取视频帧!"); break; } } ``` 6. 最后,记得在循环结束后释放VideoCapture对象: ``` capture.release(); ``` 这样,你就可以在Java中使用OpenCV获取RTSP视频流了。注意,根据你所使用的OpenCV版本和操作系统不同,可能需要进行一些额外的配置和处理。 ### 回答3: 在Java中使用OpenCV获取RTSP视频流可以通过以下步骤来实现: 首先,需要确保在项目的构建路径中已经添加了OpenCV库文件。 接下来,可以使用Java中的VideoCapture类来创建一个用于从RTSP源中读取视频流的对象。可以通过传递RTSP的URL作为参数来完成这一步骤,例如: ```java VideoCapture capture = new VideoCapture("rtsp://username:password@ip_address:port/video_stream"); ``` 在上述代码中,"username"和"password"是RTSP的访问凭证,"ip_address"是RTSP服务器的IP地址,"port"是RTSP服务器的端口号,"video_stream"是要获取视频流名称。 接下来,可以使用while循环来持续读取视频帧,并进行处理,直到没有更多的帧可供读取为止。可以使用Mat类来存储每一帧的像素数据,如下所示: ```java Mat frame = new Mat(); while (capture.read(frame)) { // 进行帧处理的代码 } ``` 在循环中,通过调用capture.read(frame)方法来读取每一帧的像素数据,并将其存储在名为"frame"的Mat对象中。可以在循环中加入自己的帧处理代码,例如进行图像处理、人脸检测等。 最后,在不再需要时,记得释放VideoCapture对象的资源,释放内存: ```java capture.release(); ``` 以上就是使用OpenCV在Java中获取RTSP视频流的基本步骤。希望对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值