我只是一名搬磚工削饵,無(wú)意侵犯各位大佬知識(shí)產(chǎn)權(quán)生棍。
最近因項(xiàng)目組需要捧杉,開(kāi)始學(xué)圖像處理
所以記錄一下這個(gè)過(guò)程以及經(jīng)驗(yàn)呈宇,希望能幫到大家
學(xué)習(xí)參考資料:
若想系統(tǒng)地學(xué)習(xí),麻煩移步到 github或買(mǎi)書(shū)啃一下
這部分主要講兩個(gè)函數(shù)
- cv2.VideoCapture 創(chuàng)建視頻對(duì)象扒俯,負(fù)責(zé)獲取視頻內(nèi)容
- cv2.VideoWriter() 創(chuàng)建視頻寫(xiě)入對(duì)象奶卓,用來(lái)錄制/保存視頻
其他
- cv2.cvtColor() 將 BGR 彩色圖片轉(zhuǎn)為 灰度圖片
- imwrite() 保存圖片
- cv2.VideoCapture().isOpened() 檢測(cè)視頻讀取狀態(tài)是否正常
- cv2.VideoCapture().read() 獲取視頻某一幀,返回兩個(gè)值撼玄,第一個(gè)是布爾值夺姑,表示“這一幀”是否獲取正確;第二個(gè)值是這一幀的內(nèi)容互纯,是一個(gè)矩陣瑟幕。
接下來(lái)看例子
cv2.VideoCapture()
- 如果傳的參數(shù)是數(shù)字,表示使用攝像頭留潦。如 cv2.VideoCapture(0)只盹,表示使用計(jì)算機(jī)第一個(gè)攝像頭。
- 如果傳的是一個(gè)視頻的地址兔院,則表示讀取本地視頻殖卑。這里我只用第二種,給一個(gè)視頻的絕對(duì)路徑并讀取它
比如:我希望讀取一個(gè)視頻坊萝,截取每一幀圖像并將其轉(zhuǎn)為灰度圖像孵稽,并播放
import cv2
capture = cv2.VideoCapture('/Users/0.mp4') ##假設(shè)我有個(gè)視頻放在(/Users/ 目錄下许起,我是 mac 玩家,win 玩家自行修改)
while(capture.isOpened()): ## 檢測(cè)視頻打開(kāi)是否有問(wèn)題
ret,frame = capture.read() ## 逐幀讀取視頻
gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY) ## 灰度轉(zhuǎn)換
cv2.imshow('frame', gray) ## (播放)看圖
if cv2.waitKey(30) == ord('q'): ## 控制退出菩鲜,選中窗口按'q' (大寫(xiě)不行)
break
capture.release() ## 清內(nèi)存园细,好習(xí)慣
cv2.destroyAllWindows() ## 后面這兩句不寫(xiě),看圖的窗口就關(guān)不了
cv2.waitKey(1)
### 為了上面好看點(diǎn)接校,我把注釋寫(xiě)在下面了
### capture.isOpened()返回的是布爾值猛频,如果成功讀取這一幀,則為 True; 反之為 False
### ret 其實(shí)就是capture.isOpened(), 而 frame 這是獲取的這一幀圖像的內(nèi)容蛛勉,是矩陣格式
### cv2.cvtColor() 將 BGR 彩色圖片轉(zhuǎn)為 灰度圖片
### cv2.imshow() 第一個(gè)參數(shù)是打開(kāi)播放圖像窗口的名字鹿寻,自己隨便命名;第二個(gè)參數(shù)是要看的圖像名稱(chēng)诽凌,就是 gray
### cv2.waitKey()毡熏,它的參數(shù)表示暫停時(shí)間,所以這個(gè)值越大侣诵,視頻播放速度越慢痢法,反之,播放速度越快窝趣,通常設(shè)置為25或30疯暑。 ord 是轉(zhuǎn)碼,因?yàn)?opencv 內(nèi)核是 C++哑舒,用的是 ASCⅡ (我不知道這里說(shuō)的對(duì)不對(duì))
如果我想截取某個(gè)時(shí)間點(diǎn)的圖片。
- 首先我們得知道幻馁,視頻中的每一幀對(duì)應(yīng)多少時(shí)間洗鸵,
- 通過(guò)使用的函數(shù)capture.get(propId),可以獲取視頻(/攝像頭的一些屬性)仗嗦,如 分辨率膘滨、亮度、對(duì)比度等稀拐,我們想知道的幀速度也在這里
- 傳入的參數(shù)是數(shù)字或關(guān)鍵詞都可以火邓。propId是從0~18的數(shù)字,代表不同的屬性德撬,完整的屬性列表可以參考: VideoCaptureProperties 铲咨。
- 如果想修改視頻的屬性,可以用 capture.set(propId,value)來(lái)修改屬性值
github 大佬的經(jīng)驗(yàn)之談:某些攝像頭設(shè)定分辨率等參數(shù)時(shí)會(huì)無(wú)效蜓洪,因?yàn)樗?有固定的分辨率大小支持纤勒,一般可在攝像頭的資料頁(yè)中找到。
import cv2
capture = cv2.VideoCapture('/Users/0.mp4')
timepoint = 10 ###(單位:秒) 想截取視頻中 10s 那一幀
timer = 0 ### 用來(lái)計(jì)算幀數(shù)隆檀,
fps = round(capture.get(5)) ### 1 秒有多少幀, 使用的參數(shù)是5,表示幀速 (要用怎么自己查表)
### 一般來(lái)說(shuō)摇天,1 秒 約等于 24 幀粹湃,我這個(gè)視頻是 23.976023976023978, 所以直接用round(), 四舍五入,將其約等于 24.
while(capture.isOpened()): ## 檢測(cè)視頻打開(kāi)是否有問(wèn)題
timer += 1 ## 開(kāi)始計(jì)算過(guò)去了多少幀
ret,frame = capture.read() ## 逐幀讀取視頻
if timer == timepoint * fps: ## 10秒的時(shí)候,開(kāi)始截圖
cv2.imwrite('/Users/10s.jpg',frame) ## 存圖泉坐,第一個(gè)參數(shù)遞質(zhì)为鳄,第二個(gè)要存的圖是哪個(gè)
break ## 退出
capture.release() ## 清內(nèi)存,好習(xí)慣
如果我看視頻看到某一幀想截圖 (這個(gè)更簡(jiǎn)答了是不是腕让,和第一個(gè)很像)
我們來(lái)個(gè)暗號(hào)济赎,比如 按下鍵盤(pán) ‘s’ 就截圖
import cv2
capture = cv2.VideoCapture('/Users/0.mp4')
while(capture.isOpened()): ## 檢測(cè)視頻打開(kāi)是否有問(wèn)題
ret,frame = capture.read() ## 逐幀讀取視頻
gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY) ## 灰度轉(zhuǎn)換
cv2.imshow('frame', gray) ## (播放)看圖
if cv2.waitKey(30) == ord('s'): ## 控制退出,選中窗口按'q' (大寫(xiě)不行)
cv2.imwrite('/Users/10s.jpg',frame) ### 其實(shí)就多了這個(gè)
break
capture.release() ## 清內(nèi)存记某,好習(xí)慣
cv2.destroyAllWindows() ## 后面這兩句不寫(xiě)司训,看圖的窗口就關(guān)不了
cv2.waitKey(1)
如果我覺(jué)得截圖不過(guò)癮,想截一段動(dòng)畫(huà)(gif) 或 截一段視頻
這次要加上存視頻的函數(shù) cv2.VideoWriter()
思路還是一樣液南,假設(shè)我們想截 第 5 秒到第 10 秒的視頻
cv2.VideoWriter()
先說(shuō)說(shuō)這個(gè)函數(shù)壳猜,它需要四個(gè)參數(shù)
cv2.VideoWriter(filename, fourcc, fps, resolution)
- 第一個(gè)參數(shù) 是文件名,如‘output.avi’ (絕對(duì)路徑滑凉,你保存文件的位置)
- 第二個(gè)參數(shù) 是編碼方式统扳,這里選的是 FourCC碼 (我也沒(méi)搞懂,反正先用著吧)
- 第三個(gè)參數(shù)是幀率 FPS (又叫幀速)畅姊,一般和原視頻一樣咒钟,24,有興趣的可以試試更大或更小的數(shù)字若未,發(fā)現(xiàn)新世界
- 第四個(gè)是分辨率 (每英寸像素Pixel per inch, ppi)
- 480P: 720×480 (寬 × 高
- 720p: 1280×720
- 1080p: 1920×1080
- 可以試試原畫(huà)是 480P 轉(zhuǎn) 1080P 輸出會(huì)變什么樣子 (查原視頻分辨率用 .get(3) 寬朱嘴,.get(4) 高
還有一個(gè)FourCC是用來(lái)指定視頻編碼方式的四字節(jié)碼,所有的編碼可參考 Video Codecs 粗合。如MJPG編碼可以這樣寫(xiě): cv2.VideoWriter_fourcc(*’MJPG’)或cv2.VideoWriter_fourcc(‘M’,’J’,’P’,’G’)
(這個(gè)我也不懂萍嬉,先用著吧)
那開(kāi)始干吧
import cv2
capture = cv2.VideoCapture('/Users/test.mp4')
time1 = 5 ###(單位:秒) 截取開(kāi)始時(shí)間 第5秒
time2 = 10 ###(單位:秒) 截取結(jié)束時(shí)間 第10秒
timer = 0 ### 用來(lái)計(jì)算幀數(shù),
fps = round(capture.get(5)) ### 獲取 1 秒有多少幀
### 定義編碼方式并創(chuàng)建VideoWriter對(duì)象
fourcc = cv2.VideoWriter_fourcc(*'MJPG')
outfile = cv2.VideoWriter('/Users/test_5s.avi',fourcc, 24, (640, 360)) ###我這邊測(cè)試視頻 幀頻是24隙疚,分辨率是640×360, 可以分別用.get(5), .get(3)和.get(4)獲取, 當(dāng)然你也可以改動(dòng)一下試試看什么效果
while(capture.isOpened()): ## 檢測(cè)視頻打開(kāi)是否有問(wèn)題
timer += 1 ## 開(kāi)始計(jì)算過(guò)去了多少幀
ret,frame = capture.read() ## 逐幀讀取視頻
if time1 * fps >= timer: ## 小于 5 秒時(shí)壤追,跳過(guò) (為什么要? 因?yàn)闆](méi)有這個(gè)會(huì)直接跳到 else,break 就結(jié)束了)
pass
elif time1 * fps < timer and timer < time2 * fps: ## 大于 5 秒供屉,小于 10 秒時(shí)行冰,開(kāi)始截視頻
outfile.write(frame) ## outfile 就是創(chuàng)建VideoWriter對(duì)象
else: ## 大于 10 秒的時(shí)候,停止
print('finished')
break ## 退出
capture.release() ## 清內(nèi)存伶丐,好習(xí)慣
OK 啦悼做,是不是很簡(jiǎn)單,快來(lái)試試吧
最后說(shuō)說(shuō)改變一些參數(shù)的結(jié)果
- 幀速撵割,這個(gè)顧名思義贿堰,幀速越大,視頻播放的速度越快啡彬,比如原本1秒是24幀羹与,如果你改成240幀故硅,相當(dāng)于你1秒的時(shí)間播放了原本10秒時(shí)間的內(nèi)容,將幀速改小同理纵搁。
- 分辨率, 別想了吃衅,只要改動(dòng)分辨率,就會(huì)保存失敗(空白文件)腾誉,這也很容易懂徘层,不可能讓你那么容易就提高視頻的清晰度嘛,(降低也不行 doge)