自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

OpenCV Android 之 VideoCapture類

開發(fā) 前端
總的來說,我們可以使用VideoCapture進(jìn)行視頻幀的遍歷,并在遍歷過程中對每一幀數(shù)據(jù)進(jìn)行編輯修改操作。我們?nèi)绻胧褂?openCV 對視頻每一幀進(jìn)行操作之后,再存儲為視頻。那么就還需要結(jié)合VideoWriter 進(jìn)行存儲。

1. 介紹

首先,需要明確一個根本問題。OpenCV 是一個基于 Apache2.0 許可(開源)發(fā)行的跨平臺計算機(jī)視覺和機(jī)器學(xué)習(xí)軟件庫。它實際上各種圖像處理和計算機(jī)視覺方面的通用算法的集中庫。

簡而言之就是:處理圖片。

通常都是使用 OpenCV 來進(jìn)行各種圖片處理和計算。所以它并不是一個視頻編解碼庫。不要想著使用 OpenCV 來進(jìn)行視頻播放

所有使用 OpenCV 進(jìn)行播放視頻,實際上都是將視頻轉(zhuǎn)圖片了,再一張張圖片在切換顯示,編解碼和效率是遠(yuǎn)遠(yuǎn)沒有專門的視頻播放器效率高的。

如果要播放視頻,還是建議使用 FFmpeg 處理。

而我們可以通過OpenCV將視頻進(jìn)行解碼成Mat文件,進(jìn)行操作,并將編輯之后的結(jié)果存儲為視頻。

可以將相機(jī)拍攝的結(jié)果,進(jìn)行實時處理之后。存儲為視頻等操作。

而使用到的就是VideoWriter? 和 VideoCapture類了。

以下內(nèi)容基于:OpenCV 4.6.0 版本API進(jìn)行的介紹和使用。

2. VideoCapture

用于從視頻文件、圖像序列或相機(jī)捕獲視頻的類。這個類提供了針對視頻的各種捕獲方法。

提供了幾種方法:

1.獲取每一幀數(shù)據(jù),轉(zhuǎn)為Mat。

2.獲取視頻的一些配置信息,例如時長,F(xiàn)PS,幀數(shù),寬高等等。

初始化如下:

VideoCapture videoCapture = new VideoCapture(); //創(chuàng)建一個VideoCapture對象

我們其實在創(chuàng)建過程中的時候,也可以進(jìn)行初始化傳參。這些構(gòu)造初始化時傳的參數(shù)和調(diào)用open()方法傳的參數(shù)實際是一樣的。

PS:使用 OpenCV 的方法時,請注意需要提前進(jìn)行初始化加載 OpenCV 庫。否則會出現(xiàn)相關(guān)類找不到而崩潰

OpenCVLoader.initDebug(false);//加載OpenCV庫

2.1 加載 open() 方法

下面不管是相機(jī)加載,還是網(wǎng)絡(luò)地址加載。我在 Android 端上沒有成功。只有加載本地視頻成功了。

加載攝像頭應(yīng)該是 Android 本身不支持的原因造成的。嘗試了各種 cameraId 值和相關(guān) apiPreference 都失敗了。(我們可以使用CameraX加載攝像頭并進(jìn)行處理和存儲)

加載網(wǎng)絡(luò)視頻失敗我估計,應(yīng)該是因為 openCV 默認(rèn)編譯的 Android SDK 中沒有相關(guān)依賴造成的。

(如果是缺少依賴庫造成的,希望能夠有明白的小伙伴指點一下吧。各種嘗試我都失敗了)。

boolean isOpen = videoCapture.open("/storage/emulated/0/Android/data/com.zinyan.demo/files/demo.mp4", Videoio.CAP_ANDROID); //加載本地視頻

boolean isOpen = videoCapture.open(0); //加載攝像頭

boolean isOpen = videoCapture.open("https://host:port/script_name?script_params|auth", Videoio.CAP_ANDROID); //加載網(wǎng)絡(luò)視頻。

open方法傳遞主要是以下一種參數(shù):

  • String filename:文件地址,可以是Url地址也可以是本地文檔地址。
  • int index:相機(jī)id, 如果0 會調(diào)用設(shè)備默認(rèn)的后置攝像頭。
  • int apiPreference: api首選項。該參數(shù)為:Videoio.CAP_ANY,Videoio.CAP_DSHOW,Videoio.CAP_ANDROID等.

