树莓派运行ROS实现face++人脸识别

摘要


  Face++是北京旷视科技有限公司旗下的新型视觉服务平台,Face++平台通过提供云端API、离线SDK、以及面向用户的自主研发产品形式,将人脸识别技术广泛应用到互联网及移动应用场景中,非常重要的是它对于非商业用户提供免费试用帐号注册。对于开发者来说自己开发高效准确的算法并不是一件容易的事情,所以我们利用face++在线人脸识别平台,结合ros系统,搭建一套性价比比较高的门禁系统。通过这一过程能够更加深刻的理解嵌入式、ros以及云服务的广泛应用,为使用其他的云服务API接口打下良好的基础。
  将树莓派作为硬件载体,编写ros节点实现摄像头自动拍照,拍完后调用opencv进行人脸识别,如果存在人脸,便同时与本地权限人照片(拥有开门权限的人)一起上传至face++云平台,利用face++的API对两张照片进行识别和比较,从而返回消息提示是否为拥有开门权限的人,继电器做出相应动作。

准备工作


1、 在树莓派编译好ros系统。
2、 登入Face++的官方网站https://www.faceplusplus.com.cn/完成注册。
树莓派运行ROS实现face++人脸识别_第1张图片
  创建API Key
树莓派运行ROS实现face++人脸识别_第2张图片
  在应用管理-API Key界面就可以看到两个非常关键的参数,API Key和API Secret,在所有的POST调用当中均需要这两个参数。树莓派运行ROS实现face++人脸识别_第3张图片
3、 调试摄像头
  (1) 插入USB摄像头,运行lsusb命令,查看是否被树莓派识别,一般插入第一个USB摄像头,会被加载为/dev/video0
  (2)安装拍照软件fswebcam

sudo apt-get install fswebcam

  (3)试拍一张看看

sudo fswebcam -d /dev/video0 -r 320x240 home/pi/0.jpg

4、 用命令行安装opencv相关库,在此之前请务必更新一下系统。

sudo apt-get update         #更新源
sudo apt-get upgrade         #更新系统
sudo apt-get install libopencv-dev
sudo apt-get install python-opencv

  (1)检查opencv是否安装成功,请尝试以下命令

$ python
>>> from cv2 import cv
>>> quit()

  没有收到导入错误(ImportError: No module named cv2),安装成功
  收到导入错误 ①opencv没有正确安装
           ②Python路径没有设置正确
     (2)OpenCV Python库存储在cv2.so文件中,运行命令验证是否已安装

$ locate cv2.so | grep python

     得到cv2.so的路径:/usr/lib/python2.7/dist-packages/cv2.so
5、 下载Face++的官网API的python的接口SDK,作为参考api调用。
     https://github.com/FacePlusPlus/python-sdk
树莓派运行ROS实现face++人脸识别_第4张图片

实践流程


1、 摄像头拍照并调用opencv进行人脸识别

  (1)在主循环内间隔2秒调用摄像头拍照

import os				#导入python的os模块
import time				#导入python的time模块
command="fswebcam -d /dev/video0 -r 600*600 /home/pi/Desktop/photo.jpeg"
os.system(command)		#执行command所代表的指令,即拍照
time.sleep(2)			#等待2s

  但不能每次拍完照都与本地权限者照片比较一下,那样调用face++的API过于频繁,一来造成累积的网络延时过大,二来正式API应用以调用次数收费(试用API也不能无限次调用,且网络不稳定,容易出问题),因此每次拍完照都要识别一下照片中有没有人脸,如果有人脸再调用face++进行人脸比较。但同样的道理也不能用face++进行人脸识别,综上考虑,用opencv进行识别。

  (2)拍好照片,并调用opencv进行人脸识别

import numpy as np		#导入python的numpy模块并更名为np
import cv2				#导入python的opencv模块
#用opencv进行人脸识别,识别出有人脸才进行下一步人脸比较,否则一直拍照
face_cascade = cv2.CascadeClassifier(haarcascade_frontalface_alt2.xml)	#read image读取图像
img = cv2.imread(photo)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)		#Convert to grayscale转换为灰度图
faces = face_cascade.detectMultiScale(gray, 1.3, 5)

  若faces返回不为空,则识别出了人脸,接下来调用Face++人脸对比API,进行比对。

