opencv 視訊處理相關

xzyun2011發表於2021-11-22

包含視訊格式知識(編解碼和封裝格式);如何獲取視訊資訊及視訊編解碼格式;opencv讀取及儲存視訊,及opencv fourcc編碼格式

一、基礎知識

視訊的編解碼格式和封裝格式

參考如山似水 視訊編碼與封裝⽅式詳解

參考迷之程式設計師 opencv視訊編碼格式

參考Alex Chung 視訊的編解碼格式 - 知乎

常⻅的AVI、RMVB、MKV、ASF、WMV、MP4、3GP、FLV等⽂件(.字尾)其實只能算是⼀種封裝標準。 ⼀個完整的視訊⽂件是由⾳頻和視訊兩部分組成的,例如H264、Xvid等就是視訊編碼格式,MP3、AAC等就是⾳頻編碼格式

常⽤視訊編碼⽅式

Xvid(MPEG4),H264,MPEG1,MPEG2 (感興趣的可以瞭解下DivX和XviD的故事,這兩兄弟,前者收費,後者開源,用後者就對了)

常⻅儲存封裝格式

總體上說AVI和RM是⽬前最常⻅的格式,⽽AVI由於先天缺陷不利於⽹絡傳輸;m2ts和mkv是先進的下⼀ 代標準,今後可能逐步流⾏。WMV和ASF通常是微軟MPEG4演算法的儲存格式, DAT和MPG是MPEG1演算法編碼的⽂件的儲存⽅式,其中DAT主要⽤於VCD,VOB則是MPEG2 演算法編碼的⽂件的儲存⽅式,通常⽤於DVD。

python使用ffmpeg 獲取視訊檔案資訊

!!!注意使用以下命令安裝包,不然會使用報錯!!!

pip install ffmpeg-python

參考程式碼

import ffmpeg

input_video = './data/rafting.avi'

if __name__ == "__main__":
    
    probe = ffmpeg.probe(input_video)

    video_stream_info = probe["streams"][0]
    audio_stream_info = probe["streams"][1]
    format_info = probe["format"]
    # show video codec info
    print("codec_type: {0} | codec_name: {1}| codec_long_name: {2}".format(video_stream_info["codec_type"],
                                                                           video_stream_info["codec_name"],
                                                                           video_stream_info["codec_long_name"]))
    # show audo codec info                                                 
    print("codec_type: {0} | codec_name: {1}| codec_long_name: {2}".format(audio_stream_info["codec_type"],
                                                                           audio_stream_info["codec_name"],
                                                                           audio_stream_info["codec_long_name"]))
    # show container(encapsulation) format
    print("filename:{0} | format_name: {1} | format_long_name: {2}".format(format_info["filename"],
                                                                           format_info["format_name"],
                                                                           format_info["format_long_name"]))

參考視訊資訊輸出樣例

