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;// 設備IPprivate 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;}@Overridepublic 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))防止重復實例化。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/14485.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/14485.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/14485.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Raylib 繪制自定義字體的一種套路

Raylib 繪制自定義字體是真的難搞。我的需求是程序可以加載多種自定義字體&#xff0c;英文中文的都有。 我調試了很久成功了&#xff01; 很有用的參考&#xff0c;建議先看一遍&#xff1a; 瞿華&#xff1a;raylib繪制中文內容 個人筆記&#xff5c;Raylib 的字體使用 - …

W801 實現獲取天氣情況

看了小安派&#xff08;AiPi-Eyes 天氣站&#xff09;的源碼&#xff0c;感覺用W801也可以實現。 一、部分源碼 main.c #include "wm_include.h" #include "Lcd_Driver.h"void UserMain(void) {printf("\n user task \n");Lcd_Init();Lcd_Clea…

MySQL主從復制(五):讀寫分離

一主多從架構主要應用場景&#xff1a;讀寫分離。讀寫分離的主要目標是分攤主庫的壓力。 讀寫分離架構 讀寫分離架構一 架構一結構圖&#xff1a; 這種結構模式下&#xff0c;一般會把數據庫的連接信息放在客戶端的連接層&#xff0c;由客戶端主動做負載均衡。也就是說由客戶…

RabbitMQ 消息隊列安裝及入門

市面常見消息隊列中間件對比 技術名稱吞吐量 /IO/并發時效性&#xff08;類似延遲&#xff09;消息到達時間可用性可靠性優勢應用場景activemq萬級高高高簡單易學中小型企業、項目rabbitmq萬級極高&#xff08;微秒&#xff09;高極高生態好&#xff08;基本什么語言都支持&am…

為什么MySQL推薦使用utf8mb4代替utf8?

前言 在MySQL數據庫的世界里&#xff0c;字符集的選擇直接影響著數據的存儲和檢索方式&#xff0c;尤其是對于多語言支持至關重要的應用而言。近年來&#xff0c;utf8mb4字符集逐漸成為MySQL中存儲Unicode字符的標準選擇&#xff0c;逐步取代了傳統的utf8字符集。本文將詳細探…

leetcode124 二叉樹中的最大路徑和-dp

題目 二叉樹中的 路徑 被定義為一條節點序列&#xff0c;序列中每對相鄰節點之間都存在一條邊。同一個節點在一條路徑序列中 至多出現一次 。該路徑 至少包含一個 節點&#xff0c;且不一定經過根節點。 路徑和 是路徑中各節點值的總和。 給你一個二叉樹的根節點 root &…

【Crypto】Rabbit

文章目錄 一、Rabbit解題感悟 一、Rabbit 題目提示很明顯是Rabbit加密&#xff0c;直接解 小小flag&#xff0c;拿下&#xff01; 解題感悟 提示的太明顯了

redis核心面試題二(實戰優化)

文章目錄 10. redis配置mysql實戰優化[重要]11. redis之緩存擊穿、緩存穿透、緩存雪崩12. redis實現分布式session 10. redis配置mysql實戰優化[重要] // 最初實現OverrideTransactionalpublic Product createProduct(Product product) {productRepo.saveAndFlush(product);je…

MQTT 5.0 報文解析 05:DISCONNECT

歡迎閱讀 MQTT 5.0 報文系列 的第五篇文章。在上一篇中&#xff0c;我們已經介紹了 MQTT 5.0 的 PINGREQ 和 PINGRESP 報文。現在&#xff0c;我們將介紹下一個控制報文&#xff1a;DISCONNECT。 在 MQTT 中&#xff0c;客戶端和服務端可以在斷開網絡連接前向對端發送一個 DIS…

手把手教你搭建一個花店小程序商城

如果你是一位花店店主&#xff0c;想要為你的生意搭建一個精美的小程序商城&#xff0c;以下是你將遵循的五個步驟。 步驟1&#xff1a;登錄喬拓云平臺進入后臺 首先&#xff0c;你需要登錄喬拓云平臺的后臺管理頁面。你可以在電腦或移動設備上的瀏覽器中輸入喬拓云的官方網站…

