基于OpenCV-Python及树莓派摄像头的打卡系统

一、打卡系统(需求)分析

教师:给每个学生制作唯一id的二维码分发、并可查看学生打卡记录(初始化学生信息、数据库查看考勤)
后勤:在需要打卡的地方安装树莓派摄像头,这里以教室为例(收集信息并返回到数据库中)
学生:用自己stu_id到指定位置打卡(录入打卡信息)

二、打卡系统(功能)分析

步骤 代码 作用 涉及内容
1 MakeQRcode.py 每个学生持一个QRcode(内容为stu_id) (考察Python)
2 ScanInvedio.py 由树莓派摄像头打卡记录 (机器视觉之OpenCV库&ARM原理)
3 SendMsg.py 树莓派把收集的数据发给服务器PC机 (通信原理:UDP待实现)
4 SaveInSql.py 由PC机把今日打卡内容传给数据备份 (数据库原理:stu_id、time)
5 CheckQRRecoad.py 数据库查询打卡stu_id和时间 (sql查询语句)

三、实现步骤

(一)准备工作

树莓派端(Raspberry3B+)
1 树莓派专用摄像头配置
2配置python的opencv-pythonzbar
服务器端(我的笔记本环境:Win10)
1 我的配置是Python3.0和MySQL8.0
2 pip安装python的opencv-pythonzbar

这里给出我之前的配置教程博客友情链接1
pi端:
树莓派配置摄像头教程
树莓派安装opencv3.4.1教程
win10端:
Win10安装opencv3.4.1配置教程
Win10配置pyzbar生成二维码教程

(二)生成stu_id二维码

友情链接2:基于Python生成二维码
在这里插入图片描述
具体讲解在上面篇博客中详细讲解过,这里就给出我的学号尾号0311二维码生成代码:
效果图:
在这里插入图片描述
源码:
MakeQRcode.py

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# 炫酷gif二维码
from MyQR import myqr
myqr.run(
    # 在命令后输入链接或者句子作为参数,然后在程序的当前目录中产生相应的二维码图片文件,默认命名为“qrcode.png”
    words='0311',
    version=1,  # 设置容错率为最高默认边长是取决于你输入的信息的长度和使用的纠错等级;而默认纠错等级是最高级的H
    level='H',  # 控制纠错水平,范围是L、M、Q、H,从左到右依次升高
    picture='test.gif',  # 用来将QR码图像与一张同目录下的图片相结合,产生一张黑白图片,格式可以是.jpg, .png, .bmp, .gif
    colorized=True,  # 可以使产生的图片由黑白(False)变为彩色(True)的
    contrast=1.0,  # 用以调节图片的对比度,1.0 表示原始图片,更小的值表示更低对比度,更大反之。默认为1.0。
    brightness=1.0,  # 用来调节图片的亮度
)

(三)打卡(扫码、存储)

(1)打卡存入数据库原理

1 扫描原理及过程在前面博客也具体讲述过,这里稍稍略过~
2 详细讲解一下:存入MySQL数据库步骤
友情链接3:Python连接MySQL数据库(增删查改)教程

  1. 建表:(这里命名我的为数据库名code_recoad、表名recode2
    在这里插入图片描述

  2. 打卡
    总结之前对视频流扫码函数,这里只增加了一个savedata(stu_id)函数进行数据保存
    注意 这里库名和表名,列名要对应数据库的内容!

源码:
SaveInSql.py

'''
==============================
5、将识别的时间及二维码信息保存到数据库中
==============================
'''
# coding=utf-8
import cv2
import pyzbar.pyzbar as pyzbar
import datetime
import pymysql


def savedata(stu_id):
    db = pymysql.connect(host='127.0.0.1',
                         port=3306,
                         user='root',
                         password='wy123456',
                         db='code_recoad',
                         charset='utf8')
    cursor = db.cursor()
    now_time = datetime.datetime.now().strftime(
        "%Y-%m-%d %H:%M:%S")  # strftime格式化时间函数
    data = (stu_id, now_time)
    sql = """INSERT INTO recode2(stu_id,
         time)
         VALUES ('%s', '%s')"""
    try:
        cursor.execute(sql % data)
        db.commit()
    except:
        print("请勿重复打卡!")
        db.rollback()
    finally:
        str = "打卡成功!(已保存数据库)"
        print(stu_id + str)
        db.close()


def decodeDisplay(image):
    barcodes = pyzbar.decode(image)
    for barcode in barcodes:
        # 提取二维码的边界框的位置
        # 画出图像中条形码的边界框
        (x, y, w, h) = barcode.rect
        cv2.rectangle(image, (x, y), (x + w, y + h), (225, 225, 225), 2)

        # 提取二维码数据为字节对象,所以如果我们想在输出图像上
        # 画出来,就需要先将它转换成字符串
        global barcodeData
        barcodeData = barcode.data.decode("utf-8")
        barcodeType = barcode.type

        # 绘出图像上条形码的数据和条形码类型
        text = "{} ({})".format(barcodeData, barcodeType)
        cv2.putText(image, text, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX,
                    .5, (225, 225, 225), 2)
        savedata(barcodeData)
        # 向终端打印条形码数据和条形码类型
        # print("[INFO] Found {} barcode: {}".format(barcodeType, barcodeData))
    return image


def detect():
    camera = cv2.VideoCapture(0)
    while True:
        # 读取当前帧
        ret, frame = camera.read()
        # 转为灰度图像
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        im = decodeDisplay(gray)

        cv2.waitKey(5)
        cv2.imshow("camera", im)
        # 如果按键q则跳出本次循环
        if cv2.waitKey(10) & 0xFF == ord('q'):
            break
    camera.release()
    cv2.destroyAllWindows()


if __name__ == '__main__':
    detect()
  1. 这是在PC端新建 SaveInSql.py 测试运行结果:
    在这里插入图片描述
    在这里插入图片描述
    数据库中成功录入:
    在这里插入图片描述

(2)移植到树莓派端

因为不可能每次打卡时,都把笔记本搬到现场,然后进行数据采集和处理;所以这里我们采取通过树莓派官方摄像头进行数据采集!

1 配置环境
与之前PC端相同配置…
在这里插入图片描述
2 树莓派摄像头采集打卡数据

3 UDP通信传回数据、笔记本进行数据处理

想法一:通过UDP通信将获取的内容传回PC端再进行数据保存
想法二:将数据保存到txt文件,通过文件传输传回PC端;这里没有实践,dingo!
遗留问题!不太明白,用PC端测试文件代替处理~

(四)查询打卡

现在数据库有我们今日打卡的内容如下:
在这里插入图片描述
对数据库已有内容进行查询:
在这里插入图片描述
CheckQRRecoad.py

# -*- coding: UTF-8 -*-
import pymysql

# 打开数据库连接
con = pymysql.connect(
    host='127.0.0.1',
    port=3306,
    user='root',
    password='wy123456',
    db='code_recoad',
    charset='utf8'
)

# 使用cursor()方法获取操作游标
cursor = con.cursor()

# SQL 查询语句
sql = "SELECT * FROM recode2"
sum = 0  # 统计已打卡人数
try:
    # 执行SQL语句
    cursor.execute(sql)
    # 获取所有记录列表
    results = cursor.fetchall()
    print("       学生打卡记录查询 ")
    print("-----------------------------")
    print("学号                  打卡时间")
    for it in results:
        for i in range(len(it)):
            print(it[i], end='    ')
        sum += 1
        print("\n")
    print("-----------------------------")
    print("    统计:(" + str(sum) + ")人已打卡")
except:
    print("Error: unable to fecth data")
# 关闭数据库连接
cursor.close()
con.close()

查询结果:

在这里插入图片描述

升级查询版
新建stu表:
在这里插入图片描述
录入学生数据:
在这里插入图片描述
修改查询语句:

#sql = "SELECT * FROM recode2"
sql = """select recode2.stu_id,stu.stu_name,recode2.time 
        from recode2,stu
        where 
           recode2.stu_id=stu.stu_id
        """

在这里插入图片描述

(五)将打卡记录和迟到情况打印成txt文件保存

今日打卡记录保存为txt文件格式,利于打印和查看

  • 主要是两条select语句筛选出总学生名单stu表打卡记录decoad2表中相同和不同部分元素
  • 还有对文件的操作:写文件 fp = open(file, "w")全部权限操作 fp = open(file, "a")

新建 loadfile.py 文件夹
在这里插入图片描述
在同目录下,新建CheckQRRecord.txt文件:
在这里插入图片描述
源码:

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

import pymysql

# 统计打卡和未打卡人数并写入txt文档中


def get_loan_number(file):
    connect = pymysql.Connect(
        host='127.0.0.1',
        port=3306,
        user='root',
        password='wy123456',
        db='code_recoad',
        charset='utf8'
    )
    cursor = connect.cursor()
    sql = """select recode2.stu_id,stu.stu_name,recode2.time 
        from recode2,stu
        where 
           recode2.stu_id=stu.stu_id
        """
    sum = 0  # 统计已打卡人数
    try:
        # 执行SQL语句
        cursor.execute(sql)
        # 获取所有记录列表
        fp = open(file, "w")
        results = cursor.fetchall()
        fp.write("            学生打卡记录表1\n")
        fp.write("-----------------------------------\n")
        fp.write("学号" + "\t" + "姓名" + "\t" + "打卡时间" + "\n")
        for it in results:
            sum += 1
            fp.write(it[0] + "\t")
            fp.write(it[1] + "\t")
            fp.write(it[2] + "\n")
        fp.write("------------------------------------\n")
        fp.write("总计:%d人已签到\n" % sum)
        print("打印完成!\n已签到%d人\n" % sum)
    except:
        print("未查询到数据!")
    # 查询缺勤人员名单
    sql2 = "select * from stu where stu_id not in (select stu_id from recode2)"
    cursor.execute(sql2)
    number = cursor.fetchall()
    fp = open(file, "a")
    loan_count = 0   # 统计未打卡人数
    fp.write("\n      缺勤记录表2  \n")
    fp.write("---------------------------------------\n")
    fp.write("学号" + "\t" + "姓名" + "\t" + "班级" + "\n")
    for loanNumber in number:
        loan_count += 1
        fp.write(loanNumber[0] + "\t")
        fp.write(loanNumber[1] + "\t")
        fp.write(loanNumber[2] + "\n")
    fp.write("--------------------------------------\n")
    fp.write("总计:%d人未签到" % loan_count)
    fp.close()
    cursor.close()
    connect.close()
    print("未签到%d人" % loan_count)


if __name__ == "__main__":
    file = r"CheckQRRecord.txt"
    get_loan_number(file)

最终效果:
在这里插入图片描述


附:本次实验遇到的问题:
1
在这里插入图片描述


本次实验的不足:

  1. 树莓派端传回数据有想法,但没有实现!
  2. 数据库打卡记录表的不足:应该加载update部分,因为stu-id为主键,打卡只能记录一次。所以应该设置一个 DBOperate.py 对每天打卡记录表进行清零,同时每天保存.txt文件应该按照当天时间进行命名保存,这样管理比较完善!

猜你喜欢

转载自blog.csdn.net/cungudafa/article/details/86221365
今日推荐