[项目]行空板——安防 精华

4372浏览
查看: 4372|回复: 3

[项目] 行空板——安防

[复制链接]
本帖最后由 云天 于 2022-9-20 12:06 编辑

行空板——安防图1

【项目背景】
现在很多家庭都安装有监控,并可以利用手机进行查看。方便自己不在家时,查看家中情况,及时发现老人幼儿发生的危险情况。同时安装监控好处是可以全天候和多方位的进行监视,节省人力物力,实时监控录像,可以随时调出记录,方便对不法活动进行举报,起到震慑作用等等。
【项目设计】
行空板——安防图2

本项目使用“行空板”结合USB摄像头,利用Mind+Python模式下编程,使用Easy IOT物联网平台,向手机发送实时图像。手机端使用App Inventor2编程,连接物联网,实时查看图像,并发送指令控制摄像头旋转、点亮彩灯等。
行空板——安防图3


行空板——安防图4

【演示视频】

【硬件结构】
供电使用两个电池座,一个四节锂电池(输出5V 3A)给行空板供电,一个二节锂电池给扩展板供电,支持舵机(接S1引脚)和彩灯(接P16引脚)。
行空板——安防图5


行空板——安防图6


行空板——安防图7

【程序设计——App Inventor2】
使用了MQTT物联网控件,配置Easy IOT相应参数。
行空板——安防图8


行空板——安防图9

【程序设计——Mind+Python】
可在Mind+Python模式下加载以下扩展,协助完成以下代码编写。
行空板——安防图10

【传送图像】
实现行空板向物联网平台发送base64编码后的图像。(行空板要连接Wifi)
  1. import base64
  2. import siot
  3. import time
  4. import cv2
  5. siot.init(client_id="",server="iot.dfrobot.com.cn",port=1883,user="X8jykxFnR",password="u8jskbFngz")
  6. siot.connect()
  7. siot.loop()
  8. siot.getsubscribe(topic="jBarN574g")
  9. siot.set_callback(on_message_callback)
  10. vd = cv2.VideoCapture()
  11. vd.open(0)
  12. while True:
  13.         ret, img = vd.read()
  14.         if ret:
  15.           img=cv2.resize(img,(400,300))
  16.           img=cv2.imencode('.jpg',img)[1]
  17.           image_code=str(base64.b64encode(img))[2:-1]
  18.           siot.publish(topic="tLm2XCm4R", data=image_code)
  19.           time.sleep(0.04)
复制代码
【查看方式】
实现“流畅查看”、“间隔查看”、“点击查看”三种查看方式,是为适应网络传输环境,Easy Iot物联网平台响应速度及信息量1万条的限制。但“间隔查看”、“点击查看”会因read()读出缓存问题,而可能看不到实时图像。解决方法见最后。
  1. #  -*- coding: UTF-8 -*-
  2. # MindPlus
  3. # Python
  4. import base64
  5. import siot
  6. import time
  7. import cv2
  8. # 事件回调函数
  9. def on_message_callback(client, userdata, msg):
  10.     global bs
  11.     if (msg.payload.decode() == '1'):
  12.         
  13.         bs=1
  14.     elif  (msg.payload.decode() == '2'):
  15.         bs=2
  16.     elif  (msg.payload.decode() == '3'):
  17.         bs=3
  18. siot.init(client_id="",server="iot.dfrobot.com.cn",port=1883,user="X8jykxFnR",password="u8jskbFngz")
  19. siot.connect()
  20. siot.loop()
  21. siot.getsubscribe(topic="jBarN574g")
  22. siot.set_callback(on_message_callback)
  23. vd = cv2.VideoCapture()
  24. vd.open(0)
  25. time1=1
  26. bs=0
  27. currtime1=time.time()
  28. while not (vd.isOpened()):
  29.     pass
  30. def getimg():
  31.     ret, img = vd.read()
  32.     if ret:
  33.         img=cv2.resize(img,(400,300))
  34.         img=cv2.imencode('.jpg',img)[1]
  35.         image_code=str(base64.b64encode(img))[2:-1]
  36.         siot.publish(topic="tLm2XCm4R", data=image_code)
  37. while True:
  38.     if bs==1:
  39.            time1=0.04
  40.            if time.time()-currtime1>time1:
  41.                currtime1=time.time()
  42.                getimg()
  43.     elif bs==2:
  44.            time1=1
  45.            if time.time()-currtime1>time1:
  46.                currtime1=time.time()
  47.                getimg()
  48.     elif bs==3:
  49.            bs=0
  50.            getimg()
  51.         
