0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

怎样用树莓派构建基于面部识别的门锁

454398 来源:工程师吴畏 2019-07-30 09:16 次阅读

该项目将包括三个阶段:

人脸检测和数据收集

训练识别器

面部识别

在深入研究代码之前,让我们将电磁锁与Raspberry Pi连接。

电路图和说明

Raspberry Pi的GPIO引脚可以提供3.3V的输出,但电磁锁需要7-12V才能工作。因此,我们需要使用外部电源和继电器来操作锁定。

将继电器模块的VCC和GND连接到Raspberry Pi的5V和GND。然后将继电器模块的信号引脚连接到Raspberry Pi的GPIO 26.

在继电器模块的另一侧,将负极直流电源连接到电磁门锁的负极。将来自直流电源的正极连接到继电器模块的公共端,然后将常开模块从继电器模块连接到电磁门锁的正极。

面部识别电路图。

人脸检测的数据收集

第一个任务是收集我们要训练分类器的数据。我们将使用OpenCV预训练分类器编写一个python代码,每个人需要30个面。

OpenCV已经包含许多面部,眼睛,微笑等预先训练的分类器。我们要去的分类器使用将检测面部,并在GitHub上提供级联文件。

将此文件保存在工作目录中“haarcascade_frontalface_default.xml”。

代码演练

现在让我们编写代码。 首先,我们导入所需的包。

import cv2

from picamera.array import PiRGBArray

from picamera import PiCamera

import numpy as np

import os

import sys

然后我们初始化相机对象,这将允许我们使用Raspberry Pi相机。我们将分辨率设置为(640,480),帧速率设置为30 fps。

camera = PiCamera()

camera.resolution = (640, 480)

camera.framerate = 30

PiRGBArray() 为我们提供了一个来自未编码RGB捕获的三维RGB数组(行,列,颜色)。 PiRGBArray的优势在于它能够将Raspberry Pi相机中的帧读取为NumPy阵列,使其与OpenCV兼容。它避免了从JPEG格式到OpenCV格式的转换,这会减慢我们的过程。

它需要两个参数

相机对象

分辨率

rawCapture = PiRGBArray(camera, size=(640, 480))

加载用于检测面的级联文件。

face_cascade = cv2.CascadeClassifier(“haarcascade_frontalface_default.xml”);

接下来,我们要求用户输入名称。如果已存在具有该名称的目录,则它将以“名称已存在”进行响应并退出代码。如果没有此名称的目录,它将创建目录,图像将以此名称保存。

name = input(“What‘s his/her Name? ”)

dirName = “。/images/” + name

print(dirName)

if not os.path.exists(dirName):

os.makedirs(dirName)

print(“Directory Created”)

else:

print(“Name already exists”)

sys.exit()

为图像创建目录。

之后,我们使用 capture_continuous 从Raspberry Pi相机模块开始读取帧的功能。

c apture_continuous函数有三个参数:

rawCapture

我们想要读取每个帧的格式,因为OpenCV期望图像采用BGR格式而不是RGB格式,因此我们将格式指定为BGR。

use_video_port布尔值,使其为true意味着我们将流视为视频

for frame in camera.capture_continuous(rawCapture, format=“bgr”, use_video_port=True):

一旦我们有了f rame,我们可以通过.array属性访问原始的NumPy数组。访问后,我们将此帧转换为灰度。

frame = frame.array

gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

然后我们调用分类器函数来检测帧中的面。我们传递的第一个参数是灰度图像。第二个参数是指定在每个图像比例下图像尺寸减少多少的参数。第三个参数是一个参数,指定每个候选矩形应保留多少个邻居。数字越大,误报率越低。

faces = faceCascade.detectMultiScale(gray, scaleFactor = 1.5, minNeighbors = 5)

上面的函数给出了面部区域的矩形坐标。我们使用这些坐标从图像中提取面部并将其保存在我们在开始时创建的目录中。之后,我们展示了裁剪的面部并在原始框架上创建了一个矩形。

代码将收集30张图像。

for (x, y, w, h) in faces:

roiGray = gray[y:y+h, x:x+w]

fileName = dirName + “/” + name + str(count) + “.jpg”

cv2.imwrite(fileName, roiGray)

cv2.imshow(“face”, roiGray)

cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)

count += 1

然后我们在上面显示原始帧输出窗口。 cv2.waitkey()是一个键盘绑定函数。它等待任何键盘事件的指定毫秒。它需要一个参数,这个参数是以毫秒为单位的时间。如果在该时间内按下该键,则程序将继续。传递0表示它将无限期地等待一个键。

