前面幾篇文章完成了訓練端和部署端的環境搭建以及模型的訓練,並經過兩次模型轉化最終將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倒是可以實現,但可能實時性就沒有那么高了。