复制代码
【传送信息】
修改程序,接收指令加信息,转成列表进行处理,以增加接收舵机角度信息。
  1. #  -*- coding: UTF-8 -*-
  2. # MindPlus
  3. # Python
  4. import base64
  5. import siot
  6. import time
  7. import cv2
  8. # 事件回调函数
  9. def on_message_callback(client, userdata, msg):
  10.     global bs,angle
  11.     message=msg.payload.decode()
  12.     message=message.split(",")
  13.     if message[0] == '1':
  14.         
  15.         bs=1
  16.     elif  message[0] == '2':
  17.         print(message[0])
  18.         bs=2
  19.     elif  message[0] == '3':
  20.         bs=3
  21.     elif  message[0] == '4':
  22.         bs=4
  23.         angle=int(message[1])
  24. siot.init(client_id="",server="iot.dfrobot.com.cn",port=1883,user="X8jykxFnR",password="u8jskbFngz")
  25. siot.connect()
  26. siot.loop()
  27. siot.getsubscribe(topic="jBarN574g")
  28. siot.set_callback(on_message_callback)
  29. vd = cv2.VideoCapture()
  30. vd.open(0)
  31. time1=1
  32. bs=0
  33. angle=90
  34. currtime1=time.time()
  35. while not (vd.isOpened()):
  36.     pass
  37. def getimg():
  38.     ret, img = vd.read()
  39.     if ret:
  40.         img=cv2.resize(img,(400,300))
  41.         img=cv2.imencode('.jpg',img)[1]
  42.         image_code=str(base64.b64encode(img))[2:-1]
  43.         siot.publish(topic="tLm2XCm4R", data=image_code)
  44. while True:
  45.     if bs==1:
  46.            time1=0.04
  47.            if time.time()-currtime1>time1:
  48.                currtime1=time.time()
  49.                getimg()
  50.     elif bs==2:
  51.            time1=1
  52.            if time.time()-currtime1>time1:
  53.                currtime1=time.time()
  54.                getimg()
  55.     elif bs==3:
  56.            bs=0
  57.            getimg()
  58.     elif bs==4:
  59.         print(angle)
  60.         
复制代码
【摄像控制】
摄像头固定在舵机上,舵机连接在扩展板的S1引脚上,实现远程控制摄像头旋转。且增加行空板提示显示。
  1. #  -*- coding: UTF-8 -*-
  2. # MindPlus
  3. # Python
  4. import base64
  5. import siot
  6. import time
  7. import cv2
  8. from pinpong.board import Board
  9. from microbit_motor import DFServo
  10. from unihiker import GUI
  11. # 事件回调函数
  12. def on_message_callback(client, userdata, msg):
  13.     global bs,angle
  14.     message=msg.payload.decode()
  15.     message=message.split(",")
  16.     if message[0] == '1':
  17.         
  18.         bs=1
  19.     elif  message[0] == '2':
  20.         
  21.         bs=2
  22.     elif  message[0] == '3':
  23.         bs=3
  24.     elif  message[0] == '4':
  25.         bs=4
  26.         angle=int(message[1])
  27.     elif  message[0] == '5':
  28.         bs=5
  29. siot.init(client_id="",server="iot.dfrobot.com.cn",port=1883,user="X8jykxFnR",password="u8jskbFngz")
  30. siot.connect()
  31. siot.loop()
  32. siot.getsubscribe(topic="jBarN574g")
  33. siot.set_callback(on_message_callback)
  34. vd = cv2.VideoCapture()
  35. vd.open(0)
  36. time1=1
  37. bs=0
  38. bs1=0
  39. bs2=0
  40. bs3=0
  41. angle=6
  42. angle_old=0
  43. step=5
  44. currtime1=time.time()
  45. while not (vd.isOpened()):
  46.     pass
  47. def getimg():
  48.     ret, img = vd.read()
  49.     if ret:
  50.         img=cv2.resize(img,(400,300))
  51.         img=cv2.imencode('.jpg',img)[1]
  52.         image_code=str(base64.b64encode(img))[2:-1]
  53.         siot.publish(topic="tLm2XCm4R", data=image_code)
  54. Board().begin()
  55. S=DFServo(1)
  56. u_gui=GUI()
  57. pm=u_gui.draw_text(text="行空板",x=20,y=120,font_size=50, color="#0000FF")
  58. while True:
  59.     if bs==1:
  60.         if bs2==0:
  61.            pm.config(text="实时景")
  62.            bs2=1
  63.            bs1=0
  64.            bs3=0
  65.            time1=0.04
  66.         if time.time()-currtime1>time1:
  67.                currtime1=time.time()
  68.                getimg()
  69.     elif bs==2:
  70.         if bs3==0:
  71.            pm.config(text="间隔景")
  72.            bs3=1
  73.            bs1=0
  74.            bs2=0
  75.            time1=1
  76.         if time.time()-currtime1>time1:
  77.                currtime1=time.time()
  78.                getimg()
  79.     elif bs==3:
  80.            pm.config(text="定格景")
  81.            bs=0
  82.            bs1=0
  83.            bs2=0
  84.            bs3=0
  85.            getimg()
  86.     elif bs==4:
  87.        if angle!=angle_old:
  88.          pm.config(text="转定角")
  89.          angle_old=angle
  90.          S.angle(angle)
  91.          time.sleep(1)
  92.          time1=0.04
  93.          bs1=0
  94.          bs2=0
  95.          bs3=0
  96.        if time.time()-currtime1>time1:
  97.                currtime1=time.time()
  98.                getimg()
  99.     elif bs==5:
  100.         if bs1==0:
  101.            pm.config(text="巡航转")
  102.            bs1=1
  103.            bs2=0
  104.            bs3=0
  105.         if angle>174:
  106.            step=-5   
  107.         elif angle<6:
  108.            step=5
  109.         angle=angle+step
  110.         S.angle(angle)
  111.         time.sleep(1)
  112.         getimg()
  113.         