cv2.imshow(’frame‘, frame)

key = cv2.waitKey(1)

然后我们通过在捕获之间调用truncate(0)来清除流以准备下一帧。

rawCapture.truncate(0)

人脸检测和数据收集工作现已完成。我们应该在新创建的目录中有30个图像。

我们的30张图片保存在新创建的目录中。

人脸检测完整代码

import cv2

from picamera.array import PiRGBArray

from picamera import PiCamera

import numpy as np

import os

import sys

camera = PiCamera()

camera.resolution = (640, 480)

camera.framerate = 30

rawCapture = PiRGBArray(camera, size=(640, 480))

faceCascade = cv2.CascadeClassifier(“haarcascade_frontalface_default.xml”)

name = input(“What’s his/her Name? ”)

dirName = “。/images/” + name

print(dirName)

if not os.path.exists(dirName):

os.makedirs(dirName)

print(“Directory Created”)

else:

print(“Name already exists”)

sys.exit()

count = 1

for frame in camera.capture_continuous(rawCapture, format=“bgr”, use_video_port=True):

if count 》 30:

break

frame = frame.array

gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

faces = faceCascade.detectMultiScale(gray, scaleFactor = 1.5, minNeighbors = 5)

for (x, y, w, h) in faces:

roiGray = gray[y:y+h, x:x+w]

fileName = dirName + “/” + name + str(count) + “.jpg”

cv2.imwrite(fileName, roiGray)

cv2.imshow(“face”, roiGray)

cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)

count += 1

cv2.imshow(‘frame’, frame)

key = cv2.waitKey(1)

rawCapture.truncate(0)

if key == 27:

break

cv2.destroyAllWindows()

训练识别器

现在我们可以根据上一步收集的数据训练识别器。

我们将使用LBPH (LOCAL BINARY PATTERNS HISTOGRAMS)面部识别器,包含在OpenCV包中。我们将它加载到以下行:

recognizer = cv2.face.LBPHFaceRecognizer_create()

我们获取当前工作目录的路径,然后移动到图像目录所在的目录。

baseDir = os.path.dirname(os.path.abspath(__file__))

imageDir = os.path.join(baseDir, “images”)

《然后我们进入每个图像目录并查找图像。如果图像存在,我们将其转换为NumPy数组。

for root, dirs, files in os.walk(imageDir):

print(root, dirs, files)

for file in files:

print(file)

if file.endswith(“png”) or file.endswith(“jpg”):

path = os.path.join(root, file)

label = os.path.basename(root)

print(label)

if not label in labelIds:

labelIds[label] = currentId

print(labelIds)

currentId += 1

id_ = labelIds[label]

pilImage = Image.open(path).convert(“L”)

imageArray = np.array(pilImage, “uint8”)

之后,我们再次进行面部检测,以确保我们有正确的图像,然后我们准备训练数据。

faces = faceCascade.detectMultiScale(imageArray, scaleFactor=1.1, minNeighbors=5)

for (x, y, w, h) in faces:

roi = imageArray[y:y+h, x:x+w]

xTrain.append(roi)

yLabels.append(id_)

存储包含目录名称和标签ID的字典。

with open(“labels”, “wb”) as f:

pickle.dump(labelIds, f)

f.close()

现在训练数据并保存文件。

recognizer.train(xTrain, np.array(yLabels))

recognizer.save(“trainer.yml”)

此代码创建一个trainer.yml并标记我们在识别代码中使用的文件。

我们在识别代码中使用的trainer.yml文件。

培训识别器的完整代码

import os

import numpy as np

from PIL import Image

import cv2

import pickle

faceCascade = cv2.CascadeClassifier(“haarcascade_frontalface_default.xml”)

recognizer = cv2.face.LBPHFaceRecognizer_create()

baseDir = os.path.dirname(os.path.abspath(__file__))

imageDir = os.path.join(baseDir, “images”)

currentId = 1

labelIds = {}

yLabels = []

xTrain = []

for root, dirs, files in os.walk(imageDir):

print(root, dirs, files)

for file in files:

print(file)

if file.endswith(“png”) or file.endswith(“jpg”):

path = os.path.join(root, file)

label = os.path.basename(root)

print(label)

if not label in labelIds:

labelIds[label] = currentId

print(labelIds)

currentId += 1

id_ = labelIds[label]

pilImage = Image.open(path).convert(“L”)

imageArray = np.array(pilImage, “uint8”)

faces = faceCascade.detectMultiScale(imageArray, scaleFactor=1.1, minNeighbors=5)

