項目實踐|如何在較暗環(huán)境進行人臉檢測?
點擊上方“小白學視覺”,選擇加"星標"或“置頂”
重磅干貨,第一時間送達
本文轉自|Datawhale
計算機視覺在人臉檢測領域的應用已經較為成熟,但依然存在較多難點。其中一大難點是光照問題,由于人臉的3D結構,光照投射出的陰影,會加強或減弱原有的人臉特征。如何解決光照問題對人臉檢測帶來的影響呢?

本文目錄:
1. 基本LBP
1.1 概念理解
1.2 主要步驟
2. 圓形領域的LBP算子
2.1 概念理解
2.2 計算方法
3. 旋轉不變的LBP算子
4. 統(tǒng)一化的LBP算子
4.1 理論基礎
4.2 統(tǒng)一化的意義
4.3 收集箱個數(shù)計算
5. 案例實戰(zhàn)
5.1 讀取圖片
5.2 加載級聯(lián)文件
5.3 人臉檢測
5.4 處理臟數(shù)據(jù)
鄰域的類型可分為四鄰域、D鄰域、八鄰域。
四鄰域:該像素點的上下左右四個位置;
D領域:該像素點斜對角線上的四個相鄰位置。
八鄰域:四鄰域與D鄰域的并集。
基本的LBP算子考慮的是像素的八鄰域。
例如,在某些情況下,陽光照射強度更低,導致拍攝圖像的整體亮度降低,但是實際上每個像素之間的差值仍然是固定的。那么在這種情況下,在圖片亮度對LBP特征編碼無影響。
使用一個3*3的矩形,處理待判斷像素點及其鄰域之間的關系。
如果A的像素值大于其鄰近點的像素值,則得到0。 如果A的像素值小于其鄰近點的像素值,則得到1。
如下圖LBP原理示意圖所示,在左側的區(qū)域中,中心點的像素為76,并設置它為此次的閾值。然后現(xiàn)在我們對該中心點的8鄰域做進一步的處理。
將中心點周圍的8個位置中灰度值大于76的像素點處理為1。例如,其鄰域中像素值為128、251、99、213的點,都被處理為1,填入對應的像素點位置上。
將中心點周圍的8個位置中灰度值值小于76的像素點處理為0。例如,其鄰域中像素值為36、9、11、48的點,都被處理為0,填入對應的像素點位置上。
最后得到的二值結果如右圖所示。

步驟2:中心點處理

假設此時有一幅100*100大小的圖像。
在初始化時,將該圖劃分為10*10個Block,其中每個Block的大小為10*10。 對每個Block的像素點提取其LBP特征,并建立一個計算某個“數(shù)字”出現(xiàn)的頻率統(tǒng)計直方圖。 結束時,將生成10*10個統(tǒng)計直方圖,選擇性地對直方圖進行規(guī)范化處理。 連接所有小塊的(規(guī)范化的)直方圖,整合后構成了整個窗口的特征向量,用來描述這幅圖片。 得到特征向量之后,就可以使用各類算法對該圖像進行特定的處理了。
基本LBP算子可以被進一步推廣到使用不同大小和形狀的鄰域。采用圓形的鄰域并結合雙線性插值運算使得我們可以獲得任意半徑和任意數(shù)目的鄰域像素點。該圓形鄰域可以用表示,其中P表示圓形鄰域內參與運算的像素點個數(shù),R表示鄰域的半徑。

假設此時給出了一個半徑為2的8鄰域像素的圓形鄰域,圖中每個方格對應一個像素。
處在方格中心的鄰域點(左、上、右、下4個黑點):以該點所在方格的像素值作為它的值 不在方格中心的鄰域點(斜45°方向的4個黑點):線性插值法確定其值。

同理計算出點2的值如下:
再計算出點1和點2豎直的線性插值。
如下圖所示,黑點代表0,白點代表1,假設初始的灰度值為255。經過7次旋轉,得到7個不同的二進制序列,并分別轉換為相應的十進制數(shù),最后取到最小值“15”為最終中心點的LBP值,且序列為“00001111”。

二進制序列中存在從1到0或者0到1的轉變,可以稱作是一次跳變。下面我們將舉例說明跳變次數(shù)的計算:

對于一個局部二進制模型而言,在將其二進制位串視為循環(huán)的情況下,如果其中包含的從0到1或者從1到0的轉變不多于2個,則稱為統(tǒng)一化模式。所以上例中的模式“01010000”就不屬于統(tǒng)一化模式。
序列中包含的跳變?yōu)?次以上的,可以稱為混合模式。
4.2 統(tǒng)一化的意義
假設圖像分塊區(qū)域大小為,則像素的總數(shù)為360個。如果采用8鄰域像素的標準LBP算子,收集箱(特征)數(shù)目為個,平均到每個收集箱的像素數(shù)目還不到2個。但是在統(tǒng)一化LBP算子的收集箱數(shù)目為59個(58個統(tǒng)一化模式收集箱加上1個非統(tǒng)一化模式收集箱),平均每個收集箱中將含有6個左右的像素點,因此更具有統(tǒng)計意義。
0個轉變(2個):
1個轉變(7 x 2 = 14):01111111,00111111,00011111,00001111,00000111,00000011,00000001。 2個轉變(42):
1 x 2:01111110
總結一下,經過上面的計算知道,這種統(tǒng)一化后的編碼個數(shù)可以用公式(4)表示。
這次仍然是把待讀取的照片放入img包中,圖片名為cv_3.jpeg。
import cv2import matplotlib.pyplot as pltfilepath = "../img/cv_3.jpeg"# 讀取圖片,路徑不能含有中文名,否則圖片讀取不出來image = cv2.imread(filepath)# 顯示圖片plt.imshow('image', image)plt.show()
這次的待檢測圖片:

# 需要是Anaconda虛擬環(huán)境下的絕對路徑cascade_path = "/Users/sonata/opt/anaconda3/share/opencv4/lbpcascades/lbpcascade_frontalface_improved.xml"# 下載到了本地使用# 加載人臉級聯(lián)文件faceCascade = cv2.CascadeClassifier(cascade_path)
OpenCV給我們使用特征數(shù)據(jù)的方法:
def detectMultiScale(self, image, scaleFactor=None, minNeighbors=None, flags=None, minSize=None, maxSize=None)params:
1. scaleFactor: 指定每個圖像比例縮小多少圖像
2. minNeighbors: 指定每個候選矩形必須保留多少個鄰居,值越大說明精度要求越高
3. minSize:檢測到的最小矩形大小
4. maxSize: 檢測到的最大矩形大小
所以我們使用此方法檢測圖片中的人臉
# 灰度轉換gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 人臉檢測faces = faceCascade.detectMultiScale(gray, 1.1, 2, minSize=(100, 100))print(faces) # 識別的人臉信息# 循環(huán)處理每一張臉for x, y, w, h in faces:cv2.rectangle(img, pt1=(x, y), pt2=(x+w, y+h), color=[0, 0, 255], thickness=2)img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)plt.imshow(img)plt.show()
得到檢測結果如下:

我們發(fā)現(xiàn)除了檢測到人臉數(shù)據(jù),還有一些其他的臟數(shù)據(jù),這個時候可以打印檢測出的人臉數(shù)據(jù)位置和大小結果如下:

從大小中我們看到最大的兩個矩形,剛好是人臉數(shù)據(jù),其余都是臟數(shù)據(jù),那么繼續(xù)修改函數(shù)參數(shù)
faces = faceCascade.detectMultiScale(gray, 1.1, 2, minSize=(150, 150))# 把最小矩形大小改成150
這樣我們就可以把臟數(shù)據(jù)給除去了:

好消息,小白學視覺團隊的知識星球開通啦,為了感謝大家的支持與厚愛,團隊決定將價值149元的知識星球現(xiàn)時免費加入。各位小伙伴們要抓住機會哦!

交流群
歡迎加入公眾號讀者群一起和同行交流,目前有SLAM、三維視覺、傳感器、自動駕駛、計算攝影、檢測、分割、識別、醫(yī)學影像、GAN、算法競賽等微信群(以后會逐漸細分),請掃描下面微信號加群,備注:”昵稱+學校/公司+研究方向“,例如:”張三 + 上海交大 + 視覺SLAM“。請按照格式備注,否則不予通過。添加成功后會根據(jù)研究方向邀請進入相關微信群。請勿在群內發(fā)送廣告,否則會請出群,謝謝理解~

