【火炉炼AI】机器学习055-使用LBP直方图建立人脸识别器
【火爐煉AI】機器學習055-使用LBP直方圖建立人臉識別器
(本文所使用的Python庫和版本號: Python 3.6, Numpy 1.14, scikit-learn 0.19, matplotlib 2.2 )
在我前面的博文【火爐煉AI】機器學習052-OpenCV構建人臉鼻子眼睛檢測器中,講到了人臉檢測的方法和代碼實現,但在很多實際場合,我們需要做的是人臉識別,即判斷圖片中的那張臉是張三還是李四,故而本篇文章我們來看看如何使用LBP直方圖來建立一個人臉識別器。
1. 局部二值模式簡介
局部二值模式(Local Binary Pattern, LBP)是一種用來描述圖像局部紋理特征的算子,其最大優勢在于旋轉不變性,灰度不變性,能夠多分辨分析。局部紋理分析有很多潛在的應用,比如工業表層檢測,遠程監控,圖像分析等。
LBP的基本思想是:原始的LBP算子是3*3的窗口,以中心像素為閾值,將相鄰的8個像素的灰度值與中心像素進行比較,如果大于,則設為1,小于則為0,故而得到這9個像素的二值化圖,故而名稱為局部二值化,如下圖所示。從二值化圖的左邊中心點像素為起點,逆時針方向為正方形,按順序取該二值化數值,便得到圖中Pattern的二進制數值,此數值就是一個LBP編碼,此時,我們稱該中心像素點的LBP值為11110001。如果對一幅圖像中的所有像素點都計算LBP值,得到的就是這幅圖的LBP特征圖。
關于灰度不變性:很明顯,原始的局部圖中如果灰度值都同時增加一個值或同時減去一個值,便相當于亮度增加或減少,但此時,得到的LBP編碼不變,故而稱為灰度不變性。需要注意的是:該灰度不變性僅僅適用于灰度值的單調變化。如下圖
上面的LBP算子有一個缺陷,它只覆蓋一個固定半徑范圍內的小區域,這顯然不能滿足不同尺寸和頻率紋理的需要,故而有人對其進行改進,將3*3領域擴展到任意領域,并用圓形領域代替正方形領域,如下圖為以中心像素點為圓心,R為半徑,在圓上均勻的選取P個點作為采樣點的情況。
上圖中,R的大小決定了圓的大小,反映了二維空間的尺度;而P的大小決定了采樣點數,反映了角度空間的分辨率。同樣的,我們還可以改變R和P的值,實現不同的尺度和角度分辨率(如下圖)。這也是以后“多分辨率分析”的理論基礎。
上面的LBP算子雖然能夠實現多分辨率,但卻不是旋轉不變性,圖像的旋轉會得到不同的LBP值,故有人提出了具有旋轉不變性的LBP算子,即不斷旋轉圓形領域得到一系列初始定義的LBP值,取其最小值作為該領域的LBP值。
在LBP的應用中,比如人臉識別,紋理分析中,我們一般不將LBP圖譜作為特征向量用于分類識別,而是采用LBP特征圖的統計直方圖來作為特征向量。
使用LBP直方圖來進行特征提取的步驟一般為:
1) 首先將檢測窗口劃分為16×16的小區域(cell)
2) 對于每個cell中的一個像素,將相鄰的8個像素的灰度值與其進行比較,若周圍像素值大于中心像素值,則該像素點的位置被標記為1,否則為0。這樣,3*3鄰域內的8個點經比較可產生8位二進制數,即得到該窗口中心像素點的LBP值
3) 然后計算每個cell的直方圖,即每個數字(假定是十進制數LBP值)出現的頻率;然后對該直方圖進行歸一化處理
4)最后將得到的每個cell的統計直方圖進行連接成為一個特征向量,也就是整幅圖的LBP紋理特征向量;然后便可利用SVM或者其他機器學習算法進行分類了。
關于LBP的深入理論,可以參考博文:LBP(局部二值模式)特征提取原理 和 局部二值模式(Local Binary Patterns)進行紋理分類
2. 準備數據集
本項目所用的數據集是臉部數據集的一個子集,此處我只選擇三個人的臉部圖片來進行測試。數據集有兩部分,一個train的文件夾中有三個子文件夾,每個子文件夾代表一個人的臉部圖片,test的文件夾只含有各種人臉圖片,沒有子文件夾。所以首先我們需要將這些圖片加載到內存中,下面定義一個函數來加載圖片。
# 定義一個函數來加載圖片數據集 def load_train_set(imgs_folder,face_cascade):'''從imgs_folder中加載圖片數據和標記,注意imgs_folder中包含有多個子文件夾,每個子文件夾的名稱就是label'''folders=glob(os.path.join(imgs_folder,'*'))imgs_paths=[][imgs_paths.extend(glob(os.path.join(folder, '*.*'))) for folder in folders]face_imgs=[]labels=[]# 對每一張圖片都檢測畫面上的人臉for img_path in imgs_paths:image = cv2.imread(img_path, 0) label=os.path.split(img_path)[0]img_folder=os.path.split(img_path)[0]faces = face_cascade.detectMultiScale(image, 1.1, 2, minSize=(100,100))for (x, y, w, h) in faces:face_imgs.append(image[y:y+h, x:x+w])labels.append(os.path.split(img_folder)[1])# 此處有點不合理,本數據集中每張圖片只有一個人臉,故而可以用這個方式,# 如果有多個不同人的臉,則不能用折沖方式。# 將labels轉換為數字label_encoder=LabelEncoder()encode_labels=label_encoder.fit_transform(labels)return face_imgs, encode_labels, label_encoder,labels 復制代碼測試下上面的函數是否正常,且顯示下加載的臉部照片
# 測試上面函數是否正常 face_cascade=cv2.CascadeClassifier('E:\PyProjects\DataSet\FireAI\cascade_files/haarcascade_frontalface_alt.xml') face_imgs, labels, label_encoder,labels=load_train_set('E:\PyProjects\/DataSet\FireAI\/faces_dataset/train',face_cascade) print(len(face_imgs)) # 有53張臉,但是檢測得到56個結果,顯然有幾張圖片中檢測了多張臉 # 顯示任一張人臉 # 由于cv2讀取的是BGR,而plt是RGB,故而需要轉化一下 plt.imshow(face_imgs[3],cmap='gray') 復制代碼從打印的結果可以看出,多了三張圖片,說明有三張不是臉部照片的圖片混入,故而需要找出來刪除。定義一個函數來找出錯誤圖片
def find_false_faces(face_imgs):'''將所有臉部照片顯示出來,如果發現有錯誤的,按d鍵,記錄下錯誤的臉部照片'''need_del_ids=[]for idx,face in enumerate(face_imgs):cv2.namedWindow('check', cv2.WINDOW_NORMAL)cv2.resizeWindow('check', 500, 500)cv2.imshow('check', face)key = cv2.waitKey(0)if key==27: # 如果輸入時Esc,則退出循環print('esc to exit')breakelif key==100: # 如果輸入d鍵,則記錄該臉對應的idneed_del_ids.append(idx)cv2.destroyAllWindows()print('finished...')return need_del_ids 復制代碼故而需要從原始數據集中刪除這三張圖片以及對應的label信息
# 從數據集中刪除這三張照片對應的信息 face_imgs=np.delete(np.array(face_imgs), need_del_ids, axis=0) encode_labels=np.delete(np.array(encode_labels), need_del_ids, axis=0) labels=np.delete(np.array(labels), need_del_ids,axis=0) print(face_imgs.shape) # 53張圖沒錯,元素已經變成了np.ndarray,故而只有行 復制代碼3. 構建LBP直方圖識別器
此處的LBP直方圖識別器相當于一個分類模型,cv2已經幫我們封裝好了這個分類模型,我們只需要調用即可。
# 構建createLBPHFaceRecognizer分類模型 from cv2.face import LBPHFaceRecognizer_create recognizer=LBPHFaceRecognizer_create() recognizer.train(face_imgs, encode_labels) # 模型訓練 復制代碼一旦人臉識別器模型訓練好之后,就可以用來進行人臉識別了,下面看看識別新圖片的人臉結果。
# 用訓練好的模型預測新照片 def predict_imgs(new_imgs_folder, face_cascade,recognizer,label_encoder):'''用訓練好的人臉識別器來識別人臉'''img_paths=glob(new_imgs_folder+'/*.*')predicted_imgs=[]for img_path in img_paths:image=cv2.imread(img_path)gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)faces=face_cascade.detectMultiScale(gray,1.1, 2, minSize=(100,100))for (x, y, w, h) in faces:cv2.rectangle(image,(x,y),(x+w,y+h),(0,0,255),3)predicted_index, conf = recognizer.predict(gray[y:y+h, x:x+w])predicted_label=label_encoder.inverse_transform([predicted_index])[0]cv2.putText(image, predicted_label,(x,y-20), cv2.FONT_HERSHEY_SIMPLEX, 2, (0,0,255), 3)predicted_imgs.append(image)return predicted_imgs 復制代碼得到的結果分別為:
當然,這個識別器只能識別訓練圖片中已經有的人臉,對于訓練集中沒有的人臉,它會預測不準確。比如,拿鳳姐的圖片來預測一下試試。
估計鳳姐這張照片和Person3長的比較像,所以本模型將其預測為Person3
########################小**********結###############################
1,LBP直方圖模型可以快速訓練并快速識別,在人臉識別領域中有著比較廣泛的應用。
#################################################################
注:本部分代碼已經全部上傳到(我的github)上,歡迎下載。
參考資料:
1, Python機器學習經典實例,Prateek Joshi著,陶俊杰,陳小莉譯
總結
以上是生活随笔為你收集整理的【火炉炼AI】机器学习055-使用LBP直方图建立人脸识别器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ProxySQL 配置详解及读写分离(+
- 下一篇: 【排序算法】冒泡排序|选择排序|插入排序