复制代码
【点亮彩灯】
使用四个RGB LED模块串联接在扩展板P16引脚上。

  1. #  -*- coding: UTF-8 -*-
  2. # MindPlus
  3. # Python
  4. import base64
  5. import siot
  6. import time
  7. import cv2
  8. from pinpong.board import Board,NeoPixel,Pin
  9. from microbit_motor import DFServo
  10. from unihiker import GUI
  11. NEOPIXEL_PIN = Pin.P16
  12. PIXELS_NUM = 4 #灯数
  13. # 事件回调函数
  14. def on_message_callback(client, userdata, msg):
  15.     global bs,angle
  16.     message=msg.payload.decode()
  17.     message=message.split(",")
  18.     np.clear()
  19.     if message[0] == '1':
  20.         
  21.         bs=1
  22.     elif  message[0] == '2':
  23.         
  24.         bs=2
  25.     elif  message[0] == '3':
  26.         bs=3
  27.     elif  message[0] == '4':
  28.         bs=4
  29.         angle=int(message[1])
  30.     elif  message[0] == '5':
  31.         bs=5
  32.     elif  message[0] == '6':
  33.         bs=6   
  34. siot.init(client_id="",server="iot.dfrobot.com.cn",port=1883,user="X8jykxFnR",password="u8jskbFngz")
  35. siot.connect()
  36. siot.loop()
  37. siot.getsubscribe(topic="jBarN574g")
  38. siot.set_callback(on_message_callback)
  39. vd = cv2.VideoCapture()
  40. vd.open(0)
  41. time1=1
  42. bs=0
  43. bs1=0
  44. bs2=0
  45. bs3=0
  46. bs4=0
  47. angle=6
  48. angle_old=0
  49. step=5
  50. currtime1=time.time()
  51. while not (vd.isOpened()):
  52.     pass
  53. def getimg():
  54.     ret, img = vd.read()
  55.     if ret:
  56.         img=cv2.resize(img,(400,300))
  57.         img=cv2.imencode('.jpg',img)[1]
  58.         image_code=str(base64.b64encode(img))[2:-1]
  59.         siot.publish(topic="tLm2XCm4R", data=image_code)
  60. Board().begin()
  61. S=DFServo(1)
  62. u_gui=GUI()
  63. np = NeoPixel(Pin(NEOPIXEL_PIN), PIXELS_NUM)
  64. pm=u_gui.draw_text(text="行空板",x=20,y=120,font_size=50, color="#0000FF")
  65. while True:
  66.     if bs==1:
  67.         if bs2==0:
  68.            pm.config(text="实时景")
  69.            bs2=1
  70.            bs1=0
  71.            bs3=0
  72.            bs4=0
  73.            time1=0.04
  74.         if time.time()-currtime1>time1:
  75.                currtime1=time.time()
  76.                getimg()
  77.     elif bs==2:
  78.         if bs3==0:
  79.            pm.config(text="间隔景")
  80.            bs3=1
  81.            bs1=0
  82.            bs2=0
  83.            bs4=0
  84.            time1=1
  85.         if time.time()-currtime1>time1:
  86.                currtime1=time.time()
  87.                getimg()
  88.     elif bs==3:
  89.            pm.config(text="定格景")
  90.            bs=0
  91.            bs1=0
  92.            bs2=0
  93.            bs3=0
  94.            bs4=0
  95.            getimg()
  96.     elif bs==4:
  97.        if angle!=angle_old:
  98.          pm.config(text="转定角")
  99.          angle_old=angle
  100.          S.angle(angle)
  101.          time.sleep(1)
  102.          time1=0.04
  103.          bs1=0
  104.          bs2=0
  105.          bs3=0
  106.          bs4=0
  107.        if time.time()-currtime1>time1:
  108.                currtime1=time.time()
  109.                getimg()
  110.     elif bs==5:
  111.         if bs1==0:
  112.            pm.config(text="巡航转")
  113.            bs1=1
  114.            bs2=0
  115.            bs3=0
  116.            bs4=0
  117.         if angle>174:
  118.            step=-5   
  119.         elif angle<6:
  120.            step=5
  121.         angle=angle+step
  122.         S.angle(angle)
  123.         time.sleep(1)
  124.         getimg()
  125.     elif bs==6:
  126.         if bs4==0:
  127.            np.rainbow(0,3,0,0x0022FF)
  128.            pm.config(text="亮彩灯")
  129.            bs4=1
  130.            bs1=0
  131.            bs2=0
  132.            bs3=0
  133.         for i in range(3):
  134.            np.rotate(1)
  135.            time.sleep(0.2)