VideoCapture? 中傳入的apiPrefreence的可選參數(shù)列表如下所示:

// C++: enum VideoCaptureAPIs
public static final int
CAP_ANY = 0,
CAP_VFW = 200,
CAP_V4L = 200,
CAP_V4L2 = CAP_V4L,
CAP_FIREWIRE = 300,
CAP_FIREWARE = CAP_FIREWIRE,
CAP_IEEE1394 = CAP_FIREWIRE,
CAP_DC1394 = CAP_FIREWIRE,
CAP_CMU1394 = CAP_FIREWIRE,
CAP_QT = 500,
CAP_UNICAP = 600,
CAP_DSHOW = 700,
CAP_PVAPI = 800,
CAP_OPENNI = 900,
CAP_OPENNI_ASUS = 910,
CAP_ANDROID = 1000,
CAP_XIAPI = 1100,
CAP_AVFOUNDATION = 1200,
CAP_GIGANETIX = 1300,
CAP_MSMF = 1400,
CAP_WINRT = 1410,
CAP_INTELPERC = 1500,
CAP_REALSENSE = 1500,
CAP_OPENNI2 = 1600,
CAP_OPENNI2_ASUS = 1610,
CAP_GPHOTO2 = 1700,
CAP_GSTREAMER = 1800,
CAP_FFMPEG = 1900,
CAP_IMAGES = 2000,
CAP_ARAVIS = 2100,
CAP_OPENCV_MJPEG = 2200,
CAP_INTEL_MFX = 2300,
CAP_XINE = 2400;

調(diào)用open()方法后,如果加載成功了就會返回true,失敗則返回false。

由于,我只是加載本地視頻能夠?qū)崿F(xiàn)成功加載。所以下面的介紹也是基于該成功之后進(jìn)行的。

在Android端中,如果想能夠正確的打開視頻并進(jìn)行解析。apiPrefreence的值只有:

Videoio.CAP_ANY? 或者 Videoio.CAP_ANDROID才能正確加載視頻

返回的isOpen才是true。示例如下:

boolean isOpen = videoCapture.open(fileUrl, Videoio.CAP_ANY);

boolean isOpen = videoCapture.open(fileUrl, Videoio.CAP_ANDROID);

我有嘗試過使用CAP_FFMPEG當(dāng)做值,進(jìn)行加載。

boolean isOpen = videoCapture.open(fileUrl, Videoio.CAP_FFMPEG);

//錯誤輸出如下內(nèi)容:
com.zinyan.demo E/cv::error(): OpenCV(4.6.0) Error: Requested object was not found (could not open directory: /data/app/com.zinyan.demo-Wr3nLeu2TTtG12e53ogTGw==/base.apk!/lib/arm64-v8a) in glob_rec, file /build/master_pack-android/opencv/modules/core/src/glob.cpp, line 267

應(yīng)該是默認(rèn)的OpenCV Android SDK中。并沒有FFmpeg相關(guān)庫。

所以想通過https或者rtsp等協(xié)議加載在線視頻也失敗。原因在于openCV 預(yù)編譯的Android SDK中,并沒有那么多第三方項目。可能是需要我們自己配置吧。

PS:自己配置編譯,有點繁瑣。我也沒有進(jìn)行過嘗試。

當(dāng)我們加載成功視頻之后。就可以進(jìn)行解析操作了。

2.2 解析 read(),grab()和retrieve()方法

這三個方法主要就是用來獲取視頻的每一幀的數(shù)據(jù),并將幀數(shù)據(jù)轉(zhuǎn)為Mat對象。

請注意哦,它們獲取的Mat對象是BGR格式的。

例如:獲取當(dāng)前幀:

Mat m = new Mat();
videoCapture.read(m);
//我們就能夠得到當(dāng)前幀了。
//官方建議我們不要直接操作獲取的Mat對象。我們可以進(jìn)行拷貝之后再對Mat進(jìn)行操作
Mat temp =m.clone()

除此之外,還有以下方法也可以獲取當(dāng)前幀:

