大部分童鞋的树莓派是不是一直在吃灰呢?一直闲置着,倒不如用它做一个简易监控,如果检测到人脸后,就拍照上传到指定地方,或发消息提醒。
本内容来源于“基于树莓派的魔镜”,感兴趣的童鞋可以点击观看:演示视频和教程。
先看效果吧:
准备材料:
能用的树莓派、树莓派专用摄像头或USB摄像头、网线(稳定点)、LED灯可选
实现步骤:
1、安装OpenCV。可参考视频:教程(三) 第三方库的安装
2、推送消息部分。我用的是免费的企业微信推送,需要注册一个企业微信(https://work.weixin.qq.com)。童鞋们也可以使用免费的Qmsg酱推送到QQ或Server酱推送到微信(免费的QQ微信消息推送机器人,想要不?)。
或者使用自己的服务器搭建一个图片上传和浏览网页,可参考视频:教程(五) 服务端部署
3、下载haarcascade_frontalface_alt.xml文件,编写主体代码。
下载链接:http://xfxuezhang.cn/WEB/SHARE/haarcascade_frontalface_alt.zip
import requests
import base64
import time
import cv2
#from matplotlib import pyplot as plt
import os
import random
import json
import RPi.GPIO as GPIO
import time
def carDetect(rootPath):
cap = cv2.VideoCapture(0) # 0为默认,1为第二个
width = 512 #定义摄像头获取图像宽度
height = 512 #定义摄像头获取图像长度
cap.set(cv2.CAP_PROP_FRAME_WIDTH, width) #设置宽度
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height) #设置长度
print(">> 摄像头打开:", cap.isOpened())
while True:
ret, frame = cap.read() # 窗口名frame
cv2.imshow('image', frame)
cv2.waitKey(1)
continue
cap.release() # 释放摄像头
cv2.destroyWindow('frame') # 删除窗口
# 向服务器上传图片
def uploadImg(filepath):
url = 'http://xfxuezhang.cn/WEB/MagicMirror/upload_file.php'
filename = filepath.split('/')[-1]
if filename:
files = {"file": (filename, open(filepath, "rb"), "image/png")}
html = requests.post(url, files=files)
print(">> 上传完成!")
def sendImgByCoolPush(imgName):
msgUrl = 'https://qmsg.zendee.cn/send/d05e1f7acded6f948f3a61da9d9f7708?msg='
imgUrl = 'http://xfxuezhang.cn/WEB/MagicMirror/images/'+imgName
url = msgUrl + imgUrl
requests.get(url)
# 人脸识别并截图(这里是主要入口函数)
def faces_video():
"""人脸识别并截图(这里是主要入口函数)"""
haarcascade_path = r'data/haarcascades/haarcascade_frontalface_alt.xml'
face_cascade = cv2.CascadeClassifier(haarcascade_path) # 获取训练好的人脸的参数数据
load_succeed = face_cascade.load(haarcascade_path)
print('load haarcascade: ', load_succeed) # 训练数据文件是否导入成功
cap = cv2.VideoCapture(0) # 0为默认,1为第二个
width = 256 #定义摄像头获取图像宽度
height = 256 #定义摄像头获取图像长度
cap.set(cv2.CAP_PROP_FRAME_WIDTH, width) #设置宽度
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height) #设置长度
print(">> 摄像头打开:", cap.isOpened())
# last_time = ''
last_time = int(time.time()) # s
while True:
ret, frame = cap.read() # 读取1帧摄像头图像
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 图像矩阵
faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1,
minNeighbors=10,
flags=cv2.CASCADE_DO_CANNY_PRUNING, # cv2.CASCADE_SCALE_IMAGE,
minSize=(20, 20)
)
if len(faces) > 0:
print('faces: ', len(faces))
for x, y, w, h in faces:
cv2.rectangle(frame, (x, y), (x + w, y + w), (0, 255, 0), 2) # 画矩形
curr_time = int(time.time()) # s
if curr_time-last_time > 2:
# GPIO.output(26, GPIO.HIGH)
# GPIO.output(12, GPIO.HIGH)
# time.sleep(0.1) # 100ms
# GPIO.output(12, GPIO.LOW)
last_time = curr_time
imgName = time.strftime("%Y-%m-%d_%H-%M-%S", time.localtime())
imgPath = os.getcwd() + '/img/'+imgName+'.jpg'
cv2.imwrite(imgPath, frame) # 保存图像
print(imgName+" => 捕获到人脸,已保存照片")
uploadImg(imgPath)
sendImgByCoolPush(imgName+'.jpg') # send by coolpush
# GPIO.output(26, GPIO.LOW)
cv2.imshow('frame', frame) # 显示图像
key = cv2.waitKey(1) & 0xFF # 等待键盘输入,延时为毫秒级
if key == ord('q'): # 按q退出
break
cap.release() # 释放摄像头
cv2.destroyWindow('frame') # 删除窗口
def GpioInit():
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(26, GPIO.OUT) # LED
GPIO.output(26, GPIO.LOW)
GPIO.setup(12, GPIO.OUT) # BEEP
GPIO.output(12, GPIO.LOW)
def setupSERVO():
global pwm
P_SERVO = 18 # GPIO端口号,根据实际修改
fPWM = 50 # Hz (软件PWM方式,频率不能设置过高)
GPIO.setup(P_SERVO, GPIO.OUT)
pwm = GPIO.PWM(P_SERVO, fPWM)
pwm.start(0)
def setDirection(direction):
global pwm
duty = 10 / 180 * direction + 2
pwm.ChangeDutyCycle(duty)
print("direction =", direction, "-> duty =", duty)
time.sleep(1) #等待控制周期结束
pwm.ChangeDutyCycle(0) #清空占空比,这句是防抖关键句,如果没有这句,舵机会狂抖不止
def waitForInput():
while True:
try:
val = input("输入数值来改变舵机的转向(0~180): ").strip()
if val:
val = int(val)
if 0 <= val <= 180:
setDirection(val)
except Exception as e:
print("waitForInput: ", e)
from threading import Thread
if __name__ == '__main__':
GpioInit()
setupSERVO()
setDirection(90)
try:
th = Thread(target=waitForInput)
th.setDaemon(True)
th.start()
faces_video()
except Exception as e:
print("main: ", e)
GPIO.output(26, GPIO.LOW) #LED
GPIO.output(12, GPIO.LOW) # BEEP
setDirection(90)
GPIO.cleanup()
4、运行代码!