2、Face++人脸对比

通过参考Face++的官方SDK函数,结合官网的API说明,选定Detect API与Compare API实现所需功能。
树莓派运行ROS实现face++人脸识别_第5张图片

#利用face++的detectAPI识别opencv识别到的人脸照片
detectresult=api.detect(api_key=API_KEY,api_secret=API_SECRET,image_file=File(photo))
print_result('Detect result:', detectresult)		#将结果输出到打印到命令行界面上
#调用face++的compareAPI将拍到的照片与两张本地权限者照片做比较,confidence表示拍到的照片与本地权限者照片是同一人的置信度
comparation=api.compare(api_key=API_KEY,api_secret=API_SECRET,image_file1=File(compare_photo),image_file2=File(photo))
confidence=comparation['confidence']

  (1)detectAPI主要是对识别的照片进行处理,并将结果通过调用print_result函数输出到命令行界面
  (2)compareAPI将拍到的照片与本地权限者照片做比较,将结果赋给confidence
  (3)confidence是对比结果置信度”,经过测试,本地权限者去拍照进行比对confidence值一般在90以上,而非本地权限者拍照比对结果在60以下,所以我们将判断的阀值定为70。

3、将Face++官网的SDK修改为ros的节点。

  (1)下面是修改为ros节点,SDK所需要的文件。
树莓派运行ROS实现face++人脸识别_第6张图片
  (2)创建face_node功能包。

$ cd ~/catkin_ws/src
$ catkin_create_pkg face_node std_msgs rospy roscpp
$ cd face_node
$ mkdir -p nodes launch photo

树莓派运行ROS实现face++人脸识别_第7张图片
    ①haarcascade_frontalface_alt2.xml下载

  人脸的Haar特征分类器就是一个XML文件,该文件中会描述人脸的Haar特征值。当然Haar特征的用途可不止可以用来描述人脸这一种,用来描述眼睛,嘴唇或是其它物体也是可以的,OpenCV有已经自带了人脸的Haar特征分类器。
下载地址:
在GitHub上找到opencv软件包,并在其中找到haarcascade_frontalface_alt2.xml
https://github.com/opencv/opencv/tree/master/data/haarcascades

    ②在photo的目录下放入本地权限者的照片
    ③ ros下python函数调用

  call.py需要调用到facepp.py文件,ros不能像python一样,直接用from facepp import API, File包含,并把facepp.py和call.py放在同一个目录,.py并不是可编译的脚本文件,为了适应ros统一的编译体系,使ros识别出你写的python node,所以也加入了Python的编译流程,主要目的就是让ros和系统找到你的python程序。

    1. 在face_node/src目录下建立face_node,将facepp.py复制到该目录下,并且创建_init_.py

$ cd ~/catkin_ws/src/face_node/src
$ mkdir face_node
$ touch _init_.py

    2. 在~/catkin_ws/src/face_node下建立setup.py文件, 另外还需要在CMakesLists.txt中加一行catkin_python_setup()来处理setup.py,这一行应该在find_package()之后。

$vim setup.py
#!/usr/bin/env python

from distutils.core import setup
from catkin_pkg.python_setup import generate_distutils_setup

d = generate_distutils_setup(
    packages=['face_node'],
    package_dir={'': 'src'},
    )

setup(**d)
$vim CMakesLists.txt
cmake_minimum_required(VERSION 2.8.3)
project(face_node)

find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
)
catkin_package(DEPENDS)
catkin_python_setup()

可以参考以下两个博客修改:
https://blog.csdn.net/Cyril__Li/article/details/78979253
https://blog.csdn.net/light_jiang2016/article/details/55505627

  (3)将call.py修改为ros节点,下面将两个代码贴出来,可以参照修改。
call.py:

#-*- coding: utf-8 -*-


# 您需要先注册一个App,并将得到的API key和API secret写在这里。
# You need to register your App first, and enter you API key/secret.
API_KEY = ""
API_SECRET = ""

