以前的人臉識別匹配須要大量圖片進行建模,而後經過幾率匹配,結果不是很準確,同時也不符合通常需求。通常需求是人員經過攝像頭拍攝一張照片,而後將照片保存進行命名,以後若是再次經過攝像頭進行驗證時候,經過算法特徵匹配這我的跟保存的圖片中的類似度,類似度最低的就是這我的,固然若是有足夠的理論跟實驗支持,能夠肯定最低的這個若是大於某個值,也認爲不是這我的。git
LBP算法github
參考博客地址: http://blog.csdn.net/zouxy09/article/details/7929531算法
http://blog.csdn.net/u010006643/article/details/46417091多線程
第二篇的最後結果是監測照片中是不是人臉,和人臉的各類表情匹配。可是咱們的需求是要讓攝像頭裏的人匹配上後臺保存的那張單獨的圖片,全部改進一下讓LBP算法只比較兩張圖片差別,差別最小的就是這我的,雖然最後偏差仍然存在,可是算法是慢慢改進的,至少測試的過程個人識別結果都是我本身。app
下面說思路:ide
一 。攝像頭截圖,截圖成灰色處理的,而且尺寸爲98*116的,(後面LBP算法是按照98*116的,方便分割),而後手動挑取一張最好的看成對比庫放到指定路徑下。****注意文件名不要中文測試
說明:這個截取若是斷定是人臉了,就進行截取圖片,有時候不會識別出人臉,人稍微移動一下就能夠,這個跟手機識別軟件差很少,多數狀況你要動態的才能更好識別。ui
操做:運行shibieJietu.pyspa
import numpy as np import cv2 import sys import time import os def CatVideo(): cv2.namedWindow("shibie") #1調用攝像頭 cap=cv2.VideoCapture(0) #2人臉識別器分類器 classfier=cv2.CascadeClassifier("Train.xml") color=(0,255,0) while cap.isOpened(): ok,frame=cap.read() if not ok: break #2灰度轉換 grey=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY) #人臉檢測,1.2和2分別爲圖片縮放比例和須要檢測的有效點數 faceRects = classfier.detectMultiScale(grey, scaleFactor = 1.2, minNeighbors = 3, minSize = (32, 32)) if len(faceRects) > 0: #大於0則檢測到人臉 for (x, y, w, h) in faceRects : listStr = [str(int(time.time())), str(0)] #以時間戳和讀取的排序做爲文件名稱 fileName = ''.join(listStr) f = cv2.resize(grey[y:(y + h), x:(x + w)], (98, 116)) cv2.imwrite('D:\opencv\pictures\picTest'+os.sep+'%s.jpg' % fileName, f) cv2.rectangle(frame, (x - 10, y - 10), (x + w + 10, y + h + 10), color, 3) cv2.imshow("shibie",frame) print("ceshi2") if cv2.waitKey(10)&0xFF==ord('q'): break cap.release() cv2.destroyAllWindows() CatVideo()
二 。photoKu文件夾的六個文件夾,分別放上不一樣人,照片都是灰化處理的,尺寸98*116。灰化圖片詳情參考上一篇博客的pick_face.py。若是周圍人多的話也可讓他經過攝像頭進行步驟一取到圖片,但 是我這實在沒什麼人幫忙,就用網上圖片湊活了。.net
運行compare.py首先執行runLBP算法,將六個文件夾裏的圖片經過算法算出LBP算子和統計直方圖。
三 。開啓攝像頭,識別人臉後將人臉進行judgeFace 方法與剛纔的結果進行逐一匹配,找到方差最小的那個就是要匹配的那我的了。
from numpy import * from numpy import linalg as la import cv2 import os import math from read_data import read_name_list os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' # 爲了讓LBP具備旋轉不變性,將二進制串進行旋轉。 # 假設一開始獲得的LBP特徵爲10010000,那麼將這個二進制特徵, # 按照順時針方向旋轉,能夠轉化爲00001001的形式,這樣獲得的LBP值是最小的。 # 不管圖像怎麼旋轉,對點提取的二進制特徵的最小值是不變的, # 用最小值做爲提取的LBP特徵,這樣LBP就是旋轉不變的了。 def minBinary(pixel): length = len(pixel) zero = '' for i in range(length)[::-1]: if pixel[i] == '0': pixel = pixel[:i] zero += '0' else: return zero + pixel if len(pixel) == 0: return '0' # 加載圖像 def loadImageSet(add): #add是路徑 print("步驟1") FaceMat = mat(zeros((1,98*116)))#根據圖片尺寸更改 一共有幾行 j =0 for i in os.listdir(add): #print(i) #圖片正常顯示了 #print(i.split('.')[1]) 輸出結果:jpg if i.split('.')[1] == 'jpg': try: img = cv2.imread(add+i,0) #print(add+i) 輸出結果:D:\opencv\huge/15138183801.jpg # cv2.imwrite(str(i)+'.jpg',img) except: print ('load %s failed'%i) FaceMat[j,:] = mat(img).flatten() #print(FaceMat[j,:]) #取第j行 #print(FaceMat[:,j]) #取第j列 #http://blog.csdn.net/qq_18433441/article/details/54916991 flatten詳解 j += 1 #print(FaceMat) return FaceMat # 算法主過程 def LBP(FaceMat,R = 2,P = 8): print("步驟2") Region8_x=[-1,0,1,1,1,0,-1,-1] Region8_y=[-1,-1,-1,0,1,1,1,0] pi = math.pi LBPoperator = mat(zeros(shape(FaceMat))) for i in range(shape(FaceMat)[1]): # 對每個圖像進行處理 轉化成116*98的二維矩陣 face = FaceMat[:,i].reshape(116,98) W,H = shape(face) tempface = mat(zeros((W,H))) for x in range(R,W-R): for y in range(R,H-R): repixel = '' pixel=int(face[x,y]) #取每個值 # 圓形LBP算子 for p in [2,1,0,7,6,5,4,3]: p = float(p) xp = x + R* cos(2*pi*(p/P)) yp = y - R* sin(2*pi*(p/P)) #print(xp) 輸出結果 2.0 #print(pixel) 輸出結果 1 #print(yp) 0.0 #print(face[2,0]) 1.0 if int(face[int(xp),int(yp)])>pixel: repixel += '1' else: repixel += '0' # minBinary保持LBP算子旋轉不變 tempface[x,y] = int(minBinary(repixel),base=2) LBPoperator[:,i] = tempface.flatten().T # cv2.imwrite(str(i)+'hh.jpg',array(tempface,uint8)) return LBPoperator # judgeImg:未知判斷圖像 # LBPoperator:實驗圖像的LBP算子 # exHistograms:實驗圖像的直方圖分佈 def judgeFace(judgeImg,LBPoperator,exHistograms): judgeImg = judgeImg.T ImgLBPope = LBP(judgeImg) # 把圖片分爲7*4份 , calHistogram返回的直方圖矩陣有28個小矩陣內的直方圖 judgeHistogram = calHistogram(ImgLBPope) minIndex = 0 minVals = inf #正無窮 for i in range(shape(LBPoperator)[1]): exHistogram = exHistograms[:,i] diff = (array(exHistogram-judgeHistogram)**2).sum() print(diff) return diff # 統計直方圖 def calHistogram(ImgLBPope): Img = ImgLBPope.reshape(116,98) W,H = shape(Img) # 把圖片分爲7*4份 Histogram = mat(zeros((256,7*4))) maskx,masky = W/4,H/7 #29 14 for i in range(4): for j in range(7): # 使用掩膜opencv來得到子矩陣直方圖 mask = zeros(shape(Img), uint8) mask[int(i*maskx): int((i+1)*maskx),int(j*masky) :int((j+1)*masky)] = 255 hist = cv2.calcHist([array(Img,uint8)],[0],mask,[ 256],[0,256]) Histogram[:,(i+1)*(j+1)-1] = mat(hist).flatten().T return Histogram.flatten().T def runLBP(tuPianPath): # 加載圖像 FaceMat = loadImageSet(tuPianPath).T #反轉矩陣 LBPoperator = LBP(FaceMat) # 得到實驗圖像LBP算子 # 得到實驗圖像的直方圖分佈,這裏計算是爲了能夠屢次使用 exHistograms = mat(zeros((256*4*7,shape(LBPoperator)[1]))) for i in range(shape(LBPoperator)[1]): exHistogram = calHistogram(LBPoperator[:,i]) exHistograms[:,i] = exHistogram allLBPoperator.append(LBPoperator) allexHistograms.append(exHistograms) #build_camera(LBPoperator,exHistograms) #loadname = 'D:\opencv/'+'8.jpg' #judgeImg = cv2.imread(loadname,0) #jresult=judgeFace(mat(judgeImg).flatten(),LBPoperator,exHistograms) #if judgeFace(mat(judgeImg).flatten(),LBPoperator,exHistograms)+1 == int(nameList[i]): def build_camera(): print(1111) #opencv文件中人臉級聯文件的位置,用於幫助識別圖像或者視頻流中的人臉 face_cascade = cv2.CascadeClassifier('Train.xml') #打開攝像頭並開始讀取畫面 cameraCapture = cv2.VideoCapture(0) success, frame = cameraCapture.read() while success and cv2.waitKey(1) == -1: success, frame = cameraCapture.read() grey = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) #圖像灰化 faces = face_cascade.detectMultiScale(grey, 1.3, 5) #識別人臉 for (x, y, w, h) in faces: f = cv2.resize(grey[y:(y + h), x:(x + w)], (98, 116)) result=inf show_name='' for i in range(len(allTuPianPath)): jresult=judgeFace(mat(f).flatten(),allLBPoperator[i],allexHistograms[i]) if jresult==0: show_name=allmen[i] break elif jresult<result: result=jresult show_name=allmen[i] #print(f) # if prob >0.5: #若是模型認爲機率高於70%則顯示爲模型中已有的label # show_name = name_list[label] # else: # show_name = 'Stranger' cv2.putText(frame, show_name, (x, y - 20), cv2.FONT_HERSHEY_SIMPLEX, 1, 255, 2) #顯示名字 frame = cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 0, 0), 2) #在人臉區域畫一個正方形出來 cv2.imshow("Camera", frame) return show_name cameraCapture.release() cv2.destroyAllWindows() if __name__ == '__main__': allLBPoperator=[]#六個LBP算子 allexHistograms=[]#六個統計直方圖
#六個文件夾路徑 allTuPianPath=['D:\opencv\photoKu\huge/','D:\opencv\photoKu\luyi/','D:\opencv\photoKu\me/','D:\opencv\photoKu\shayi/','D:\opencv\photoKu\wuyanzu/','D:\opencv\photoKu\zhoujielun/'] #六我的名
allmen=['hege','luyi','me','shayi','wuyanzu','zhoujielun']
#分別獲取每張圖片的LBP算子,和統計直方圖 for tuPianPath in allTuPianPath: runLBP(tuPianPath)
#開啓攝像頭 name=build_camera()
#最後攝像頭若是關閉會打印出這我的名 print(name)
這張圖片是輸出的結果,開始分別算出六個LBP算子和統計立方圖片,步驟一步驟二打印六次,而後1111進入攝像頭,開始比較識別到的人臉,與六張圖的平方差分別是
245164,175674,50472,248620,162249,222144。 (第三張是我本人,平方差是5萬多,明顯比其餘的低的多)
****這裏須要注意的是,攝像頭以前截取的頭像,應該跟對比時候的頭像差異不會太大,由於都只有一個頭,環境都差不太多,至於化妝,戴帽子什麼的應該會有差別,可是誰家早上視頻識別時候很差好的,非得戴帽子,帶鏡子啥的,因此,只要儘可能作到一致性,識別差距就不會太大。
因爲是while循環攝像頭,因此識別到的下一張頭像繼續運算下去,這裏其實能夠將攝像頭關掉了,而後打印出人名便可,有須要的能夠本身改動。我懶。
最後不得不認可,運算過程太卡頓,並且攝像頭循環也沒作退出處理,須要慢慢等着,而後六個平方差都算完後頭像上顯示人名,之後爭取改進成多線程的,估計會快一些。如今是截取了一張圖片而後就開始比對,這張圖片此時不能再動了,致使攝像頭髮生卡頓,多線程應該可以解決這個問題。
代碼地址:https://github.com/chaoyuebeijita/face
facecompare+LBP.zip