人脸识别电风扇(AI电风扇 face_recognition)

人脸识别电风扇是什么?

通过PC摄像头识别人脸,人在PC前时风扇自动打开,离开时自动关闭。
效果图:

人脸识别开启+人离开后3S关闭:
在这里插入图片描述
非本人不开启:
在这里插入图片描述

为什么做?

每到夏天就要开风扇,但我们并不是无时无刻都在电脑前,离开时(比如上厕所、下班)如果不关闭,就会造成资源浪费,但如果每次都关闭就会很麻烦。这个工具可以帮你省(zhuang)事(bi),又节(zhuang)能(bi)!

需要什么?

软件:
python核心包:face_recognition、serial、OpenCV
硬件:
pc(带摄像头)
arduino开发板
USB风扇

现在开始

逻辑:每读取一帧进行一次下图循环,循环结束后立即读取当前帧继续循环。

Created with Raphaël 2.2.0 开始 查找人脸 本人? 控制风扇开启 结束 3s内是否出现过? 无操作 控制风扇关闭 yes no yes no

OK,上代码!!
python:

# -*- coding: utf-8 -*-
# 摄像头头像识别
import face_recognition
import cv2
import threading
import time
import time
import serial
import sys
import os
import time
import re
#串口
global MAX_LOOP_NUM
global newCmd
MAX_LOOP_NUM = 10
print(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())))

def waitForCmdOKRsp():
    maxloopNum = 0
    while True:
        line = ser.readline()
        maxloopNum = maxloopNum + 1

        try:
            print("Rsponse : %s" % line.decode('utf-8'))
        except:
            pass

        if (re.search(b'OK', line)):
            break
        elif (maxloopNum > MAX_LOOP_NUM):
            sys.exit(0)


def sendAT_Cmd(serInstance, atCmdStr, waitforOk):
#    print("Command: %s" % atCmdStr)
    serInstance.write(atCmdStr.encode('utf-8'))
    # or define b'string',bytes should be used not str
#    if (waitforOk == 1):
#        waitForCmdOKRsp()
#    else:
#        waitForCmdRsp()
class myThread2 (threading.Thread):#该线程用于控制开发板
    def __init__(self, video_capture, name, counter):
        threading.Thread.__init__(self)
        self.video_capture = video_capture
    def run(self):
        global frame1
        global turnon
        turnon=0
        # ser = serial.Serial("/dev/cu.usbmodemHIDP1", 9600, timeout=30)
        try:#连接开发板
            ser = serial.Serial("COM3", 9600, timeout=30)
        except:
            ser = serial.Serial("COM4", 9600, timeout=30)
        i=1
        t0=0
        t1=0
        t2=0
        t3=0
        t4=0
        guanbi = 1
        sendAT_Cmd(ser, 'b', 1)
        while i < 2:
            if turnon == 1:
                t4 = t3
                t3 = t2
                t2 = t1
                t1 = t0
                t0 = 1
                sendAT_Cmd(ser, 'a', 1)
                guanbi = 0
                time.sleep(0.6)
            elif (t0 + t1 + t2 + t3 + t4) > 0:
                t4 = t3
                t3 = t2
                t2 = t1
                t1 = t0
                t0 = 0
                # sendAT_Cmd(ser, 'a', 1)
                time.sleep(0.6)
            elif guanbi == 1:
                t4 = t3
                t3 = t2
                t2 = t1
                t1 = t0
                t0 = 0
                # sendAT_Cmd(ser, 'b', 1)
                # guanbi = 1
                time.sleep(0.6)
            else:
                t4 = t3
                t3 = t2
                t2 = t1
                t1 = t0
                t0 = 0
                sendAT_Cmd(ser, 'b', 1)
                guanbi = 1
                time.sleep(0.6)

thread2 = myThread2(1, "Thread-2", 1)
thread2.start()


# global video_capture
video_capture = cv2.VideoCapture(0)
# video_capture.open("rtsp://admin:xxxx@192.168.10.91:554/Streaming/Channels/101?transportmode=unicast")#读取海康威视摄像头
video_capture.read()#读取本地摄像头
#time.sleep(10)
# 本地图像
person1_image = face_recognition.load_image_file("zyw.jpg")
person1_face_encoding = face_recognition.face_encodings(person1_image)[0]

# # 本地图像二
person2_image = face_recognition.load_image_file("gzw.jpg")
person2_face_encoding = face_recognition.face_encodings(person2_image)[0]

# 本地图片三
person3_image = face_recognition.load_image_file("gzm1.jpg")
person3_face_encoding = face_recognition.face_encodings(person3_image)[0]

# Create arrays of known face encodings and their names
# 脸部特征数据的集合
known_face_encodings = [
    person1_face_encoding,
    person2_face_encoding,
    person3_face_encoding,
]

# 人物名称的集合
known_face_names = [
    "zhao",
    "geng",
    "Mingo",
]

