生活随笔
收集整理的這篇文章主要介紹了
基于树莓派的人脸识别门禁系统
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、樹莓派Opencv以及擴展模塊的安裝
1、概述:本次在樹莓派上安裝Opencv及其擴展模塊,考慮到樹莓派的SD卡容量和內存的限制,不采用直接pip安裝方法,而采用編譯Opencv源碼的方式進行安裝。
2、遇到的問題及解決方法
遇到的問題解決方法
| 缺少”cuda.hpp” | 將/home/pi/opencv_contrib3.4.1/modules/xfeatures2d/include/opencv2下的xfeatures2d文件夾復制到home/pi/opencv-3.4.1/modules/stitching/include/opencv2下 |
| 缺少”bosstdesc_bgm.i” | 下載對應的文件到opencv_contrib/modules/xfeatures2d/src下 |
| 運行至99%時樹莓派卡死 | 原本采用make -j4進行源碼編譯加速,但是多次嘗試仍然卡死,之后采用make解決了問題,可能原因是make -j4所需的交換空間太大導致卡死。 |
3、運行結果
導入opencv庫沒有問題,說明安裝成功。
二、樹莓派人臉檢測
1、概述:本次在樹莓派上檢測人臉用Opencv自帶的Haar特征分類器。
2、代碼編寫:
將.xml文件拷貝到mu_code文件夾下,在mu_code下編寫代碼,則工程的根目錄默認在mu_code。
import cv2
cap
=cv2
.VideoCapture
(0)
cascadePath
= "/home/pi/opencv-3.4.3/data/haarcascades/haarcascade_frontalface_default.xml"
faceCascade
= cv2
.CascadeClassifier
(cascadePath
)
while (True):ret
, img
= cap
.read
()gray
= cv2
.cvtColor
(img
, cv2
.COLOR_BGR2GRAY
)faces
= faceCascade
.detectMultiScale
(gray
, 1.3, 5)if len(faces
)!=0:x
= faces
[0][0]y
= faces
[0][1]w
= faces
[0][2]h
= faces
[0][3]cv2
.rectangle
(img
, (x
, y
), (x
+ w
, y
+ h
), (255, 0, 0), 2)cv2
.imshow
("fle",img
)cv2
.waitKey
(10)
3、運行結果:
由圖中可以看出可以正確檢測出人臉。
三、樹莓派人臉識別
1、概述:
本次在樹莓派上進行人臉識別采用OpenCV人臉識別類LBPHFaceRecognizer。
2、代碼編寫:
import cv2
from PIL
import Image
import numpy
as np
imagePath
="face.png"
img_face
=cv2
.imread
(imagePath
,0)
cv2
.imshow
("fle",img_face
)
cv2
.waitKey
(0)
recognizer
= cv2
.face
.LBPHFaceRecognizer_create
()
PIL_img
= Image
.open(imagePath
).convert
('L')
img_numpy
= np
.array
(PIL_img
, 'uint8')
faces
=[]
ids
=[]
faces
.append
(img_numpy
)
ids
.append
(2)
recognizer
.train
(faces
, np
.array
(ids
))
id, confidence
= recognizer
.predict
(img_face
)
print("id=",id)
print("confidence=",confidence
)
3、運行結果:
人臉圖片用于訓練,用于訓練的id是2,這里只是為了檢測代碼的正確性,所以依然用這張圖片是做識別,識別的結果是id=2,confidence≈9.8。Id號識別正確,confidence接近于0,說明識別率很高。
四、樹莓派利用雙色LED模擬開關門動作
1、概述:
設計一個雙色LED類,該類應該能夠向外提供兩個方法,分別設置紅燈和綠燈的PWM。
這里在主函數調用是都是設置為滿PWM。
2、接線
樹莓派3mm雙色LED模塊
| GND | 負極(-) |
| P17 | 紅色燈正極(中間引腳) |
| P18 | 綠色燈正極 |
3、代碼編寫
import RPi
.GPIO
as GPIO
import time
class Double_LED_Class:def __init__(self
): makerobo_pins
= (11, 12) GPIO
.setmode
(GPIO
.BOARD
) GPIO
.setwarnings
(False) GPIO
.setup
(makerobo_pins
, GPIO
.OUT
) GPIO
.output
(makerobo_pins
, GPIO
.LOW
) self
.p_R
= GPIO
.PWM
(makerobo_pins
[0], 2000) self
.p_G
= GPIO
.PWM
(makerobo_pins
[1], 2000) self
.p_R
.start
(0)self
.p_G
.start
(0)def makerobo_pwm_map(self
,x
, in_min
, in_max
, out_min
, out_max
):return (x
- in_min
) * (out_max
- out_min
) / (in_max
- in_min
) + out_min
def makerobo_set_red_Color(self
,col
): R_val
= self
.makerobo_pwm_map
(col
, 0, 255, 0, 100)self
.p_R
.ChangeDutyCycle
(R_val
) def makerobo_set_green_Color(self
,col
): G_val
= self
.makerobo_pwm_map
(col
, 0, 255, 0, 100)self
.p_G
.ChangeDutyCycle
(G_val
) def makerobo_destroy(self
):self
.p_G
.stop
()self
.p_R
.stop
()GPIO
.output
(self
.makerobo_pins
, GPIO
.LOW
) GPIO
.cleanup
()
if __name__
== "__main__":Hardware_double_led
=Double_LED_Class
()Hardware_double_led
.makerobo_set_red_Color
(200)time
.sleep
(3)Hardware_double_led
.makerobo_set_red_Color
(0)Hardware_double_led
.makerobo_set_green_Color
(200)
4、運行結果
五、樹莓派門禁系統界面設計與整體邏輯代碼整合
1、概述:
樹莓派門禁系統總共包括4個界面設計,分別是人臉識別開門界面、管理員登錄界面、人臉錄入界面、人臉數據庫展示界面。這四個界面都用PyQt5進行設計,先在Window上用Qt Designer搭建界面,用Python編寫邏輯關系,最后移植到樹莓派上,樹莓派上只需要安裝PyQt庫即可運行程序。
下面為四個界面的展示圖:
界面控件的邏輯關系如下圖:
2、代碼編寫:
代碼思路:
創建了四個界面類,分別繼承于用Qt Designer創建 的四個界面類,這樣做是為了能夠在更改界面的時候不會改變邏輯部分代碼。另外創建了一個數據庫操作類,主要是為了能夠查詢,讀寫數據庫,這里采用的是SQlite數據庫。
Main文件:
import sys
import cv2
import threading
from PyQt5
.QtCore
import QBasicTimer
from PyQt5
.QtCore
import *
from PyQt5
.QtWidgets
import QApplication
, QWidget
, QPushButton
, QLabel
, QLineEdit
, QGridLayout
, QMessageBox
, QGroupBox
from PyQt5
import QtWidgets
from PyQt5
import QtCore
, QtGui
, QtWidgets
from PyQt5
.QtWidgets
import QWidget
, QLabel
, QApplication
from PIL
import Image
import numpy
as np
from PyQt5
.QtWidgets
import *
from PyQt5
.QtCore
import *
from PyQt5
.QtGui
import QPalette
, QBrush
, QPixmap
from PyQt5
.QtSql
import *
import time
from double_led
import Double_LED_Class
import os
from MainWindow
import Ui_Dialog
as Ui_Dialog_MainWindow
from Admin_enter
import Ui_Dialog
as Ui_Dialog_Admin_enter
from Face_rec
import Ui_Dialog
as Ui_Dialog_Face_rec
from SQliteWindow
import Ui_Dialog
as Ui_Dialog_SQliteWindow
cascadePath
= "haarcascade_frontalface_default.xml"
faceCascade1
= cv2
.CascadeClassifier
(cascadePath
)
faceCascade2
= cv2
.CascadeClassifier
(cascadePath
)
faceCascade3
= cv2
.CascadeClassifier
(cascadePath
)
faceCascade4
=cv2
.CascadeClassifier
(cascadePath
)
class Fle_MainWindow(QDialog
,Ui_Dialog_MainWindow
):def __init__(self
):super(Fle_MainWindow
,self
).__init__
()self
.setupUi
(self
)self
.timer_camera
= QtCore
.QTimer
()self
.user
= []self
.recognizer
= cv2
.face
.LBPHFaceRecognizer_create
()faces
, ids
= self
.getImagesAndLabels
("./Face_data")self
.recognizer
.train
(faces
, np
.array
(ids
))self
.font
= cv2
.FONT_HERSHEY_SIMPLEXself
.camera_init
()self
.timer_camera
.timeout
.connect
(self
.show_camera
)self
.timer_camera
.start
(30)self
.pushButton_administrators
.clicked
.connect
(self
.slot_btn_admin
)self
.Hardware_double_led
=Double_LED_Class
()def getImagesAndLabels(self
,path
):imagePaths
= [os
.path
.join
(path
, f
) for f
in os
.listdir
(path
)]faceSamples
= []ids
= []for imagePath
in imagePaths
:PIL_img
= Image
.open(imagePath
).convert
('L')img_numpy
= np
.array
(PIL_img
, 'uint8')id = int(imagePath
.split
("/")[2].split
(".")[1])faces
= faceCascade3
.detectMultiScale
(img_numpy
)for (x
, y
, w
, h
) in faces
:faceSamples
.append
(img_numpy
[y
:y
+ h
, x
:x
+ w
])ids
.append
(id)print(ids
)return faceSamples
, ids
def camera_init(self
):self
.cap
= cv2
.VideoCapture
(0)self
.__flag_work
= 0self
.x
= 0self
.count
= 0self
.minW
= 0.2 * self
.cap
.get
(3)self
.minH
= 0.2 * self
.cap
.get
(4)def show_camera(self
):flag
, self
.image
= self
.cap
.read
()gray
= cv2
.cvtColor
(self
.image
, cv2
.COLOR_BGR2GRAY
)faces
= faceCascade1
.detectMultiScale
(gray
,scaleFactor
=1.2,minNeighbors
=5,minSize
=(int(self
.minW
), int(self
.minH
)),)if len(faces
)!=0:WxH_max
=0 WxH_max_face
=faces
[0]for i
in faces
:if(i
[2]*i
[3]>WxH_max
):WxH_max
=i
[2]*i
[3]WxH_max_face
=ix
=WxH_max_face
[0]y
= WxH_max_face
[1]w
= WxH_max_face
[2]h
= WxH_max_face
[3]cv2
.rectangle
(self
.image
, (x
, y
), (x
+ w
, y
+ h
), (0, 255, 0), 2)id, confidence
= self
.recognizer
.predict
(gray
[y
:y
+ h
, x
:x
+ w
])if (confidence
< 70):confidence
= " {0}%".format(round(100 - confidence
))for i
in range(0,mysqlite
.get_rows
()):if mysqlite
.find_data
(i
,0)==id:self
.label_ID
.setText
(str(mysqlite
.find_data
(i
,1)))self
.label_name
.setText
(str(mysqlite
.find_data
(i
,2)))self
.Hardware_double_led
.makerobo_set_red_Color
(0)self
.Hardware_double_led
.makerobo_set_green_Color
(100)else:confidence
= " {0}%".format(round(100 - confidence
))self
.label_ID
.setText
("不認識")self
.label_name
.setText
("不認識")self
.Hardware_double_led
.makerobo_set_red_Color
(100)self
.Hardware_double_led
.makerobo_set_green_Color
(0)cv2
.putText
(self
.image
, str(id), (x
+ 5, y
- 5), self
.font
, 1, (255, 255, 255), 2)cv2
.putText
(self
.image
, str(confidence
), (x
+ 5, y
+ h
- 5), self
.font
, 1, (255, 255, 0), 1)else:self
.Hardware_double_led
.makerobo_set_red_Color
(0)self
.Hardware_double_led
.makerobo_set_green_Color
(0)show
= cv2
.resize
(self
.image
, (640, 480))show
= cv2
.cvtColor
(show
, cv2
.COLOR_BGR2RGB
)showImage
= QtGui
.QImage
(show
.data
, show
.shape
[1], show
.shape
[0], QtGui
.QImage
.Format_RGB888
)self
.lab_face
.setPixmap
(QtGui
.QPixmap
.fromImage
(showImage
))def slot_btn_admin(self
):self
.timer_camera
.stop
()self
.cap
.release
()self
.logon
= Fle_Admin_enter
()self
.logon
.show
()self
.hide
()self
.Hardware_double_led
.makerobo_set_red_Color
(0)self
.Hardware_double_led
.makerobo_set_green_Color
(0)
class Fle_Admin_enter(QDialog
,Ui_Dialog_Admin_enter
):def __init__(self
):super(Fle_Admin_enter
, self
).__init__
()self
.setupUi
(self
)self
.lineEdit_admin_ID
.setText
("")self
.lineEdit_admin_key
.setText
("")self
.lineEdit_admin_key
.setEchoMode
(QLineEdit
.Password
)self
.lineEdit_admin_ID
.textEdited
[str].connect
(self
.changeEdit_ID
)self
.lineEdit_admin_key
.textEdited
[str].connect
(self
.changeEdit_key
)self
.pushButton_admin_back
.clicked
.connect
(self
.slot_btn_back
)self
.pushButton_admin_enter
.clicked
.connect
(self
.slot_btn_logon
)def changeEdit_ID(self
):Edit_ID
= self
.lineEdit_admin_ID
.text
()print("Edit_ID=",Edit_ID
)def changeEdit_key(self
):Edit_key
= self
.lineEdit_admin_key
.text
()print("Edit_ID=",Edit_key
)def slot_btn_back(self
):self
.menu
= Fle_MainWindow
()self
.menu
.show
()self
.hide
()def slot_btn_logon(self
):print(self
.lineEdit_admin_ID
.text
)print(self
.lineEdit_admin_key
.text
)if self
.lineEdit_admin_ID
.text
() == "1" and self
.lineEdit_admin_key
.text
() == "1":self
.manager_face
= Fle_Face_rec
()self
.manager_face
.show
()self
.hide
()else:QMessageBox
.warning
(self
, "提示", "賬號或密碼錯誤!", QMessageBox
.Close
)
class Fle_Face_rec(QDialog
,Ui_Dialog_Face_rec
):def __init__(self
):super(Fle_Face_rec
, self
).__init__
()self
.setupUi
(self
)self
.lineEdit_ID
.setText
("")self
.lineEdit_name
.setText
("")self
.timer
= QBasicTimer
()self
.step
= 0self
.timer_camera
= QtCore
.QTimer
()self
.camera_init
()self
.timer_camera
.timeout
.connect
(self
.show_camera
)self
.timer_camera
.start
(30)self
.pushButton_begin_rec
.clicked
.connect
(self
.slot_btn_enter
)self
.pushButton_back
.clicked
.connect
(self
.slot_btn_back
)self
.pushButton_show_sqlite
.clicked
.connect
(self
.show_sqlitedata
)def camera_init(self
):self
.cap
= cv2
.VideoCapture
(0)self
.__flag_work
= 0self
.x
=0self
.count
= 0self
.cap
.set(4,640)self
.cap
.set(3,480)def slot_btn_back(self
):self
.timer_camera
.stop
()self
.cap
.release
()self
.logon
= Fle_MainWindow
()self
.logon
.show
()self
.hide
()def show_camera(self
):flag
, self
.image
= self
.cap
.read
()gray
= cv2
.cvtColor
(self
.image
, cv2
.COLOR_BGR2GRAY
)faceCascade2
= cv2
.CascadeClassifier
(cascadePath
);faces
= faceCascade2
.detectMultiScale
(gray
,scaleFactor
=1.2,minNeighbors
=5,minSize
=(200, 200))if len(faces
)!=0:WxH_max
= 0WxH_max_face
= faces
[0]for i
in faces
:if (i
[2] * i
[3] > WxH_max
):WxH_max
= i
[2] * i
[3]WxH_max_face
= ix
= WxH_max_face
[0]y
= WxH_max_face
[1]w
= WxH_max_face
[2]h
= WxH_max_face
[3]cv2
.rectangle
(self
.image
, (x
, y
), (x
+ w
, y
+ h
), (255, 0, 0), 2)roi_gray
= gray
[y
:y
+ h
, x
:x
+ w
]roi_color
= self
.image
[y
:y
+ h
, x
:x
+ w
]show
= cv2
.resize
(self
.image
, (640, 480))show
= cv2
.cvtColor
(show
, cv2
.COLOR_BGR2RGB
)showImage
= QtGui
.QImage
(show
.data
, show
.shape
[1], show
.shape
[0], QtGui
.QImage
.Format_RGB888
)self
.label_face
.setPixmap
(QtGui
.QPixmap
.fromImage
(showImage
))def slot_btn_enter(self
):self
.count
= 0self
.thread
= threading
.Thread
(target
=self
.thread_pic
)self
.thread
.start
()self
.timer
.start
(100, self
)def timerEvent(self
, e
):self
.progressBar
.setValue
(self
.count
)def thread_pic(self
):tip
="正在錄入"+str(self
.lineEdit_ID
.text
())+str(self
.lineEdit_name
.text
())+"的人臉!!"print(tip
)self
.file = "./Face_data"file_ID
=str(self
.lineEdit_ID
.text
())while (True):gray
= cv2
.cvtColor
(self
.image
, cv2
.COLOR_BGR2GRAY
)faces
= faceCascade4
.detectMultiScale
(gray
, 1.3, 5)if len(faces
)!=0:WxH_max
= 0WxH_max_face
= faces
[0]for i
in faces
:if (i
[2] * i
[3] > WxH_max
):WxH_max
= i
[2] * i
[3]WxH_max_face
= ix
= WxH_max_face
[0]y
= WxH_max_face
[1]w
= WxH_max_face
[2]h
= WxH_max_face
[3]self
.count
+= 1print(self
.file + "/User." + file_ID
+ '.' + str(self
.count
) + ".png")bool = cv2
.imwrite
(self
.file + "/User." + file_ID
+ '.' + str(self
.count
) + ".png",gray
[y
:y
+ h
, x
:x
+ w
])if self
.count
>= 100:print("人臉數據采集已完成!")breakmysqlite
.add_row
(self
.lineEdit_ID
.text
(),self
.lineEdit_xuehao
.text
(),str(self
.lineEdit_name
.text
()))def show_sqlitedata(self
):self
.logon
= Fle_SQliteWindow
()self
.logon
.show
()
class Fle_SQliteWindow(QDialog
,Ui_Dialog_SQliteWindow
):def __init__(self
):super(Fle_SQliteWindow
,self
).__init__
()self
.setupUi
(self
)self
.tableView
.setModel
(mysqlite
.model
)self
.pushButton_add
.clicked
.connect
(self
.addrow
)self
.pushButton_delete
.clicked
.connect
(lambda: mysqlite
.model
.removeRow
(self
.tableView
.currentIndex
().row
()))def addrow(self
):ret
= mysqlite
.model
.insertRows
(mysqlite
.model
.rowCount
(), 1) print('數據庫共有%d行數據' % mysqlite
.model
.rowCount
())print('insertRow=%s' % str(ret
))
class Fle_Sqlite():def __init__(self
):self
.db
= QSqlDatabase
.addDatabase
('QSQLITE')self
.db
.setDatabaseName
('./people_data.db')if not self
.db
.open():print('無法建立與數據庫的連接')query
= QSqlQuery
()query
.exec('create table people(id varcahr(10),xuehao varcahr(15),name varcahr(50))')self
.model
= QSqlTableModel
() self
.initializeModel
()def initializeModel(self
):self
.model
.setTable
('people')self
.model
.setEditStrategy
(QSqlTableModel
.OnFieldChange
)self
.model
.select
()self
.model
.setHeaderData
(0, Qt
.Horizontal
, 'ID')self
.model
.setHeaderData
(1, Qt
.Horizontal
, 'xuehao')self
.model
.setHeaderData
(2, Qt
.Horizontal
, 'name')def find_data(self
, row
, col
):index
= self
.model
.index
(row
, col
)return self
.model
.data
(index
)def add_row(self
,ID
,xuehao
,name
):row
= self
.model
.rowCount
()self
.model
.insertRow
(row
) self
.model
.setData
(self
.model
.index
(row
, 0), ID
) self
.model
.setData
(self
.model
.index
(row
, 1), xuehao
) self
.model
.setData
(self
.model
.index
(row
, 2), name
) self
.model
.submitAll
()print(ID
)print(xuehao
)print(name
)def del_row(self
):row
= self
.model
.rowCount
()-1self
.model
.removeRow
(row
)self
.model
.submitAll
()def get_rows(self
):return self
.model
.rowCount
()if __name__
== "__main__":mysqlite
=Fle_Sqlite
()app
= QApplication
(sys
.argv
)w
= Fle_MainWindow
()w
.show
()sys
.exit
(app
.exec_
())
3、運行結果:
由上面兩圖可以看出識別效果正確。
識別出人臉時亮綠燈。
由上圖可知,顯示“不認識”時亮紅燈。
六、總結與體會
①本次實驗采用的LBPH人臉識別模型精度欠缺,受光線影響非常嚴重,或許可以通過攝像頭加紅外濾光片外加紅外補光燈解決。
②本次實驗中多次遇到攝像頭調用打開不了導致imread出錯的情況,具體原因沒有找到,猜測是攝像頭的序列號改變了。
③本次實驗中創建了多個界面類,而人臉識別界面類和人臉錄入界面類都需要調用攝像頭,導致了攝像頭經常報錯,所以在界面切換的時候關掉了攝像頭,在界面初始化的時候又打開了攝像頭,但是這樣做有時也會造成攝像頭來不及釋放而報錯。
④對于數據庫的操作,卡了很長的時間才分清楚數據庫和數據表的區別,最后才搞清楚讀寫操作都是對鏈接到數據庫的數據表操作。
附錄
代碼:https://gitee.com/guoxianda/face-recognition-base-on-Raspberry-pie
總結
以上是生活随笔為你收集整理的基于树莓派的人脸识别门禁系统的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。