2024.5.26 機器學習周報

目錄 引言 Abstract 文獻閱讀 1、題目 2、引言 3、創新點 4、Motivation 5、naive Lite-HRNet 6、Lite-HRNet 7、實驗 深度學習 解讀SAM(Segment Anything Model) 1、SAM Task 2、SAM Model 2.1、Patch Embedding 2.2、Positiona Embedding 2.3、Transformer …

移動端適配:vw適配方案

vw (Viewport Width) 是一種長度單位&#xff0c;代表視口寬度的百分比。1vw 等于視口寬度的1%。在網頁設計和前端開發中&#xff0c;vw 單位常用于實現響應式設計和屏幕適配&#xff0c;尤其是針對不同尺寸和分辨率的移動設備。 為什么使用vw適配&#xff1f; 響應式: 使用v…

互聯網醫院開發:引領智慧醫療新時代

隨著科技的迅猛發展和互聯網的普及&#xff0c;傳統醫療模式正在迎來一場深刻的變革。互聯網醫院的崛起&#xff0c;打破了時間和空間的限制&#xff0c;為患者和醫療機構帶來了更加便捷、高效、安全的醫療服務體驗。本文將從技術角度深入探討互聯網醫院的開發&#xff0c;包括…

【openpcdet中yaml文件的DATA_AUGMENTOR學習】

提示&#xff1a;文章寫完后&#xff0c;目錄可以自動生成&#xff0c;如何生成可參考右邊的幫助文檔 文章目錄 前言一、代碼二、詳細解釋DISABLE_AUG_LISTAUG_CONFIG_LIST1. gt_sampling2. random_world_flip3. random_world_rotation4. random_world_scaling 總結 前言 提示…

多線程(八)

一、wait和notify 等待 通知 機制 和join的用途類似,多個線程之間隨機調度,引入 wait notify 就是為了能夠從應用層面上,干預到多個不同線程代碼的執行順序.( 這里說的干預,不是影響系統的線程調度策略 內核里的線程調度,仍然是無序的. 相當于是在應用程序…

Pod容器資源限制和探針

目錄 一、資源限制 1.Pod和容器的資源請求和限制 2.CPU 資源單位 案例一 案例二 二、健康檢查&#xff0c;又稱為探針&#xff08;Probe&#xff09; 1.探針的三種規則 2.Probe支持三種檢查方法 3.探測獲得的三種結果 案例一&#xff1a;exec 案例二&#xff1a;htt…

OneMO同行 心級服務:中移物聯OneMO模組助力客戶終端寒冷環境下的穩定運行

中移物聯OneMO模組以客戶為中心&#xff0c;基于中國移動心級服務要求&#xff0c;開展“OneMO同行 心級服務 標定一流”高標服務主題活動&#xff0c;升級“服務內容““服務方式”和“服務意識”&#xff0c;為行業客戶提供全新的服務體驗。 近日&#xff0c;某車載監控設備…

Hive語法學習總結

Hive SQL語法學習總結 hive參數庫操作1.創建庫2.具體案例3.庫的其他操作 表和庫的路徑演示表的操作創建表插入數據 hive參數 一 hive常用交互命令hive -e sql語句hive -f sql文件 //文件中是sql語句二 參數的設置方式一&#xff1a;在客戶端中設置參數(當次有效)set 參數名參…

ACM實訓第十七天

Is It A Tree? 問題 考試時應該做不出來&#xff0c;果斷放棄 樹是一種眾所周知的數據結構&#xff0c;它要么是空的(null, void, nothing)&#xff0c;要么是一個或的集合滿足以下屬性的節點之間有向邊連接的節點較多。 ?只有一個節點&#xff0c;稱為根節點&#xff0c;它…

【Crypto】摩絲

文章目錄 一、摩斯解題感悟 一、摩斯 很明顯莫爾斯密碼 iloveyou還挺浪漫 小小flag&#xff0c;拿下 解題感悟 莫爾斯密碼這種題還是比較明顯的