face_locations = []
face_encodings = []
face_names = []
process_this_frame = True

#s=[]
ret, frame = video_capture.read()

#多线程
class myThread (threading.Thread):
    def __init__(self, video_capture, name, counter):
        threading.Thread.__init__(self)
        self.video_capture = video_capture
    def run(self):
        global frame1
        i=1
        while i<2:
            ret, frame1 = self.video_capture.read()
            #frame = cv2.flip(frame1, -1)
            # s.append(frame)
            #time.sleep(0.3)

thread1 = myThread(video_capture, "Thread-1", 1)
thread1.start()

time.sleep(1)
while True:
    # 读取摄像头画面
    #ret, frame = video_capture.read()
    frame = cv2.flip(frame1,1)#图像翻转:frame = cv2.flip(frame1, -1)
    # 改变摄像头图像的大小,图像小,所做的计算就少
    small_frame = cv2.resize(frame, (0, 0), fx=0.25, fy=0.25)
    # opencv的图像是BGR格式的,而我们需要是的RGB格式的,因此需要进行一个转换。
    rgb_small_frame = small_frame[:, :, ::-1]
    # Only process every other frame of video to save time
    if process_this_frame:
        # 根据encoding来判断是不是同一个人,是就输出true,不是为flase
        face_locations = face_recognition.face_locations(rgb_small_frame)
        face_encodings = face_recognition.face_encodings(rgb_small_frame, face_locations)
        face_names = []
        for face_encoding in face_encodings:
            # 默认为unknown
            #matches = face_recognition.compare_faces(known_face_encodings, face_encoding)
            matches = face_recognition.face_distance(known_face_encodings, face_encoding)
            name = "Unknown"
            min_distance = min(matches)
            if min_distance < 0.4:
                i = matches.argmin()
                name = known_face_names[i]
                print(name+":"+time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))+":"+str(min_distance))
                turnon = 1
            else:
                turnon = 0
            face_names.append(name)
        if face_encodings==[]:
            turnon = 0
    process_this_frame = not process_this_frame
    # 将捕捉到的人脸显示出来
    for (top, right, bottom, left), name in zip(face_locations, face_names):
        # Scale back up face locations since the frame we detected in was scaled to 1/4 size
        top *= 4
        right *= 4
        bottom *= 4
        left *= 4

        # 矩形框
        cv2.rectangle(frame, (left, top), (right, bottom), (0, 0, 255), 2)

        #加上标签
        cv2.rectangle(frame, (left, bottom - 35), (right, bottom), (0, 0, 255), cv2.FILLED)
        font = cv2.FONT_HERSHEY_DUPLEX
        cv2.putText(frame, name, (left + 6, bottom - 6), font, 1.0, (255, 255, 255), 1)

    # Display
    cv2.namedWindow('monitor',cv2.WINDOW_NORMAL)
    #WINDOW_NORMAL:用户便可以改变窗口的大小(没有限制)
    #WINDOW_AUTOSIZE:窗口大小会自动调整以适应所显示的图像,并且不能手动改变窗口大小.
    #WINDOW_OPENGL:窗口创建的时候便会支持OpenGL
    cv2.imshow('monitor', frame)
    #print(str(time.time())+"a")
    # 按Q退出
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
video_capture.release()
cv2.destroyAllWindows()

arduino:

#include "Keyboard.h"

void setup() {
  // open the serial port:
  Serial.begin(9600);
  // initialize control over the keyboard:
  Keyboard.begin();
  pinMode(2, OUTPUT);
}
char inChar = 'b';
void loop() {
rial.available() > 0) {
        inChar = Serial.read();
    }
    if (inChar == 'a') {
      digitalWrite(2, HIGH);   // turn the LED on (HIGH is the voltage level)
    }
    if (inChar == 'b') {
      digitalWrite(2, LOW);    // turn the LED off by making the voltage LOW
    }
  
}

总结

现在你可能觉得很厉害,这玩意真是又方(zhuang)便(bi)、又节(zhuang)能(bi)!
但是!!!!!!!!!!!!
在这里插入图片描述在这里插入图片描述
好吧,我承认他并不节能,但是还算 方(zhuang)便(bi) 吧??!!

后记

虽然用30%的CPU性能换取一个风扇开关功能是不合算的,但实现该功能并不是本文的最终目的,本文更多的是想帮助大家学习与了解“人脸识别”技术。

另外,项目其实还有很大优化空间。比如:当前代码逻辑是CPU每处理一帧后会立即处理下一帧,但这根本没必要。如果代码设计成每秒处理一帧的话,CPU占用是可以大大降低的。而这并不是本文重点,所以有兴趣的小伙伴可以自己研究。

最后,这玩意还有其他应用吗?
当然有! 比如 “远程办公” 可以监控真实工作时间,哈哈!!!

  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值