使用到的庫:dlib+Opencvpython版本:3.8編譯環境:Jupyter Notebook(Anaconda3)
0.Dlib人臉特征檢測原理提取特征點:請參考
首選抓取多張圖片,從中獲取特征數據集和平均特征值然後寫入csv文件 - 計算特征數據集的歐式距離作對比:首先使用Opencv庫将攝像頭中的人臉框出來,再将攝像頭中采取到的人臉特征值與數據集中的每個人的特征均值作對比,選取最接近(歐氏距離最小)的值,将其标注為歐氏距離最小的數據集的人名
私信小編01即可獲取大量Python學習資源
一、構建人臉特征數據集 1. 安裝Dlib請參考
2. 構建自己的數據集 2.1 抓取人臉圖片在視頻流中抓取人臉特征,并保存為256*256大小的圖片文件共20張,這就是我們建立數據集的第一步,用來訓練人臉識别。
不一定是256*256的尺寸,可以根據自己的需求來調整大小,圖片越大訓練結果會愈加精确,但也會影響訓練模型的時間。
其中:
光線:曝光和黑暗的圖片需手動剔除- 請使用同一個設備進行數據采集,不同設備的攝像頭采集到的數據集會有出入- 這裡采用的是從視頻流中進行捕捉截圖,也可以自己準備20張左右的人臉圖片
代碼:
importcv2importdlibimportosimportsysimportrandom#存儲位置output_dir='D:/No1WorkSpace/JupyterNotebook/Facetrainset/Num&Name'#這裡填編号+人名size=256#圖片邊長ifnotos.path.exists(output_dir): os.makedirs(output_dir)#改變圖片的亮度與對比度defrelight(img,light=1,bias=0): w=img.shape[1] h=img.shape[0]#image=[] foriinrange(0,w): forjinrange(0,h): forcinrange(3): tmp=int(img[j,i,c]*light+bias) iftmp>255: tmp=255 eliftmp<0: tmp=0 img[j,i,c]=tmp returnimg#使用dlib自帶的frontal_face_detector作為我們的特征提取器detector=dlib.get_frontal_face_detector()#打開攝像頭參數為輸入流,可以為攝像頭或視頻文件camera=cv2.VideoCapture(0)#camera=cv2.VideoCapture('C:/Users/CUNGU/Videos/Captures/wang.mp4')index=1whileTrue: if(index<=20):#存儲15張人臉特征圖像 print('Beingprocessedpicture%s'%index)#從攝像頭讀取照片 success,img=camera.read()#轉為灰度圖片 gray_img=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#使用detector進行人臉檢測 dets=detector(gray_img,1) fori,dinenumerate(dets): x1=d.top()ifd.top()>0else0 y1=d.bottom()ifd.bottom()>0else0 x2=d.left()ifd.left()>0else0 y2=d.right()ifd.right()>0else0 face=img[x1:y1,x2:y2]#調整圖片的對比度與亮度,對比度與亮度值都取随機數,這樣能增加樣本的多樣性 face=relight(face,random.uniform(0.5,1.5),random.randint(-50,50)) face=cv2.resize(face,(size,size)) cv2.imshow('image',face) cv2.imwrite(output_dir+'/'+str(index)+'.jpg',face) index+=1 key=cv2.waitKey(30)&0xff ifkey==27: break else: print('Finished!')#釋放攝像頭releasecamera camera.release()#删除建立的窗口deleteallthewindows cv2.destroyAllWindows() break運行效果:
2.2 分析每張人臉的特征值并存入csv文件根據抓取的圖片和人臉識别模型->訓練得到的20個的68個特征數據集以及1個平均特征值存入csv文件
每張圖片的68個特征數據集可以不用存取,他們隻是中間量,計算平均值以後就可以抛棄了,這裡把他們輸出出來隻是為了方便學習。
代碼:
#從人臉圖像文件中提取人臉特征存入CSV#Featuresextractionfromimagesandsaveintofeatures_all.csv#return_128d_features()獲取某張圖像的128D特征#compute_the_mean()計算128D特征均值fromcv2importcv2ascv2 importos importdlib fromskimageimportio importcsv importnumpyasnp #要讀取人臉圖像文件的路徑path_images_from_camera="D:/No1WorkSpace/JupyterNotebook/Facetrainset/"#Dlib正向人臉檢測器detector=dlib.get_frontal_face_detector() #Dlib人臉預測器predictor=dlib.shape_predictor("D:/No1WorkSpace/JupyterNotebook/model/shape_predictor_68_face_landmarks.dat") #Dlib人臉識别模型#Facerecognitionmodel,theobjectmapshumanfacesinto128Dvectorsface_rec=dlib.face_recognition_model_v1("D:/No1WorkSpace/JupyterNotebook/model/dlib_face_recognition_resnet_model_v1.dat") #返回單張圖像的128D特征defreturn_128d_features(path_img): img_rd=io.imread(path_img) img_gray=cv2.cvtColor(img_rd,cv2.COLOR_BGR2RGB) faces=detector(img_gray,1) print("%-40s%-20s"%("檢測到人臉的圖像/imagewithfacesdetected:",path_img),'\n') #因為有可能截下來的人臉再去檢測,檢測不出來人臉了 #所以要确保是檢測到人臉的人臉圖像拿去算特征 iflen(faces)!=0: shape=predictor(img_gray,faces[0]) face_descriptor=face_rec.compute_face_descriptor(img_gray,shape) else: face_descriptor=0 print("noface") returnface_descriptor #将文件夾中照片特征提取出來,寫入CSVdefreturn_features_mean_personX(path_faces_personX): features_list_personX=[] photos_list=os.listdir(path_faces_personX) ifphotos_list: foriinrange(len(photos_list)): withopen("D:/No1WorkSpace/JupyterNotebook/feature/featuresGiao"+str(i)+".csv","w",newline="")ascsvfile: writer=csv.writer(csvfile) #調用return_128d_features()得到128d特征 print("%-40s%-20s"%("正在讀的人臉圖像/imagetoread:",path_faces_personX+"/"+photos_list[i])) features_128d=return_128d_features(path_faces_personX+"/"+photos_list[i]) print(features_128d) writer.writerow(features_128d) #遇到沒有檢測出人臉的圖片跳過 iffeatures_128d==0: i+=1 else: features_list_personX.append(features_128d) else: print("文件夾内圖像文件為空/Warning:Noimagesin"+path_faces_personX+'/','\n') #計算128D特征的均值 #Nx128D->1x128D iffeatures_list_personX: features_mean_personX=np.array(features_list_personX).mean(axis=0) else: features_mean_personX='0' returnfeatures_mean_personX #讀取某人所有的人臉圖像的數據people=os.listdir(path_images_from_camera) people.sort() withopen("D:/No1WorkSpace/JupyterNotebook/feature/features_all.csv","w",newline="")ascsvfile: writer=csv.writer(csvfile) forpersoninpeople: print("#####"+person+"#####") #Getthemean/averagefeaturesofface/personX,itwillbealistwithalengthof128D features_mean_personX=return_features_mean_personX(path_images_from_camera+person) writer.writerow(features_mean_personX) print("特征均值/Themeanoffeatures:",list(features_mean_personX)) print('\n') print("所有錄入人臉數據存入/Saveallthefeaturesoffacesregisteredinto:D:/myworkspace/JupyterNotebook/People/feature/features_all2.csv")如果要輸出每一張圖片的特征數據集,這裡要用到Python的文件批量生成。
代碼運行效果
二、識别人臉并匹配數據集 1. 原理:通過計算特征數據集的歐氏距離作對比來識别人臉,取歐氏距離最小的數據集進行匹配。
歐氏距離也稱歐幾裡得距離或歐幾裡得度量,是一個通常采用的距離定義,它是在m維空間中兩個點之間的真實距離。在二維和三維空間中的歐氏距離的就是兩點之間的距離。使用這個距離,歐氏空間成為度量空間。相關聯的範數稱為歐幾裡得範數。較早的文獻稱之為畢達哥拉斯度量。二維空間公式:
2. 視頻流實時識别人臉數據代碼:
#攝像頭實時人臉識别importos importdlib#人臉處理的庫Dlibimportcsv#存入表格importtime importsys importnumpyasnp#數據處理的庫numpyfromcv2importcv2ascv2#圖像處理的庫OpenCvimportpandasaspd#數據處理的庫Pandas#人臉識别模型,提取128D的特征矢量#facerecognitionmodel,theobjectmapshumanfacesinto128Dvectors#Referthistutorial:http://dlib.net/python/index.html#dlib.face_recognition_model_v1facerec=dlib.face_recognition_model_v1("D:/No1WorkSpace/JupyterNotebook/model/dlib_face_recognition_resnet_model_v1.dat") #計算兩個128D向量間的歐式距離#computethee-distancebetweentwo128Dfeaturesdefreturn_euclidean_distance(feature_1,feature_2): feature_1=np.array(feature_1) feature_2=np.array(feature_2) dist=np.sqrt(np.sum(np.square(feature_1-feature_2))) returndist #處理存放所有人臉特征的csvpath_features_known_csv="D:/No1WorkSpace/JupyterNotebook/feature/features_all.csv" csv_rd=pd.read_csv(path_features_known_csv,header=None) #用來存放所有錄入人臉特征的數組#thearraytosavethefeaturesoffacesinthedatabasefeatures_known_arr=[] #讀取已知人臉數據#printknownfacesforiinrange(csv_rd.shape[0]): features_someone_arr=[] forjinrange(0,len(csv_rd.loc[i,:])): features_someone_arr.append(csv_rd.loc[i,:][j]) features_known_arr.append(features_someone_arr) print("FacesinDatabase:",len(features_known_arr)) #Dlib檢測器和預測器#Thedetectorandpredictorwillbeuseddetector=dlib.get_frontal_face_detector() predictor=dlib.shape_predictor('D:/No1WorkSpace/JupyterNotebook/model/shape_predictor_68_face_landmarks.dat') #創建cv2攝像頭對象#cv2.VideoCapture(0)tousethedefaultcameraofPC,#andyoucanuselocalvideonamebyusecv2.VideoCapture(filename)cap=cv2.VideoCapture(0) #cap.set(propId,value)#設置視頻參數,propId設置的視頻參數,value設置的參數值cap.set(3,480) #cap.isOpened()返回true/false檢查初始化是否成功#whenthecameraisopenwhilecap.isOpened(): flag,img_rd=cap.read() kk=cv2.waitKey(1) #取灰度 img_gray=cv2.cvtColor(img_rd,cv2.COLOR_RGB2GRAY) #人臉數faces faces=detector(img_gray,0) #待會要寫的字體fonttowritelater font=cv2.FONT_HERSHEY_COMPLEX #存儲當前攝像頭中捕獲到的所有人臉的坐标/名字 #thelisttosavethepositionsandnamesofcurrentfacescaptured pos_namelist=[] name_namelist=[] #按下q鍵退出 #press'q'toexit ifkk==ord('q'): break else: #檢測到人臉whenfacedetected iflen(faces)!=0: #獲取當前捕獲到的圖像的所有人臉的特征,存儲到features_cap_arr #getthefeaturescapturedandsaveintofeatures_cap_arr features_cap_arr=[] foriinrange(len(faces)): shape=predictor(img_rd,faces[i]) features_cap_arr.append(facerec.compute_face_descriptor(img_rd,shape)) #遍曆捕獲到的圖像中所有的人臉 #traversalallthefacesinthedatabase forkinrange(len(faces)): print("#####cameraperson",k+1,"#####") #讓人名跟随在矩形框的下方 #确定人名的位置坐标 #先默認所有人不認識,是unknown #setthedefaultnamesoffaceswith"unknown" name_namelist.append("unknown") #每個捕獲人臉的名字坐标thepositionsoffacescaptured pos_namelist.append(tuple([faces[k].left(),int(faces[k].bottom()+(faces[k].bottom()-faces[k].top())/4)])) #對于某張人臉,遍曆所有存儲的人臉特征 #foreveryfacesdetected,comparethefacesinthedatabase e_distance_list=[] foriinrange(len(features_known_arr)): #如果person_X數據不為空 ifstr(features_known_arr[i][0])!='0.0': print("withperson",str(i+1),"theedistance:",end='') e_distance_tmp=return_euclidean_distance(features_cap_arr[k],features_known_arr[i]) print(e_distance_tmp) e_distance_list.append(e_distance_tmp) else: #空數據person_X e_distance_list.append(999999999) #找出最接近的一個人臉數據是第幾個 #Findtheonewithminimumedistance similar_person_num=e_distance_list.index(min(e_distance_list)) print("Minimumedistancewithperson",int(similar_person_num)+1) #計算人臉識别特征與數據集特征的歐氏距離 #距離小于0.4則标出為可識别人物 ifmin(e_distance_list)<0.4: #這裡可以修改攝像頭中标出的人名 #Hereyoucanmodifythenamesshownonthecamera #1、遍曆文件夾目錄 folder_name='D:/No1WorkSpace/JupyterNotebook/Facetrainset/' #最接近的人臉 sum=similar_person_num+1 key_id=1#從第一個人臉數據文件夾進行對比 #獲取文件夾中的文件名:1wang、2zhou、3... file_names=os.listdir(folder_name) fornameinfile_names: #print(name+'->'+str(key_id)) ifsum==key_id: #winsound.Beep(300,500)#響鈴:300頻率,500持續時間 name_namelist[k]=name[1:]#人名删去第一個數字(用于視頻輸出标識) key_id+=1 #播放歡迎光臨音效 #playsound('D:/myworkspace/JupyterNotebook/People/music/welcome.wav') #print("Maybeperson"+str(int(similar_person_num)+1)) #-----------篩選出人臉并保存到visitor文件夾------------ fori,dinenumerate(faces): x1=d.top()ifd.top()>0else0 y1=d.bottom()ifd.bottom()>0else0 x2=d.left()ifd.left()>0else0 y2=d.right()ifd.right()>0else0 face=img_rd[x1:y1,x2:y2] size=64 face=cv2.resize(face,(size,size)) #要存儲visitor人臉圖像文件的路徑 path_visitors_save_dir="D:/No1WorkSpace/JupyterNotebook/KnownFacetrainset/" #存儲格式:2019-06-24-14-33-40wang.jpg now_time=time.strftime("%Y-%m-%d-%H-%M-%S",time.localtime()) save_name=str(now_time)+str(name_namelist[k])+'.jpg' #print(save_name) #本次圖片保存的完整url save_path=path_visitors_save_dir+'/'+save_name #遍曆visitor文件夾所有文件名 visitor_names=os.listdir(path_visitors_save_dir) visitor_name='' fornameinvisitor_names: #名字切片到分鐘數:2019-06-26-11-33-00wangyu.jpg visitor_name=(name[0:16]+'-00'+name[19:]) #print(visitor_name) visitor_save=(save_name[0:16]+'-00'+save_name[19:]) #print(visitor_save) #一分鐘之内重複的人名不保存 ifvisitor_save!=visitor_name: cv2.imwrite(save_path,face) print('新存儲:'+path_visitors_save_dir+'/'+str(now_time)+str(name_namelist[k])+'.jpg') else: print('重複,未保存!') else: #播放無法識别音效 #playsound('D:/myworkspace/JupyterNotebook/People/music/sorry.wav') print("Unknownperson") #-----保存圖片------- #-----------篩選出人臉并保存到visitor文件夾------------ fori,dinenumerate(faces): x1=d.top()ifd.top()>0else0 y1=d.bottom()ifd.bottom()>0else0 x2=d.left()ifd.left()>0else0 y2=d.right()ifd.right()>0else0 face=img_rd[x1:y1,x2:y2] size=64 face=cv2.resize(face,(size,size)) #要存儲visitor-》unknown人臉圖像文件的路徑 path_visitors_save_dir="D:/No1WorkSpace/JupyterNotebook/UnKnownFacetrainset/" #存儲格式:2019-06-24-14-33-40unknown.jpg now_time=time.strftime("%Y-%m-%d-%H-%M-%S",time.localtime()) #print(save_name) #本次圖片保存的完整url save_path=path_visitors_save_dir+'/'+str(now_time)+'unknown.jpg' cv2.imwrite(save_path,face) print('新存儲:'+path_visitors_save_dir+'/'+str(now_time)+'unknown.jpg') #矩形框 #drawrectangle forkk,dinenumerate(faces): #繪制矩形框 cv2.rectangle(img_rd,tuple([d.left(),d.top()]),tuple([d.right(),d.bottom()]),(0,255,255),2) print('\n') #在人臉框下面寫人臉名字 #writenamesunderrectangle foriinrange(len(faces)): cv2.putText(img_rd,name_namelist[i],pos_namelist[i],font,0.8,(0,255,255),1,cv2.LINE_AA) print("Facesincameranow:",name_namelist,"\n") #cv2.putText(img_rd,"Press'q':Quit",(20,450),font,0.8,(84,255,159),1,cv2.LINE_AA) cv2.putText(img_rd,"FaceRecognition",(20,40),font,1,(0,0,255),1,cv2.LINE_AA) cv2.putText(img_rd,"Visitors:"+str(len(faces)),(20,100),font,1,(0,0,255),1,cv2.LINE_AA) #窗口顯示showwithopencv cv2.imshow("camera",img_rd) #釋放攝像頭releasecameracap.release() #删除建立的窗口deleteallthewindowscv2.destroyAllWindows()若直接使用本代碼,文件目錄弄成中文會亂碼
運行效果:
圖中兩人的特征數據集均已被收集并錄入,所以可以識别出來,如果沒有被錄入的人臉就會出現unknown。
沒有吳京叔叔的數據集,所以他是陌生人
有話要說...