boolean isFrame =videoCapture.grab(); //從視頻文件或捕獲設(shè)備中抓取下一幀。抓取成功為true,否則為false
Mat tt =new Mat();
boolean isRetrieve =videoCapture.retrieve(tt); //解碼并返回抓取的視頻幀。如果沒有幀返回false。

其實read()? 是grab()+retrieve()方法的合集。

grab()方法只是檢測視頻幀,不會解析視頻幀。所以它速度比較快。

retrieve()?方法會進(jìn)行視頻幀的解析。會比grab()方法更耗時。這兩個方法通常都是一起使用的。

但是,大部分情況下都是使用read()+循環(huán),遍歷整個視頻的所有幀,并進(jìn)行處理。

while (videoCapture.read(mat)) {
Mat m = new Mat();
Imgproc.cvtColor(mat, m, Imgproc.COLOR_BGR2HSV_FULL);
}

read():方法返回的false時,代表視頻已經(jīng)沒有下一幀了。也就是解析到最后一幀了。

通過循環(huán)的方式,可以快速的解析視頻中的每一幀數(shù)據(jù),并轉(zhuǎn)為Mat進(jìn)行處理。

注意,VideoCapture 在調(diào)用 read()? 獲取視頻幀之后。一直獲取到最后之后。不會回到第一幀獲取。我們只能重新調(diào)用open()方法再次加載才行。

2.3 修改 set()和get()方法

我們除了可以遍歷視頻幀數(shù)據(jù)以外。還可以通過get()方法獲取視頻的相關(guān)信息。

示例如下:

double ftp = videoCapture.get(Videoio.CAP_PROP_FPS);
double width = videoCapture.get(Videoio.CAP_PROP_FRAME_WIDTH);
double count = videoCapture.get(Videoio.CAP_PROP_FRAME_COUNT);
double htight = videoCapture.get(Videoio.CAP_PROP_FRAME_HEIGHT);

這個方法要傳入的是 propId 值,該值的取值參數(shù)有如下:

Videoio.CAP_PROP_POS_MSEC = 0,
Videoio.CAP_PROP_POS_FRAMES = 1,
Videoio.CAP_PROP_POS_AVI_RATIO = 2,
Videoio.CAP_PROP_FRAME_WIDTH = 3,
Videoio.CAP_PROP_FRAME_HEIGHT = 4,
Videoio.CAP_PROP_FPS = 5,
Videoio.CAP_PROP_FOURCC = 6,
Videoio.CAP_PROP_FRAME_COUNT = 7,
Videoio.CAP_PROP_FORMAT = 8,
Videoio.CAP_PROP_MODE = 9,
Videoio.CAP_PROP_BRIGHTNESS = 10,
Videoio.CAP_PROP_CONTRAST = 11,
Videoio.CAP_PROP_SATURATION = 12,
Videoio.CAP_PROP_HUE = 13,
Videoio.CAP_PROP_GAIN = 14,
Videoio.CAP_PROP_EXPOSURE = 15,
Videoio.CAP_PROP_CONVERT_RGB = 16,
Videoio.CAP_PROP_WHITE_BALANCE_BLUE_U = 17,
Videoio.CAP_PROP_RECTIFICATION = 18,
Videoio.CAP_PROP_MONOCHROME = 19,
Videoio.CAP_PROP_SHARPNESS = 20,
Videoio.CAP_PROP_AUTO_EXPOSURE = 21,
Videoio.CAP_PROP_GAMMA = 22,
Videoio.CAP_PROP_TEMPERATURE = 23,
Videoio.CAP_PROP_TRIGGER = 24,
Videoio.CAP_PROP_TRIGGER_DELAY = 25,
Videoio.CAP_PROP_WHITE_BALANCE_RED_V = 26,
Videoio.CAP_PROP_ZOOM = 27,
Videoio.CAP_PROP_FOCUS = 28,
Videoio.CAP_PROP_GUID = 29,
Videoio.CAP_PROP_ISO_SPEED = 30,
Videoio.CAP_PROP_BACKLIGHT = 32,
Videoio.CAP_PROP_PAN = 33,
Videoio.CAP_PROP_TILT = 34,
Videoio.CAP_PROP_ROLL = 35,
Videoio.CAP_PROP_IRIS = 36,
Videoio.CAP_PROP_SETTINGS = 37,
Videoio.CAP_PROP_BUFFERSIZE = 38,
Videoio.CAP_PROP_AUTOFOCUS = 39,
Videoio.CAP_PROP_SAR_NUM = 40,
Videoio.CAP_PROP_SAR_DEN = 41,
Videoio.CAP_PROP_BACKEND = 42,
Videoio.CAP_PROP_CHANNEL = 43,
Videoio.CAP_PROP_AUTO_WB = 44,
Videoio.CAP_PROP_WB_TEMPERATURE = 45,
Videoio.CAP_PROP_CODEC_PIXEL_FORMAT = 46,
Videoio.CAP_PROP_BITRATE = 47;