{'streams': [{'index': 0, 'codec_name': 'msmpeg4v2', 'codec_long_name': 'MPEG-4 part 2 Microsoft variant version 2', 'codec_type': 'video', 'codec_time_base': '1/12', 'codec_tag_string': 'MP42', 'codec_tag': '0x3234504d', 'width': 1920, 'height': 1080, 'coded_width': 1920, 'coded_height': 1080, 'closed_captions': 0, 'has_b_frames': 0, 'pix_fmt': 'yuv420p', 'level': -99, 'refs': 1, 'r_frame_rate': '12/1', 'avg_frame_rate': '12/1', 'time_base': '1/12', 'start_pts': 0, 'start_time': '0.000000', 'duration_ts': 19999, 'duration': '1666.583333', 'bit_rate': '2422022', 'nb_frames': '19999', 'disposition': {'default': 0, 'dub': 0, 'original': 0, 'comment': 0, 'lyrics': 0, 'karaoke': 0, 'forced': 0, 'hearing_impaired': 0, 'visual_impaired': 0, 'clean_effects': 0, 'attached_pic': 0, 'timed_thumbnails': 0}}], 'format': { ...}

二、opencv視訊相關操作

1.視訊資訊讀取相關

首先讀取視訊檔案,函式部分使用方式如下

video_reader = cv2.VideoCapture('test.mp4')

cv2.VideoCapture()

如果傳的引數是數字,表示使用攝像頭。如 cv2.VideoCapture(0),表示使用計算機第一個攝像頭。

如果傳的是一個視訊的地址,則表示讀取本地視訊。這裡我只用第二種,給一個視訊的絕對路徑並讀取它。另有如下兩常用函式:

  • cv2.VideoCapture().isOpened() 檢測視訊讀取狀態是否正常
  • cv2.VideoCapture().read() 獲取視訊某一幀,返回兩個值,第一個是布林值,表示“這一幀”是否獲取正確;第二個值是這一幀的內容,是一個矩陣。

獲取視訊的基本資訊

例如獲取視訊的編解碼資訊 FOURCC ,例如輸出 1145656920

print( int(video_reader.get(cv2.CAP_PROP_FOURCC)))    
## 或者直接整數引數替代,參考下面表格
print(int(video_reader.get(6)))   

**cv2.VideoCapture.get引數 ** 參考官網

FOURCC

關於fourCC的一段講述

FourCC is a 4-byte code used to specify the video codec. The list of available codes can be found in fourcc.org. It is platform dependent. Following codecs work fine: In Fedora: DIVX, XVID, MJPG, X264, WMV1, WMV2. ( XVID is more preferable. MJPG results in high size video. X264 gives very small size video ) In Windows: DIVX ( more to be tested and added )

FourCC code is passed as cv2.VideoWriter_fourcc('M','J','P','G') or cv2.VideoWriter_fourcc(\*'MJPG) for MJPG.

這裡針對FOURCC專門寫一下,可以看到例如上面的輸出 1145656920,opencv中預設把FOURCC從字元轉為int型別對應的轉換原理可以參考維基中的Technical details。

int轉換為四位的字元,參考以下python程式碼

def decode_fourcc(cc):
    return "".join([chr((int(cc) >> 8 * i) & 0xFF) for i in range(4)])
    
decode_fourcc(1145656920)
'XVID'

或者參考這c++程式碼

unsigned int f = (unsigned)capture.get(cv::CAP_PROP_FOURCC);
char fourcc[] = {
		(char)f, // First character is lowest bits
		(char)(f >> 8), // Next character is bits 8-15
		(char)(f >> 16), // Next character is bits 16-23
		(char)(f >> 24), // Last character is bits 24-31
		'\0' // and don't forget to terminate
	};
cout << "the return int fourcc was: " << f << endl;
cout << "FourCC for this video was: " << fourcc << endl;
/*執行結果為:
the return int fourcc was: 1145656920
FourCC for this video was: XVID
*/

或者這個線上轉換的, 線上int fourCC轉字元;另外opencv有函式自動把四位字元的fourCC轉為int

cv2.VideoWriter_fourcc(*'XVID')     ###  1145656920

一些常見的fourCC 字元和 integer 對照表

字元 對應integer
"XVID" 1145656920
"MJPG" 1196444237
"X264" 875967064
"DIB" 541215044
"WMV1" 827739479
"WMV2" 844516695

3. 讀取視訊相關

這一部分比較簡單,網上教程也很多,貼一個程式碼就行

    success = True
    video_reader = cv2.VideoCapture(video_path)
    while success and video_reader.isOpened():
        # get a frame
        success, frame = video_reader.read()
        # show a frame
        cv2.imshow("capture", frame)
        if cv2.waitKey(100) & 0xFF == ord('q'):
            break
    video_reader.release()
    cv2.destroyAllWindows() 

3. 儲存視訊相關

cv2.VideoWriter()

儲存視訊需要使用cv2.VideoWriter()函式

VideoWriter(filename, fourcc, fps, frameSize[, isColor]) -> <VideoWriter object>

引數說明:

比較重要的三個fourcc 指定編碼格式,注意格式和對應的字尾匹配;frameSize 視訊解析度,一定要確保寫入的影像和此解析度一致,如果像改解析度得先把圖resize再儲存成特定解析度;isColor,True,輸入圖必須是RGB,否則無法儲存,但是卻不會報錯,只不過發現儲存的視訊為空的,也打不開

  • filename,要儲存的視訊路徑
  • fourcc,視訊壓縮幀的編碼codec,例如 cv2.VideoWriter_fourcc('M', 'P', '4', '2') 或者 cv2.VideoWriter_fourcc(*"MP42") 表示使用 MPEG-4.2 codec, 可以參考這個: 可以使用的fourcc列表大全
  • fps,輸出視訊的幀率
  • frameSize,輸出視訊每幀影像的大小,要和寫入的那幀圖大小一直,不然會有問題
  • isColor,如果非零,編碼器將希望得到彩色幀並進行編碼;否則,是灰度幀(只有在Windows下支援這個標誌)

附加一個關於fourCC的說明

四個字元用來表示壓縮幀的codec 例如:
CV_FOURCC(‘P’,‘I’,‘M’,‘1’) = MPEG-1 codec
CV_FOURCC(‘M’,‘J’,‘P’,‘G’) = motion-jpeg codec
CV_FOURCC(‘M’, ‘P’, ‘4’, ‘2’) = MPEG-4.2 codec
CV_FOURCC(‘D’, ‘I’, ‘V’, ‘3’) = MPEG-4.3 codec
CV_FOURCC(‘D’, ‘I’, ‘V’, ‘X’) = MPEG-4 codec
CV_FOURCC(‘U’, ‘2’, ‘6’, ‘3’) = H263 codec
CV_FOURCC(‘I’, ‘2’, ‘6’, ‘3’) = H263I codec
CV_FOURCC(‘F’, ‘L’, ‘V’, ‘1’) = FLV1 codec
NOTE:生成檔案佔用空間最小的編碼方式是MPEG-4.2 codec。在VideoWriter類的建構函式引數為CV_FOURCC(‘M’, ‘P’, ‘4’, ‘2’) 。
最大的是MPEG-1 codec,對應在VideoWriter類的建構函式引數為CV_FOURCC(‘P’,‘I’,‘M’,‘1’) ,所佔磁碟空間是前者的5.7倍。所以如果需要24小時全天候錄製監控,可以優先使用MPEG-4.2的編解碼方式。
若編碼器代號為 -1,則執行時會彈出一個編碼器選擇框.

原文連結:https://blog.csdn.net/qiu931110/article/details/85174069

例子

先定義輸出檔案

    fps_cv = video_reader.get(cv2.CAP_PROP_FPS)  ### 視訊fps, opencv檢測到的
    fourcc = cv2.VideoWriter_fourcc(*'XVID')     ### 儲存視訊的格式
    h, w, c = frame.shape
    out = cv2.VideoWriter(save_path, fourcc, fps_cv, (w, h), isColor=True)  ## 儲存視訊

然後一遍讀視訊每幀一遍儲存成新的視訊

    success = True
    video_reader = cv2.VideoCapture(video_path)
    while success and video_reader.isOpened():
        # get a frame
        success, frame = video_reader.read()
        ### save frame
        out.write(frame)
    out.release()  ### 完成儲存,釋放
    video_reader.release()

各種視訊格式測試

儲存1080p的視訊,共300幀的內容,H.265 和H.264暫未測試,opencv需要相關的依賴包

解析度 格式 需要時間 檔案大小
1920*1080 'XVID' MPEG-4 codec 1.7377230167388915 6.2MB
1920*1080 ‘MP42’ MPEG-4.2 codec 1.7837894439697266 6.1MB
1920*1080 "DIVX" MPEG-4 codec 1.7331401348114013 6.2MB
1920*1080 "DIV3" MPEG-4.3 codec 3.3492454290390015 6.1MB

相關文章