基于OpenCV創(chuàng)建視頻會(huì)議虛擬背景
點(diǎn)擊上方“小白學(xué)視覺”,選擇加"星標(biāo)"或“置頂”
重磅干貨,第一時(shí)間送達(dá)
本期我們將使用Python和OpenCV為視頻會(huì)議創(chuàng)建虛擬背景。

虛擬背景是當(dāng)前遠(yuǎn)程工作的員工中的熱門話題之一。由于Covid-19的流行,許多人必須通過視頻通話以便繼續(xù)工作。很多視頻會(huì)議的軟件可以設(shè)置虛擬背景,以便用戶建立更友好的氛圍來接聽這些電話。
作為一名程序員,當(dāng)我們第一次使用這樣的虛擬背景時(shí)自然很感興趣。我們都想知道它是如何工作的,可以自己建立這樣的虛擬背景嗎?
接下來,我們將嘗試使用Python和OpenCV使用計(jì)算機(jī)視覺技術(shù)構(gòu)建虛擬背景的基本方法。(雖然效果并不是很好~)
介紹
我們的目的是拍攝視頻,嘗試弄清楚視頻的背景和前景,刪除背景部分,并用圖片(虛擬背景)代替。因?yàn)樵诖隧?xiàng)目中,我們將使用簡單的方法,假設(shè)前景通常具有與背景不同的顏色。首先,讓我們看看我們的工具是什么。
計(jì)算機(jī)視覺
計(jì)算機(jī)視覺是一個(gè)跨學(xué)科領(lǐng)域,涉及計(jì)算機(jī)如何處理和(或)理解圖像和視頻。說這是一個(gè)跨學(xué)科的領(lǐng)域,因?yàn)樗梃b了不同學(xué)科(計(jì)算機(jī)科學(xué),代數(shù),幾何等)的許多概念,并將它們組合起來以解決許多不同而復(fù)雜的任務(wù),例如對(duì)象跟蹤,對(duì)象檢測(cè),?對(duì)象識(shí)別,圖片和視頻中的對(duì)象細(xì)分。
OpenCV
OpenCV是一個(gè)用于解決計(jì)算機(jī)視覺任務(wù)的庫。它是開源的,可用于多種編程語言,包括Python和C ++。它具有大量的計(jì)算機(jī)視覺功能,其中一些基于數(shù)學(xué)和統(tǒng)計(jì)方法,而另一些則基于機(jī)器學(xué)習(xí)。
建立虛擬背景
我為此嘗試的方法如下。我將顯示每個(gè)步驟的代碼片段,并在本文結(jié)尾處,您將獲得完整的代碼。
1. 導(dǎo)入依賴
import numpy as npimport cv2
2.從本地環(huán)境加載視頻并初始化數(shù)據(jù)
ap = cv2.VideoCapture('video6.mp4')ret = TrueframeCounter = 0previousFrame = NonenextFrame = Noneiterations = 0
3.從本地環(huán)境加載替代背景圖像
backgroundImage = cv2.imread("image1.jpg")4.逐幀分割視頻
while (ret):ret, frame = cap.read()
5.每隔兩幀拍攝一次
if frameCounter % 2 == 1:nextFrame = frame==?0:frameCounter = 0previousFrame = frame=?frameCounter?+?1iterations?=?iterations?+?1
6.找到兩個(gè)幀之間的絕對(duì)差并將其轉(zhuǎn)換為灰度->獲得蒙版
if iterations > 2:diff = cv2.absdiff(previousFrame, nextFrame)mask = cv2.cvtColor(diff, cv2.COLOR_BGR2GRAY)
每個(gè)圖像都由像素組成,我們可以將其想象為具有行和列的2D矩陣,并且矩陣中的每個(gè)單元格都是圖像中的像素(當(dāng)然,對(duì)于彩色圖像,我們擁有的尺寸比2大,但為簡單起見,可以忽略)。
我們通過在第一個(gè)圖像中逐個(gè)像素移動(dòng)(因此在第一矩陣中一個(gè)單元一個(gè)像素)并從另一個(gè)圖像中替換對(duì)應(yīng)的像素(因此從另一個(gè)矩陣中替換對(duì)應(yīng)的像素)來獲得差異。
現(xiàn)在的訣竅是:如果在兩幀之間,像素沒有被修改,那么結(jié)果當(dāng)然是0。兩幀之間的像素如何變化?如果視頻是完全靜態(tài)的(圖像中沒有任何動(dòng)靜),則所有像素的每一幀之間的差將為0,因?yàn)闆]有任何更改。但是,如果某物在圖像中移動(dòng),那么我們可以通過檢測(cè)像素差異來識(shí)別某物在圖像中的移動(dòng)位置。我們可以假設(shè),在視頻會(huì)議中,移動(dòng)的事物位于前臺(tái)(即您),而靜態(tài)部分是背景。
那么0到底有什么重要呢?圖像將為每個(gè)像素顯示為0的黑色,我們將利用這一優(yōu)勢(shì)。
7.找到蒙版中超出閾值的單元格-我選擇3作為閾值,當(dāng)然也可以使用不同的值。較大的值將從背景中刪除更多內(nèi)容,但也可能從前景中刪除更多內(nèi)容
th = 3isMask = mask > thnonMask = mask <= th
8.創(chuàng)建一個(gè)空白圖像(每個(gè)單元格為0),其大小為兩個(gè)框架中任何一個(gè)的大小
result = np.zeros_like(nextFrame, np.uint8)9.調(diào)整背景圖像的大小,使其具有與框架相同的大小
resized = cv2.resize(backgroundImage, (result.shape[1], result.shape[0]), interpolation = cv2.INTER_AREA)10.對(duì)于蒙版中大于閾值的每個(gè)單元,請(qǐng)從原始幀進(jìn)行復(fù)制
result[isMask] = nextFrame[isMask]00000000000011.對(duì)于蒙版中低于閾值的每個(gè)單元,請(qǐng)從替代背景圖像進(jìn)行復(fù)制
result[nonMask] = resized[nonMask]12.將結(jié)果框保存到本地環(huán)境
cv2.imwrite("output" + str(iterations) + ".jpg", result)結(jié)果與結(jié)論
那么結(jié)果如何呢?老實(shí)說,我對(duì)結(jié)果感到有些失望。然后,我做了更多的研究,其原因變得更加明顯。為此,您需要一種更高級(jí)的方法,并且大公司在此類問題上投入了大量資源也就不足為奇了。
這是我嘗試的視頻的屏幕截圖。這基本上是我的手在墻前移動(dòng)的視頻。