for (x, y, w, h) in faces:

roi = imageArray[y:y+h, x:x+w]

xTrain.append(roi)

yLabels.append(id_)

with open(“labels”, “wb”) as f:

pickle.dump(labelIds, f)

f.close()

recognizer.train(xTrain, np.array(yLabels))

recognizer.save(“trainer.yml”)

print(labelIds)

使用识别器进行面部识别

我们在上一节中设置的识别器现在可用于识别面部。它会给我们信心和标签ID(识别器对这场比赛的信心程度)。如果面部匹配,继电器将打开。

首先我们加载包含字典的pickle文件。

with open(‘labels’, ‘rb’) as f:

dicti = pickle.load(f)

f.close()

然后我们加载将检测面部的分类器以及预测面部和训练数据的识别器。

faceCascade = cv2.CascadeClassifier(“haarcascade_frontalface_default.xml”)

recognizer = cv2.face.LBPHFaceRecognizer_create()

recognizer.read(“trainer.yml”)

我们读取帧,将其转换为灰度,并在图像中查找面。如果有任何面部,我们将提取面部区域并使用识别器识别图像。

识别器将为我们提供标签ID和置信度。

gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

faces = faceCascade.detectMultiScale(gray, scaleFactor = 1.5, minNeighbors = 5)

for (x, y, w, h) in faces:

roiGray = gray[y:y+h, x:x+w]

roiColor = frame[y:y+h, x:x+w]

id_, conf = recognizer.predict(roiGray)

我们在字典中查找分配给此标签ID的名称。

for name, value in dict.items():

if value == id_:

print(name)

然后检查我们是否有足够的信心打开门锁。如果信心小于70,门将打开。否则,它将保持关闭状态。

if conf 《= 70:

GPIO.output(relay_pin, 1)

cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)

cv2.putText(frame, name + str(conf), (x, y), font, 2, (0, 0 ,255), 2,cv2.LINE_AA)

else:

GPIO.output(relay_pin, 0)

在原始图像中创建一个矩形,并将该名称写在矩形的顶部。

cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)

cv2.putText(frame, name, (x, y), font, 2, (0, 0 ,255), 2,cv2.LINE_AA)

随着代码的完成,设置已准备好进行面部识别!

训练识别器的完整代码

import cv2

from picamera.array import PiRGBArray

from picamera import PiCamera

import numpy as np

import pickle

import RPi.GPIO as GPIO

from time import sleep

relay_pin = [26]

GPIO.setmode(GPIO.BCM)

GPIO.setup(relay_pin, GPIO.OUT)

GPIO.output(relay_pin, 0)

with open(‘labels’, ‘rb’) as f:

dicti = pickle.load(f)

f.close()

camera = PiCamera()

camera.resolution = (640, 480)

camera.framerate = 30

rawCapture = PiRGBArray(camera, size=(640, 480))

faceCascade = cv2.CascadeClassifier(“haarcascade_frontalface_default.xml”)

recognizer = cv2.face.LBPHFaceRecognizer_create()

recognizer.read(“trainer.yml”)

font = cv2.FONT_HERSHEY_SIMPLEX

for frame in camera.capture_continuous(rawCapture, format=“bgr”, use_video_port=True):

frame = frame.array

gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

faces = faceCascade.detectMultiScale(gray, scaleFactor = 1.5, minNeighbors = 5)

for (x, y, w, h) in faces:

roiGray = gray[y:y+h, x:x+w]

id_, conf = recognizer.predict(roiGray)

for name, value in dict.items():

if value == id_:

print(name)

if conf 《= 70:

GPIO.output(relay_pin, 1)

cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)

cv2.putText(frame, name + str(conf), (x, y), font, 2, (0, 0 ,255), 2,cv2.LINE_AA)

else:

GPIO.output(relay_pin, 0)

cv2.imshow(‘frame’, frame)

key = cv2.waitKey(1)

rawCapture.truncate(0)

if key == 27:

break

cv2.destroyAllWindows()

最后的想法

这种人脸识别系统不是100%准确,但在良好的光线下效果很好条件。问题是它还可以检测图片中的面孔 - 例如,有人可以通过手机显示您的图片来解锁它。我们可以通过训练自己的级联分类器来改进这一点。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 面部识别
    +关注

    关注

    1

    文章

    375

    浏览量

    26623
  • 树莓派
    +关注

    关注

    116

    文章

    1699

    浏览量

    105548