但是,我們很多時候使用上面的關(guān)鍵字進(jìn)行獲取的數(shù)據(jù),結(jié)果值都是0

這是因為 openCV 使用的解析器在獲取視頻時,如果正確獲取了相關(guān)配置項參數(shù)就會返回具體指。如果沒有正確獲取就會返回0了。

在我的實際使用過程中,大部分都是取不到真實數(shù)據(jù)。而寬高等數(shù)據(jù),還得讀取過一幀數(shù)據(jù)之后,才能取到值。

videoCapture.set(int propId, double value)

而set()方法,就是將這些配置信息修改到 VideoCapture 中。

如果在open()方法中調(diào)用的解碼器支持的話。就可以將這些配置信息添加到解碼器中。進(jìn)行生效了。

我們?nèi)绻皇菃渭冋{(diào)用 openCV 的 API。那么set()方法使用空間不大了。

2.4 關(guān)閉 release()

當(dāng)我們遍歷完畢,可以調(diào)用release()方法 關(guān)閉文件的加載。釋放內(nèi)存。

同時底層C++代碼中的相關(guān)方法也會進(jìn)行釋放。

3. 小結(jié)

總的來說,我們可以使用VideoCapture進(jìn)行視頻幀的遍歷,并在遍歷過程中對每一幀數(shù)據(jù)進(jìn)行編輯修改操作。

我們?nèi)绻胧褂?openCV 對視頻每一幀進(jìn)行操作之后,再存儲為視頻。那么就還需要結(jié)合VideoWriter 進(jìn)行存儲。

默認(rèn)情況下Android下,是可以實現(xiàn)視頻的每一幀獲取,并修改然后存儲為新的視頻文件的。

通過這些方法可以實現(xiàn),例如視頻添加水印,背景替換,黑白轉(zhuǎn)換等等。圖片能實現(xiàn)的一些編輯操作都可以通過獲取每一幀,處理完畢后。再將每一幀存儲為視頻來實現(xiàn)。

openCV 官網(wǎng)說明文檔:

https://docs.opencv.org/4.6.0/d4/d15/groupvideoioflags__base.html#ga023786be1ee68a9105bf2e48c700294d

下一篇簡單介紹下VideoWriter的相關(guān)使用吧。

責(zé)任編輯:武曉燕 來源: Zinyan
相關(guān)推薦

2013-05-20 17:21:34

2013-05-21 09:56:15

2020-07-08 07:56:08

Java工具類包裝類

2013-05-20 17:51:47

Android游戲開發(fā)SurfaceView

2013-05-21 14:10:11

Android游戲開發(fā)SoundPool類同時多音效

2011-06-16 11:13:13

QtQWidget

2021-04-05 08:11:04

Java基礎(chǔ)Calendar類DateFormat類

2023-07-13 08:26:49

Java羅漢增強(qiáng)類

2009-07-22 09:31:59

Scala類類層級Java類

2011-06-16 11:28:48

Qt QApplicati

2022-04-05 20:54:21

OpenCVPython人臉檢測

2010-07-05 16:23:39

UML類圖

2020-04-30 21:30:18

JavaScript前端技術(shù)

2014-07-29 15:57:01

ContentProv

2009-07-08 13:22:30

JDK源碼分析Set

2011-04-22 16:30:50

加電故障

2023-11-09 08:36:51

內(nèi)置工具類Spring

2010-06-30 14:46:49

UML類圖

2015-03-03 15:53:31

Android控件

2014-08-15 13:24:32

Android之SQL
點贊
收藏

51CTO技術(shù)棧公眾號