# 网络图片的URL地址,调用demo前请填上内容
# The url of network picture, please fill in the contents before calling demo
face_one = 'http://bj-mc-prod-asset.oss-cn-beijing.aliyuncs.com/mc-official/images/face/demo-pic11.jpg'
# 本地图片的地址,调用demo前请填上内容
# Local picture location, please fill in the contents before calling demo
face_two = './demo.jpeg'
# 本地图片的地址,调用demo前请填上内容
# Local picture location, please fill in the contents before calling demo
face_search = './demo.jpeg'

#国际版的服务器地址
#the server of international version
api_server_international = 'https://api-us.faceplusplus.com/facepp/v3/'

# Import system libraries and define helper functions
# 导入系统库并定义辅助函数
from pprint import pformat


def print_result(hit, result):
    def encode(obj):
        if type(obj) is unicode:
            return obj.encode('utf-8')
        if type(obj) is dict:
            return {encode(v): encode(k) for (v, k) in obj.iteritems()}
        if type(obj) is list:
            return [encode(i) for i in obj]
        return obj
    print hit
    result = encode(result)
    print '\n'.join("  " + i for i in pformat(result, width=75).split('\n'))


# First import the API class from the SDK
# 首先,导入SDK中的API类
from facepp import API, File


#创建一个API对象,如果你是国际版用户,代码为:api = API(API_KEY, API_SECRET, srv=api_server_international)
#Create a API object, if you are an international user,code: api = API(API_KEY, API_SECRET, srv=api_server_international)
api = API(API_KEY, API_SECRET)

# 创建一个Faceset用来存储FaceToken
# create a Faceset to save FaceToken
ret = api.faceset.create(outer_id='test')
print_result("faceset create", ret)

# 对图片进行检测
# detect image
Face = {}
res = api.detect(image_url=face_one)
print_result("person_one", res)
Face['person_one'] = res["faces"][0]["face_token"]

res = api.detect(image_file=File(face_two))
print_result("person_two", res)
Face['person_two'] = res["faces"][0]["face_token"]

# 将得到的FaceToken存进Faceset里面
# save FaceToken in Faceset
api.faceset.addface(outer_id='test', face_tokens=Face.itervalues())

# 对待比对的图片进行检测,再搜索相似脸
# detect image and search same face
ret = api.detect(image_file=File(face_search))
print_result("detect", ret)
search_result = api.search(face_token=ret["faces"][0]["face_token"], outer_id='test')

# 输出结果
# print result
print_result('search', search_result)
print '=' * 60
for k, v in Face.iteritems():
    if v == search_result['results'][0]['face_token']:
        print 'The person with highest confidence:', k
        break


# 删除无用的人脸库
# delect faceset because it is no longer needed
api.faceset.delete(outer_id='test', check_empty=0)

# 恭喜!您已经完成了本教程,可以继续阅读我们的API文档并利用Face++ API开始写您自
# 己的App了!
# 旅途愉快 :)
# Congratulations! You have finished this tutorial, and you can continue
# reading our API document and start writing your own App using Face++ API!
# Enjoy :)

ros_faceselect.py:

#!/usr/bin/env python
#-*- coding: utf-8 -*-
import rospy
from std_msgs.msg import Int32

import time		#导入python的time模块

import numpy as np  #导入python的numpy模块并更名为np
import cv2  #导入python的opencv模块

import os	#导入python的os模块
command="fswebcam -d /dev/video0 -r 600*600 /home/pi/Desktop/photo.jpeg"
photo = "/home/pi/Desktop/photo.jpeg"
compare_photo =  "/home/pi/catkin_ws/src/face_node/photo/photo_compare.jpeg"
hf_alt2_xml = "/home/pi/catkin_ws/src/face_node/haarcascade_frontalface_alt2.xml"

# 您需要先注册一个App,并将得到的API key和API secret写在这里。
# You need to register your App first, and enter you API key/secret.
API_KEY = "yJL5Mw02ZohjfElqG9BUXVDftC2AS8lw"
API_SECRET = "whXnDdVyiu0V6hL3lgWJfw0nFDiADLRX"
# Import system libraries and define helper functions
# 导入系统库并定义辅助函数
from pprint import pformat

def print_result(hit, result):
    def encode(obj):
        if type(obj) is unicode:
            return obj.encode('utf-8')
        if type(obj) is dict:
            return {encode(v): encode(k) for (v, k) in obj.iteritems()}
        if type(obj) is list:
            return [encode(i) for i in obj]
        return obj
    print hit
    result = encode(result)
    print '\n'.join("  " + i for i in pformat(result, width=75).split('\n'))
	
# First import the API class from the SDK
# 首先,导入SDK中的API类
from face_node.facepp import API, File
#创建一个API对象,如果你是国际版用户,代码为:api = API(API_KEY, API_SECRET, srv=api_server_international)
#Create a API object, if you are an international user,code: api = API(API_KEY, API_SECRET, srv=api_server_international)
api = API(API_KEY, API_SECRET)

rospy.init_node('opencv_face_node')

pub = rospy.Publisher('topic_face', Int32, queue_size=3)

#下面进入拍照循环
while not rospy.is_shutdown():
    os.system(command)#执行command所代表的指令,即拍照
    time.sleep(2)#等待2s
	#下面是用opencv进行人脸识别,识别出有人脸才进行下一步人脸比较,否则一直拍照
    face_cascade = cv2.CascadeClassifier(hf_alt2_xml)
    #read image读取图像
    img = cv2.imread(photo)
    #Convert to grayscale转换为灰度图
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    #detect face Multiscale 检测面尺度
    faces = face_cascade.detectMultiScale(gray, 1.3, 5)
  
    if faces!=():
        #利用face++的detectAPI识别刚刚拍摄的照片中的人脸,其实这句调试时能看到不少信息,方便些,可以省略
        detectresult=api.detect(api_key=API_KEY,api_secret=API_SECRET,image_file=File(photo))
        print_result('Detect result:', detectresult)		#将结果输出到打印到命令行界面上
		#调用face++的compareAPI将拍到的照片与本地权限者照片做比较,confidence表示拍到的照片与本地权限者照片是同一人的置信度
        comparation=api.compare(api_key=API_KEY,api_secret=API_SECRET,image_file1=File(compare_photo),image_file2=File(photo))
        confidence=comparation['confidence']
        if confidence >= 70:
            pub.publish(1)
        else:
            pub.publish(2)
    else:
        print "No one"

  代码下载地址:https://github.com/qmros/ros_facenode

4、将Face++官网的SDK修改为ros的节点。

  (1)将继电器的正、负、in端分别接树莓派GPIO的5V引脚、地引脚与11引脚,在程序中导入python的GPIO库,写入简单的GPIO引脚高低电平控制程序,观察继电器的状态。

import RPi.GPIO as GPIO#导入库
GPIO.setmode(GPIO.BOARD)  # BOARD编号方式,基于插座引脚编号
GPIO.setup(11, GPIO.OUT)#将GPIO的11引脚设为输出
GPIO.output(11, 1)# 让GPIO的11引脚为高电平
GPIO.output(11, 0) # 让GPIO的11引脚为低电平

  (2)通过连接arduino来控制继电器,参考网址创客智造
   https://www.ncnynl.com/archives/201610/917.html

运行结果


$cd ~/catkin_ws/
$catkin_make

编译通过之后,插上USB摄像头,运行

$roslaunch face_node face_node.launch

屏幕输出打印的信息,但识别到有人,它会将结果发布到topic_face的主题,没人的时候打印No one,我们打开另外一个命令窗口运行

$rostopic echo /topic_face

查看/topic_face发布的消息,如果是1,说明拍照的人和本地权限者照片相同,2的话,说明不是本地权限者。

参考文献


[1] 在树莓派上实现face++人脸识别 - oBuZuoPiQi的博客
https://blog.csdn.net/obuzuopiqi/article/details/54428433

[2] 基于opencv与face++人脸识别+树莓派的门禁管理系统设计报告
http://www.51hei.com/bbs/dpj-103117-1.html

[3] ROS Package中的Python使用规范 - Cyril__Li的博客
https://blog.csdn.net/Cyril__Li/article/details/78979253

[4] ros 编译 Python 文件 - 蒋亮亮的博客
https://blog.csdn.net/light_jiang2016/article/details/55505627

你可能感兴趣的:(机器人,ros,人脸识别)