收藏 人收藏

    评论

    相关推荐

    树莓与Arduino的区别是什么

    在当今的科技世界中,树莓(Raspberry Pi)和Arduino是两个经常被提及的名字。它们都是开源硬件平台,但它们的目标、功能和用途却大相径庭。 1. 目标和用途 树莓(Ra
    的头像 发表于 11-11 11:14 404次阅读

    ARM开发板与树莓的比较

    ARM开发板和树莓都是基于ARM架构的单板计算机,它们在教育、工业控制、物联网等领域有着广泛的应用。 硬件配置 ARM开发板和树莓的硬件配置各有特点,具体取决于不同的型号和制造商。
    的头像 发表于 11-05 11:11 267次阅读

    树莓gpio有什么,树莓gpio接口及编程方法

    一、树莓GPIO的用途 树莓(Raspberry Pi)是一款小巧、功能强大的单板计算机,广泛应用于编程教育、物联网项目、家庭媒体中心等领域。GPIO(General Purpos
    的头像 发表于 10-22 18:09 537次阅读

    什么是树莓树莓是什么架构的

    什么是树莓 树莓(Raspberry Pi,简写为RPi,别名为RasPi/RPI)是由英国“Raspberry Pi 慈善基金会”开发的一款为学习计算机编程教育而设计的微型电脑。
    的头像 发表于 10-22 17:33 573次阅读

    树莓网关:物联网应用的新标杆

    什么是树莓树莓(Raspberry Pi)是一种基于Linux的小型单板计算机,由英国的树莓
    的头像 发表于 10-09 16:44 251次阅读
    类<b class='flag-5'>树莓</b><b class='flag-5'>派</b>网关:物联网应用的新标杆

    树莓和单片机的优缺点是什么

    树莓(Raspberry Pi)和单片机(Microcontroller)是两种广泛应用于电子项目和嵌入式系统的硬件平台。它们各自具有独特的优缺点,适用于不同的应用场景。 树莓
    的头像 发表于 08-30 18:21 1491次阅读

    树莓的功能用途是什么

    树莓(Raspberry Pi)是一款由英国树莓基金会研发的信用卡大小的单板计算机,自2012年推出以来,已经发展出多个型号和版本。树莓
    的头像 发表于 08-30 18:01 2319次阅读

    树莓4B的性能特点及应用

    树莓4B简介 树莓4B是一款基于ARM架构的单板计算机,其搭载了四核Cortex-A72 CPU,主频高达1.5GHz,同时配备了4GB LPDDR4内存。此外,它还具备了丰富的接
    的头像 发表于 08-30 16:54 1496次阅读

    树莓gui开发什么ide

    树莓(Raspberry Pi)是一款功能强大的微型计算机,可以运行多种操作系统,如Raspbian、Ubuntu等。在树莓派上进行GUI(图形用户界面)开发,可以使用多种集成开发环境(IDE
    的头像 发表于 08-30 16:49 708次阅读

    树莓是x86还是arm

    树莓(Raspberry Pi)是一款由英国树莓基金会(Raspberry Pi Foundation)开发的微型计算机。它基于ARM架构,而非x86架构。 一、
    的头像 发表于 08-30 15:42 822次阅读

    树莓装ubuntu和raspbian哪个更好

    树莓(Raspberry Pi)是一款由英国树莓基金会开发的单板计算机,广泛应用于教育、科研、物联网等领域。树莓
    的头像 发表于 08-30 15:41 1111次阅读

    树莓和arm开发板的区别

    树莓(Raspberry Pi)和ARM开发板都是基于ARM架构的微型计算机,但它们之间存在一些关键区别。 一、历史背景 树莓(Raspberry Pi)
    的头像 发表于 08-30 15:36 848次阅读

    树莓基金会更新树莓OS,支持最新浏览器,优化电源管理

    首先,树莓 OS 对于电源系统进行了优化提升,新增了对树莓 5 SBC 的兼容支持。其次,还在屏幕配置功能中新增了无头模式分辨率选项,并取消了 Wayland 模式下的此项设置。
    的头像 发表于 03-14 14:55 669次阅读

    树莓主板如何连接电脑

    连接树莓派到电脑是一个非常有用的功能,它可以让我们在电脑上进行树莓的操作和管理。本文将详细介绍如何连接树莓主板到电脑。我会从准备工作开始
    的头像 发表于 01-07 15:40 1856次阅读

    基于树莓的环境监测系统

    树莓(Raspberry Pi)是一种小型而功能强大的计算机,其性能和功能足以支持许多应用领域。在环境监测系统中,树莓也被广泛应用。本文将详细介绍基于
    的头像 发表于 01-04 15:15 2067次阅读