本文不涉及分類器、訓(xùn)練識別器等算法原理,僅包含對其應(yīng)用(未來我也會寫自己對機(jī)器學(xué)習(xí)算法原理的一些觀點(diǎn)和了解)
首先我們需要知道的是利用現(xiàn)有框架做一個人臉識別系統(tǒng)并不難,然后就開始我們的系統(tǒng)開發(fā)吧。
我們的系統(tǒng)主要分為三個部分,然后我還會提出對補(bǔ)獲圖片不能添加中文的解決方案。我們需要完成的任務(wù):1.人臉檢測和數(shù)據(jù)收集2.訓(xùn)練識別器3.人臉識別和顯示
在讀此篇文章之前我相信你已經(jīng)做了python環(huán)境部署和opencv模塊的下載安裝工作,現(xiàn)在我們還需要的模塊是pillow(樹莓派默認(rèn)帶有此模塊,但如果你用的是win系統(tǒng)可能還需要另外安裝,在終端輸入pip install pillow即可),和opencv-contrib模塊,cv2的face模塊包含在內(nèi)(當(dāng)然我的Linux系統(tǒng)的樹莓派貌似仍然默認(rèn)包含了此模塊,所以如果你是用的pc可能需要另外下載),以及最基本的numpy模塊。
在開始寫代碼之前我們首先需要在當(dāng)前運(yùn)行目錄中添加兩個文件夾,dataset用于存放捕獲到的人臉圖像,方便后面訓(xùn)練識別器,trainer文件夾則存放了訓(xùn)練結(jié)果
一。人臉檢測和數(shù)據(jù)收集
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
#數(shù)據(jù)采集 cam = cv2.VideoCapture( 0 ) #補(bǔ)獲圖片 cam. set ( 3 , 640 ) # set video width cam. set ( 4 , 480 ) # set video height face_detector = cv2.CascadeClassifier( 'haarcascade_frontalface_default.xml' ) #導(dǎo)入分類器 # For each person, enter one numeric face id face_id = input ( '\n 輸入用戶id' ) print ( "\n 數(shù)據(jù)采集中,請正視攝像頭輕微扭轉(zhuǎn)" ) # Initialize individual sampling face count count = 0 while ( True ): ret, img = cam.read() #ret為是否成功讀取,是一個布爾值 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) #轉(zhuǎn)化為灰度圖 faces = face_detector.detectMultiScale(gray, 1.3 , 5 ,minSize = ( 100 , 100 )) for (x,y,w,h) in faces: #此處faces是一個array數(shù)組或空的元組,原因我后面會分析 cv2.rectangle(img, (x,y), (x + w,y + h), ( 255 , 0 , 0 ), 2 ) count + = 1 # Save the captured image into the datasets folder cv2.imwrite( "dataset/User." + str (face_id) + '.' + str (count) + ".jpg" , gray[y:y + h,x:x + w]) cv2.imshow( 'image' , img) k = cv2.waitKey( 100 ) & 0xff # Press 'ESC' for exiting video if k = = 27 : break elif count > = 10 : # Take 10 face sample and stop video break # Do a bit of cleanup print ( "\n [INFO] Exiting Program and cleanup stuff" ) cam.release() cv2.destroyAllWindows() |
在這一部分中我們完成了人臉的補(bǔ)獲,并將其保存在了我們建立的dataset文件夾,并將每一個人的數(shù)據(jù)用特定的id表述,這樣我們就能訓(xùn)練能識別不同人臉的識別器。cam.set這一步中第二個參數(shù)是圖像的分辨率,640×480是opencv的默認(rèn)分辨率,但其仍支持800×600且最大支持1280乘1024像素,即使你的攝像頭最大允許分辨率遠(yuǎn)大于這個值,opencv貌似仍不會允許你使用。之后就是haar級聯(lián)分類器的導(dǎo)入,在配置過程中,我們已經(jīng)下載了opencv自帶的分類器,你只需要在文件管理器中查找haarcascade_frontalface_default.xml這個文件即可,在這個文件所在的文件夾中有許多分類器,當(dāng)然如果你要識別例如蘋果香蕉等物體你可能需要訓(xùn)練新的分類器(這也很容易做到),本文討論的是人臉識別,因此這里不再贅述,你可以選擇用其絕對路徑導(dǎo)入,當(dāng)然你也可以像我一樣將其復(fù)制到你當(dāng)前目錄中。然后進(jìn)入循環(huán),圖片的讀取->轉(zhuǎn)灰度圖,然后是使用你已經(jīng)導(dǎo)入的分類器識別人臉并將其用方框標(biāo)出,然后將方框內(nèi)的圖片儲存入dataset文件夾中。值得一提的是,因?yàn)榉诸惼鞯乃惴ㄊ呛苈模苑诸惼鞅旧砭陀袦p幀處理(即使這樣我的樹莓派帶人臉識別系統(tǒng)仍然很吃力),所以faces應(yīng)該是大部分時間都是空的元組,小部分時間是讀取到的array數(shù)組,因此你需要特別注意縮進(jìn)問題,不要讓分類器本身的減幀影響你視頻讀取并顯示的幀數(shù)。
二.訓(xùn)練識別器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
import cv2 #訓(xùn)練器 import numpy as np from PIL import Image import os # Path for face image database path = 'dataset' recognizer = cv2.face.LBPHFaceRecognizer_create() #識別器的導(dǎo)入 detector = cv2.CascadeClassifier( "haarcascade_frontalface_default.xml" ) # function to get the images and label data def getImagesAndLabels(path): imagePaths = [os.path.join(path,f) for f in os.listdir(path)] #在這里os模塊可以幫助我們很好的建立路徑,建議可以先查看一下相關(guān)函數(shù)的使用方法。 faceSamples = [] ids = [] for imagePath in imagePaths: PIL_img = Image. open (imagePath).convert( 'L' ) #轉(zhuǎn)化為灰度圖 img_numpy = np.array(PIL_img, 'uint8' ) #轉(zhuǎn)化為數(shù)組 id = int (os.path.split(imagePath)[ - 1 ].split( "." )[ 1 ]) faces = detector.detectMultiScale(img_numpy) for (x,y,w,h) in faces: faceSamples.append(img_numpy[y:y + h,x:x + w]) ids.append( id ) return faceSamples,ids print ( "\n 訓(xùn)練數(shù)據(jù)中,請稍后" ) faces,ids = getImagesAndLabels(path) recognizer.train(faces, np.array(ids)) # Save the model into trainer/trainer.yml recognizer.write( 'trainer/trainer.yml' ) # recognizer.save() worked on Mac, but not on Pi # Print the numer of faces trained and end program print ( "\n {0} 張臉訓(xùn)練完畢. 程序關(guān)閉" . format ( len (np.unique(ids)))) |
在這一步我們需要對識別器按照不同id分別訓(xùn)練并保存結(jié)果,并將結(jié)果匯總寫入trainer文件夾中命名為trainer.yml。這個文件里就是訓(xùn)練好的識別器。
三.人臉識別和顯示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
# -*- coding: UTF-8 -*- #識別器 import cv2 import numpy as np import os from PIL import Image, ImageFont, ImageDraw path_to_ttf = 'C:\Windows\Fonts\Microsoft YaHei UI\msyh.ttc' #ttc文件是支持漢語的字體,稍后我會說明。 font1 = ImageFont.truetype(path_to_ttf, size = 20 ) recognizer = cv2.face.LBPHFaceRecognizer_create() recognizer.read( 'trainer/trainer.yml' ) #讀取識別器 cascadePath = "haarcascade_frontalface_default.xml" faceCascade = cv2.CascadeClassifier(cascadePath); font = cv2.FONT_HERSHEY_SIMPLEX #iniciate id counter id = 0 # names related to ids: example ==> Marcelo: id=1, etc names = [ 'None' , '段林晨' , 'Paula' , 'Ilza' , 'Z' , 'W' ] #因?yàn)槲覀儾粫谌四樧R別時只顯示你的代號而是要顯示你的具體信息。 cam = cv2.VideoCapture( 0 ) cam. set ( 3 , 640 ) # set video widht cam. set ( 4 , 480 ) # set video height #最小識別的臉的大小,在識別過程中,我們不會捕獲到距離你很遠(yuǎn)的街上路人的信息,這會導(dǎo)致很多問題,因此我們只需要識別想?yún)⑴c識別的人,而設(shè)置最小人臉識別大小可以規(guī)避這一點(diǎn) minW = 0.1 * cam.get( 3 ) minH = 0.1 * cam.get( 4 ) while True : ret, img = cam.read() gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) faces = faceCascade.detectMultiScale( gray, scaleFactor = 1.2 , minNeighbors = 5 , minSize = ( int (minW), int (minH)), ) #相關(guān)參數(shù)設(shè)置可以自行搜索 for (x,y,w,h) in faces: cv2.rectangle(img, (x,y), (x + w,y + h), ( 0 , 255 , 0 ), 2 ) id , confidence = recognizer.predict(gray[y:y + h,x:x + w]) # Check if confidence is less them 100 ==> "0" is perfect match if (confidence < 100 ): id = names[ id ] confidence = " {0}%" . format ( round ( 100 - confidence)) #confidence是置信度指數(shù),等于100-概率,相信大家的概率統(tǒng)計一定比我優(yōu)秀 else : id = "未識別" confidence = " {0}%" . format ( round ( 100 - confidence)) img = Image.fromarray(img) draw = ImageDraw.Draw(img) draw.text(xy = (x + 5 ,y - 5 ), text = str ( id ), font = font1,fill = ( 255 , 255 , 255 )) img = np.array(img) cv2.putText(img, str (confidence), (x + 5 ,y + h - 5 ), font, 1 , ( 255 , 255 , 0 ), 1 ) cv2.imshow( 'camera' ,img) k = cv2.waitKey( 10 ) & 0xff # Press 'ESC' for exiting video if k = = 27 : break # Do a bit of cleanup print ( "\n [INFO] Exiting Program and cleanup stuff" ) cam.release() cv2.destroyAllWindows() |
在這一步中,很遺憾的是cv2.putText函數(shù)并不支持漢語的應(yīng)用,即你不能通過這個函數(shù)將漢語姓名顯示在視頻中,雖然你可能會有英文名或干脆用漢語拼音,但這個問題我們必須要解決。因此我們在這里引入了pillow模塊,我們只需要使用img.draw功能在圖片上先打出你的姓名,再進(jìn)行cv2.putText函數(shù)就能很好的解決這個問題,但是比較麻煩的是這兩個函數(shù)涉及到的圖片類型是不一樣的,因此我在代碼中對img和array圖像進(jìn)行了轉(zhuǎn)換,最終完成了人臉識別系統(tǒng)。
到此這篇關(guān)于基于opencv和pillow實(shí)現(xiàn)人臉識別系統(tǒng)(附demo)的文章就介紹到這了,更多相關(guān)opencv pillow實(shí)現(xiàn)人臉識別內(nèi)容請搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!
原文鏈接:https://blog.csdn.net/qq_45694203/article/details/112914948