前面几篇文章完成了训练端和部署端的环境搭建以及模型的训练,并经过两次模型转化最终将YOLOv3 TINY模型部署在了树莓派上。其实最核心的内容已经完成了,接下来就是一些应用层面的东西了。
树莓派控制马达:
1. 材料硬件:
1.树莓派3B+
2.四个直流电机
3.一个小车底盘+四个车轮(某宝上有卖)
4.L298N驱动模块(介于树莓派与马达之间的桥梁)
5.充电宝一个(用于给树莓派供电)
6.18650锂电池两节(给小车马达供电,普通干电池真的不能用,不然你会拥有好多废电池)
7.杜邦线公对公、母对母、公对母各40条
8.面包板(可选)
9.蜂鸣器
2.线路连接:
图片是用fritzing这个软件画的,也是今天第一次用,画的有点丑,凑合看吧。我没有找到L298N这个模块,就用图中红色的这个代替一下吧。
我的马达控制逻辑比较简单,小车左右两侧的马达为一组同时控制,小车左边两个马达正负极分别连在out1、out2接口上,右边两个马达正负极分别连在out3、out4上,通过给out1和out2,out3和out4输出相反的电平实现马达的转动,采用BOARD编码格式,使用35、33、31、29四个GPIO接口分别连接到L298N驱动模块上的in1、in2、in3、in4接口,同时将32、36、38、40分别连接到四个使能端接口,通过python编程设置gpio接口输出高电平和低电平实现相应的控制,蜂鸣器连接到gpio的11号端口上。
3.小车控制与视频直播流web程序:
web程序采用的是基于python的flask框架,便于实现流媒体直播。同时前台的按钮可以将前进后退转弯信号传回后台,并在后台解析后调用相关的控制程序实现小车的前进后退。
# -*- coding:utf-8 -*-
from flask import Flask, render_template, Response,request
import cv2
import os,time
import RPi.GPIO as GPIO
from flask import jsonify
import sys
class Car(object):
def __init__(self):
self.enab_pin = [38, 40, 32, 36]
self.inx_pin = [35, 33, 31, 29] # 1leftahead 2left down 3 right ahead 4 right down
self.RightAhead_pin = self.inx_pin[2]
self.RightBack_pin = self.inx_pin[3]
self.LeftAhead_pin = self.inx_pin[0]
self.LeftBack_pin = self.inx_pin[1]
self.setup()
def setup(self):
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)
for pin in self.enab_pin:
GPIO.setup(pin, GPIO.OUT)
GPIO.output(pin, GPIO.HIGH)
pin = None
for pin in self.inx_pin:
GPIO.setup(pin, GPIO.OUT)
GPIO.output(pin, GPIO.LOW)
def front(self):
self.setup()
GPIO.output(self.RightAhead_pin, GPIO.HIGH)
GPIO.output(self.LeftAhead_pin, GPIO.HIGH)
def rear(self):
self.setup()
GPIO.output(self.RightBack_pin, GPIO.HIGH)
GPIO.output(self.LeftBack_pin, GPIO.HIGH)
def right(self):
self.setup()
GPIO.output(self.RightAhead_pin, GPIO.HIGH)
def left(self):
self.setup()
GPIO.output(self.LeftAhead_pin, GPIO.HIGH)
def stop(self):
for pin in self.inx_pin:
GPIO.output(pin, GPIO.LOW)
def clear(self):
GPIO.cleanup()
def main(status):
car = Car()
if status == 'front':
car.front()
if status == 'rear':
car.rear()
if status == 'right':
car.right()
if status == 'left':
car.left()
if status == 'stop':
car.stop()
class VideoCamera(object):
def __init__(self):
self.video = cv2.VideoCapture(0)
def get_frame(self):
success, image = self.video.read()
ret, jpeg = cv2.imencode('.jpg', image)
return jpeg.tobytes()
def __del__(self):
self.video.release()
print('cam is closed...')
app = Flask(__name__)
''
@app.route('/') # 主页
def index():
# jinja2模板,具体格式保存在index.html文件中
return render_template('index.html')
@app.route('/operation')
def operation():
return render_template('operation.html')
def gen(camera):
while True:
frame = camera.get_frame()
if(frame !=None):
yield (b'--frame\r\n'b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
@app.route('/video_feed') # 这个地址返回视频流响应
def video_feed():
# os.system('python3 test_tiny_yolo.py')
return Response(gen(VideoCamera()),
mimetype='multipart/x-mixed-replace; boundary=frame')
@app.route('/cmd',endpoint='cmd',methods=['GET', 'POST'])
def getjson():
a = request.args.get('mydata')
print('收到请求:'+a)
main(a)
return jsonify('success')
if __name__ == '__main__':
app.run(host='0.0.0.0', port =5000,debug=True, threaded=True)
print("ok")
实现效果:
{此处插入视频}
微信报警程序:
1.安装wxpy:
查看官方网站:https://wxpy.readthedocs.io/zh/latest/
2.监控端程序:
我们需要的功能很简单:
在离开家门之前在树莓派上登陆一个微信--》当有不明入侵人员进入小车的视线范围时被检测到--》给另一个微信好友发送检测到的人体图片以及检测到的人数和检测时间--》收到信息后由微信好友回复"Y/N"来决定是否触发蜂鸣器来发出警报。
只需要在实时检测的代码中插入图片保存和记录时间人数的代码段即可:
WEBIMG = cv2.resize(color_image, (width, height))
cv2.imshow(window_name, WEBIMG)
cv2.imwrite('image1.jpeg', WEBIMG)
if(flag == True):
now = int(time.time())
if(iffirst or (now - lastsendtime) >= 20): #为了演示方便,这里设置触发时间间隔为20s
iffirst = False
filename = 'flag.txt'
with open(filename,'w') as f: # 如果filename不存在会自动创建, 'w'表示写数据,写之前会清空文件中的原有数据!
f.write(str(now))
f.write('\n')
f.write(str(count))
f.write('\n')
lastsendtime = now
cv2.imwrite('person.jpeg', WEBIMG)
在监控工作时只有当检测到人体时才执行图片保存任务和flag文件的写入工作,并且只有和上次保存时间相隔超过20s时才会进行更新,这很大程序避免了在一段时间内频繁发送图片的情况。
3.微信发送端程序:
监控端在不断的写图片更新flag,同时微信端也不断的读取flag来判断是否有新的检测情况,如果有则发送检测到的图片和时间人数信息给指定的微信好友。
# 导入模块
from wxpy import*
import datetime
import RPi.GPIO as GPIO
import sys
import time
def alarm():
fengming = 11
GPIO.setmode(GPIO.BOARD)
GPIO.setup(fengming, GPIO.OUT)
GPIO.output(fengming, GPIO.HIGH)
time.sleep(5)
GPIO.cleanup()
# 初始化机器人,扫码登陆
bot = Bot()
my_friend = bot.friends().search('可以的')[0]
flag = 0
lastsendtime = None
@bot.register()
def print_others(msg):
m = msg.text
print(m)
if(("y" in m) or ("Y" in m)):
print(m)
alarm()
while True:
with open('flag.txt') as f: # 默认模式为‘r’,只读模式
lastsend = f.readline()
if(lastsend==''):
continue
count = f.readline().strip()
if((lastsendtime == None )or (lastsend !=lastsendtime)):
lastsendtime = lastsend
lastsend_trans=time.localtime(int(lastsend))
lastsend_time=time.strftime('%Y-%m-%d %H:%M:%S',lastsend_trans)
# 发送图片
time.sleep(3)
my_friend.send_image('/home/pi/OpenVINO-YoloV3-master/person.jpeg')
my_friend.send("时间: "+lastsend_time+"\n检测到"+count +"个人进入房间。。。")
my_f
riend.send("是否开启警报?(回复y/n)")
embed()
实现的效果:
后来想了个问题就是是否可以给熟人加个白名单呢,这个仅靠目标检测是实现不了,需要进行人脸比对,利用一些云端的API倒是可以实现,但可能实时性就没有那么高了。