虛擬背景Python和OpenCV教程-輸入
這是輸出圖像的屏幕截圖。作為背景,我在羅馬尼亞的拉斯諾夫使用了我的照片。

虛擬背景Python和OpenCV教程-輸出
結(jié)果并不滿意,但是我們也從這個(gè)項(xiàng)目中學(xué)到的東西。
創(chuàng)建虛擬背景的其他方法
如果認(rèn)為問題非常復(fù)雜,并且需要的智能水平,那么答案可能是機(jī)器學(xué)習(xí)。
已有深度學(xué)習(xí)模型可以執(zhí)行此類任務(wù)。但是,這樣的模型需要訓(xùn)練大量的數(shù)據(jù)集和大量的處理能力,在撰寫本文時(shí),我還沒有這些能力做這種嘗試。這種深度學(xué)習(xí)模型要解決的任務(wù)稱為圖像分割。
另一種方法是計(jì)算機(jī)視覺方法,用于查找相機(jī)和圖像中的對(duì)象之間的距離。然后,建立一個(gè)閾值,以將前景與背景分開。之后,可以使用與移除背景相同的蒙版,并引入一個(gè)新的蒙版。
交流群
歡迎加入公眾號(hào)讀者群一起和同行交流,目前有SLAM、三維視覺、傳感器、自動(dòng)駕駛、計(jì)算攝影、檢測(cè)、分割、識(shí)別、醫(yī)學(xué)影像、GAN、算法競賽等微信群(以后會(huì)逐漸細(xì)分),請(qǐng)掃描下面微信號(hào)加群,備注:”昵稱+學(xué)校/公司+研究方向“,例如:”張三?+?上海交大?+?視覺SLAM“。請(qǐng)按照格式備注,否則不予通過。添加成功后會(huì)根據(jù)研究方向邀請(qǐng)進(jìn)入相關(guān)微信群。請(qǐng)勿在群內(nèi)發(fā)送廣告,否則會(huì)請(qǐng)出群,謝謝理解~