复制代码

【解决问题】
使用Opencv读取实时视频流数据,做算法处理,因为算法本身处理速度有限,因此会产生每次读取到的帧不是当前帧的问题,体验很差。cv2.VideoCapture 的 read 函数并不能获取实时流的最新帧而是按照内部缓冲区中顺序逐帧的读取,opencv会每过一段时间清空一次缓冲区,但是清空的时机并不是我们能够控制的,因此如果对视频帧的处理速度如果跟不上接受速度,那么每过一段时间,在播放时(imshow)时会看到画面突然花屏,甚至程序直接崩溃,在网上查了很多资料,处理方式基本是一个思想
生产者消费者模式:
        使用一个临时缓存,可以是一个变量保存最新一帧,也可以是一个队列保存一些帧,然后开启一个线程读取最新帧保存到缓存里,用户读取的时候只返回最新的一帧


  1. import cv2
  2. import queue
  3. import threading
  4. # 无缓存读取视频流类
  5. class VideoCapture:
  6.   def __init__(self, name):
  7.     self.cap = cv2.VideoCapture(name)
  8.     self.q = queue.Queue()
  9.     t = threading.Thread(target=self._reader)
  10.     t.daemon = True
  11.     t.start()
  12.   # 帧可用时立即读取帧,只保留最新的帧
  13.   def _reader(self):
  14.     while True:
  15.       ret, frame = self.cap.read()
  16.       if not ret:
  17.         break
  18.       if not self.q.empty():
  19.         try:
  20.           self.q.get_nowait()   # 删除上一个(未处理的)帧
  21.         except queue.Empty:
  22.           pass
  23.       self.q.put(frame)
  24.   def read(self):
  25.     return self.q.get()
  26. cap = VideoCapture("rtsp://....")
  27. while True:
  28.   frame = cap.read()
  29.   cv2.imshow("frame", frame)
  30.   if chr(cv2.waitKey(1)&255) == 'q':
  31.     break
复制代码







白凡  高级技师

发表于 2022-9-20 15:35:51

学习学习!
回复

使用道具 举报

JOVI  中级技师 来自手机

发表于 2023-11-29 04:20:28

学习
回复

使用道具 举报

许培享  中级技神

发表于 2023-12-7 08:36:47

好样的,学学习习
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail