基于树莓派的便携考生人证核实设备与系统

1.树莓派系统Raspbian的安装

1.1 下载系统镜像

镜像下载地址

https://www.raspberrypi.org/downloads/raspbian/

image

注:官方的Raspbian有三个版本,在此我们选择
Raspbian Buster with desktop and recommended software

1.2 烧录系统镜像

为了安装Raspbian到树莓派内 我们需要把镜像烧录到SD卡中
使用的软件为balenaEtcher

balenaEtcher官方网址

https://www.balena.io/etcher/

安装后我们选择系统镜像并插入SD卡进行烧录

image

2.硬件连接和搭建

2.1 硬件参数

名称型号参数
主板Raspberry Pi 4 Model BBroadcom BCM2711 quad-core Cortex-A72 (ARM v8) 64-bit SoC @ 1.5 GHz
摄像头Razer USB Camera自动对焦
屏幕Waveshare 3.5inch RPi LCD(B)320×480分辨率 电阻式触摸控制
电池Raspberry Pi Club UPSPack V23800mhA

3.树莓派系统的配置

为了方便的调试系统 我们需要开启SSH和VNC功能

注:安装好的SD卡分区为EXT4格式 在WINDOWS系统下无法常规读取 因此我们需要使用DiskGenius软件对SD卡进行操作

image
DiskGenius官方网址

http://www.diskgenius.cn/

3.1 开启SSH

SSH的开启非常便捷 我们可以在/boot/分区内添加一个名为SSH的文件 系统在启动时便会自动的开启SSH功能 但此时并不能使用root用户登录SSH 因此我们需要修改文件配置 使用pi用户登录ssh输入以下指令

sudo vim /etc/ssh/sshd_config

找到 PermitRootLogin without-password 更改为 PermitRootLogin yes 便可使用root用户登录SSH

为了方便后续操作 我们需要使用root用户登录对系统进行配置
在成功进入系统后使用命令

sudo passwd root

在提示下设置root用户密码 便可自由使用SSH功能

3.2设置Wifi

sudo vim /boot/wpa_supplicant.conf

country=CN
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
 
network={
ssid="WiFi-A"
psk="12345678"
key_mgmt=WPA-PSK
priority=1
}

3.3 开启VNC

在SSH终端内输入

sudo raspi-config

即可进入树莓派系统配置界面
image
选择 [5 Interfacing Options]->[P3 VNC] 即可开启VNC功能

注:配置完需进行重启
在Windows/Linux等平台可以使用VNC官方连接软件VNC Viewer进行连接

下载地址https://www.realvnc.com/en/connect/download/vnc/

3.4 配置树莓派摄像头

在SSH终端内输入

sudo raspi-config

即可进入树莓派系统配置界面
image
选择 [5 Interfacing Options]->[P1 Camera] 即可开启摄像头功能

注:配置完需进行重启 如使用CSI摄像头需在
/etc/modules
末尾添加
bcm2835-v4l2

3.5 安装显示屏驱动

在SSH终端内输入

git clone https://github.com/waveshare/LCD-show.git
cd LCD-show/
sudo ./LCD35B-show

重启后即可使用(为了方便使用,可以调整屏幕显示方向,参见#设置显示方向)。

注意1:执行apt-get upgrade会导致LCD无法正常工作。此时需要编辑SD卡中的 config.txt 文件,并删除这一句:dtoverlay=ads7846。

注意2:在Raspbian-lite下,需要执行sudo ./LCD35B-show lite命令,以安装驱动。

3.6 程序的开启自启动

关键词释意
[Desktop Entry]文件头
Encoding编码
Name应用名称
Name[xx]不同语言的应用名称
GenericName描述
Comment注释
Exec执行的命令
Icon图标路径
Terminal是否使用终端
Type启动器类型
Categories应用的类型(内容相关)

在/home/pi/.config/新建一个名为autostart的文件夹

mkdir /home/pi/.config/autostart

在 autostart 目录下新建boot.desktop

nano /home/pi/.config/autostart/project.desktop

文件内容如下

[Desktop Entry]
Categories=Application;Programme;
Comment=Demo
Encoding=UTF-8
Exec=python /home/pi/Desktop/project/main.py
Name=Demo Desktop
Type=Application

3.7 设置显示方向

cd LCD-show/
./LCD35B-show 180

注:执行apt-get upgrade会导致LCD无法正常工作。此时需要编辑SD卡中的 config.txt 文件,并删除这一句:dtoverlay=ads7846

4.相关组件的编译与安装

编译先必须更改swap 大小,否则会出现内存不足导致编译卡住的情况发生

sudo vi /etc/dphys-swapfile

将CONF_SWAPSIZE的值修改成2048

Ubuntu缺省情况下,并没有提供C/C++的编译环境,因此还需要手动安装。但是如果单独安装gcc以及g++比较麻烦,幸运的是,Ubuntu提供了一个build-essential软件包。也就是说,安装了该软件包,编译c/c++所需要的软件包也都会被安装。因此如果想在Ubuntu中编译c/c++程序,只需要安装该软件包就可以了。

4.1 curl

sudo apt-get install curl

cURL是一个利用URL语法在命令行下工作的文件传输工具,1997年首次发行。它支持文件上传和下载,所以是综合传输工具,但按传统,习惯称cURL为下载工具。cURL还包含了用于程序开发的libcurl。

4.2 opencv

OpenCV的全称是Open Source Computer Vision Library,是一个跨平台的计算机视觉库。OpenCV是由英特尔公司发起并参与开发,以BSD许可证授权发行,可以在商业和研究领域中免费使用。OpenCV可用于开发实时的图像处理、计算机视觉以及模式识别程序。该程序库也可以使用英特尔公司的IPP进行加速处理。

sudo apt-get install build-essential
sudo apt-get install cmake git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev
sudo apt-get install python-dev python-numpy libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libjasper-dev libdc1394-22-dev
cd /root/
git clone https://github.com/opencv/opencv.git
git clone https://github.com/opencv/opencv_contrib.git
cd /root/opencv
mkdir build
cd build
cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/usr/local -DOPENCV_EXTRA_MODULES_PATH=/root/opencv_contrib/modules /root/opencv/
make -j4
sudo make install

4.3 tkinter

pip install Pillow

5.代码构建

5.1 compare_core.py

# coding=UTF-8
import requests
import os
from json import JSONDecoder
import urllib3,base64,json
import numpy

def submit(url,submit_data):
    response = requests.post(url, data=submit_data)
    req_con = response.content.decode('utf-8')
    req_dict = JSONDecoder().decode(req_con)
    return req_dict
  
def get_access_token(client_id,client_secret):
    url = "https://aip.baidubce.com/oauth/2.0/token"
    data = {"grant_type": "client_credentials", "client_id": client_id,"client_secret":client_secret}
    response=submit(url,data)
  
    access_token=response['access_token']
    return access_token

def face_compare_baidu(access_token,locate1,locate2):
    url = "https://aip.baidubce.com/rest/2.0/face/v3/match"+"?access_token=" + access_token

    file1 = open(locate1,'rb')
    file2 = open(locate2,'rb')
    image1 = base64.b64encode(file1.read())
    image2 = base64.b64encode(file2.read())
  
    data = json.dumps(
    [{"image": str(image1,'utf-8'), "image_type": "BASE64", "face_type": "CERT", "quality_control": "NONE"},
     {"image": str(image2,'utf-8'), "image_type": "BASE64", "face_type": "LIVE", "quality_control": "NORMAL"}])

    response=submit(url,data)
    print(response)
    if(response['error_code']!=0):
        return 0
    score=response['result']['score']
    return score

5.2 upload.py

import requests,base64,ssl
session = requests.session()


def upload(locate1,locate2,confidence):
    file1 = open(locate1,'rb')
    file2 = open(locate2,'rb')
    image1 = base64.b64encode(file1.read())
    image2 = base64.b64encode(file2.read())
    url = "https://your_iot_domain/index.php/admin/add"

    session.headers = {
        "Host": "your_iot_domain",
        "Connection": "keep-alive",
        "Accept": "application/json, text/javascript, */*; q=0.01",
        "Origin": "https://your_iot_domain/",
        "X-Requested-With": "XMLHttpRequest",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36",
        "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
        "Referer": "https://your_iot_domain/index.php/admin.html",
        "Accept-Encoding":"gzip, deflate",
        "Accept-Language": "zh-CN,zh;q=0.9",
        }
    data = {
            'image1':'data:image/jpg;base64,'+str(image1,'utf-8'),
            'image2':'data:image/jpg;base64,'+str(image2,'utf-8'),
            'confidence':confidence
        }
    res = session.post(url=url,data=data,verify=False)
    print(res.text)

5.3 main.py

# coding=UTF-8
import cv2
import threading
import os
import time

from tkinter import *
from PIL import Image, ImageTk
from compare_core import *


flag_img1=0
flag_img2=0
class Cameara:
    def __init__(self, src=0):
        self.stream = cv2.VideoCapture(src)
        self.stream.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
        self.stream.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
        (self.grabbed, self.frame) = self.stream.read()
        self.stopped = False

    def start(self):
        threading.Thread(target=self.update, args=()).start()

    def update(self):
        while True:
            if self.stopped:
                return
            (self.grabbed, self.frame) = self.stream.read()

    def read(self):
        return self.frame

    def stop(self):
        self.stopped = True

camera = Cameara("/dev/video0")

def resizeImage(image,width=None,height=None,inter=cv2.INTER_AREA):
    newsize = (width,height)
    (h,w) = image.shape[:2]
    if width is None and height is None:
        return image
    if width is None:
        n = height/float(h)
        newsize = (int(n*w),height)
    else :
        n = width/float(w)
        newsize = (width,int(h*n))
    newimage = cv2.resize(image, newsize, interpolation=inter)
    return newimage

def rotate(image, angle, center=None, scale=1.0):
    h, w = image.shape[:2]
    if center is None:
        center = (w // 2, h // 2)

    M = cv2.getRotationMatrix2D(center, angle, scale)

    rotated = cv2.warpAffine(image, M, (w, h))
    return rotated 


def compare_face_baidu():
    global flag_img1
    global flag_img2
    access_token=get_access_token('sXgKYI****0o8G5Fe4O','DxAhEzSWqAGv1sHL******xYKixpxOcZq')
    print(access_token)
    score=face_compare_baidu(access_token,"1.jpg","2.jpg")
    if(score>=80):
        Label3.config(text="对比通过 相似度 %.2f"%(score)+"%")
    else:
        Label3.config(text="对比不通过 相似度 %.2f"%(score)+"%")
  
    os.remove("1.jpg")
    os.remove("2.jpg")
    flag_img1=0
    flag_img2=0



def show_frame():
    global flag_img1
    global flag_img2
    global camera

    camera.start()
    #indow.after(10, show_frame)
    while True:
        frame = camera.read()

        frame = rotate(frame,90)
        cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)

        w = cv2image.shape[1]
        h = cv2image.shape[2]
        image_origin = resizeImage(cv2image,int(w/3.5),int(h/3.5),cv2.INTER_LINEAR)

        img = Image.fromarray(image_origin)
        imgtk = ImageTk.PhotoImage(image=img)
        if flag_img1==0:
            Label1.imgtk = imgtk
            Label1.configure(image=imgtk)
        if flag_img2==0:
            Label2.imgtk = imgtk
            Label2.configure(image=imgtk)
  
  
def event_button0():
    Thread0.start()

def event_button1():
    global flag_img1
    global camera
    frame = camera.read()
    saveimage = rotate(frame,90)
    cv2.imwrite("1.jpg",saveimage)
    flag_img1=1


def event_button2():
    global flag_img2
    global camera
    frame = camera.read()
    saveimage = rotate(frame,90)
    cv2.imwrite("2.jpg",saveimage)
    flag_img2=1

def event_button3():
    global flag_img1
    if flag_img1:
        os.remove("1.jpg")
        flag_img1=0

def event_button4():
    global flag_img2
    if flag_img2:
        os.remove("2.jpg")
        flag_img2=0

def event_button5():
    Label3.config(text="对比中......")
    Thread1=threading.Thread(target=compare_face_baidu,name='compare_face_baidu')
    Thread1.start()

if __name__ == "__main__":

    #Set up GUI
    window = Tk()  
    window.wm_title("人证核实界面")
    window.geometry('680x480')

    #Graphics window
    main_Frame = Frame(window)
    main_Frame.pack()
    Frame_left=Frame(main_Frame)
    Frame_right=Frame(main_Frame)
    Frame_left.pack(side='left')
    Frame_right.pack(side='right')
  
    #Capture video frames
    Label1 = Label(Frame_left)
    Label1.pack()
    Label2 = Label(Frame_right)
    Label2.pack()

    Button1=Button(Frame_left,text="拍照",command=event_button1)
    Button1.pack(ipadx=50)
    Button2=Button(Frame_right,text="拍照",command=event_button2)
    Button2.pack(ipadx=50)
    Button3=Button(Frame_left,text="重拍",command=event_button3)
    Button3.pack(ipadx=50)
    Button4=Button(Frame_right,text="重拍",command=event_button4)
    Button4.pack(ipadx=50)
    Label3=Label(window,text ='等待拍照....',justify=LEFT)
    Label3.pack()


    Button0=Button(Frame_left,text="开启摄像头",command=event_button0)
    Button0.pack(ipadx=50)
    Button5=Button(Frame_right,text="对         比",command=event_button5)
    Button5.pack(ipadx=50)

    if(os.path.exists('1.jpg')==True):
        os.remove("1.jpg")
    if(os.path.exists('2.jpg')==True):
        os.remove("2.jpg")
    Thread0=threading.Thread(target=show_frame,name='show_frame')

    window.mainloop()
Last modification:December 23, 2020
如果觉得我的文章对你有用,请随意赞赏