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

[项目] 【智控万物】掌控监视器

[复制链接]
【智控万物】掌控监视器图9


【项目背景】受到了“yywudao”的“[入门教程][2020]掌控板显示图片(三)-- 进阶版处理图片及显示动画”的启发,作者用掌控板播放了“Bad apple”。我也重现了此显示。

【智控万物】掌控监视器图1



顺着作者的想法,既然能播放动画,那应该也有播放视频流,下面是演示视频。
【智控万物】掌控监视器图16




【项目设计】


前期工作请参考:https://mc.dfrobot.com.cn/thread-302527-1-1.html

【准备工作】

电脑要安装:
1、python3(Python3 教程 | 菜鸟教程)
2、cv2(pip3 install --user opencv-python)
3、numpy(pip install --user numpy,我的之前安装过,出了问题,解决方法:先pip uninstall numpy,确保完全卸载numpy,再pip install --user numpy

【电脑端】

1、Python获取摄像头图像


注意Python采用代码缩进和冒号( : )来区分代码块之间的层次。

  1. #pip3 install --user opencv-python
  2. #先pip uninstall numpy,确保完全卸载numpy,再pip install --user numpy
  3. def main():
  4. import cv2
  5. import numpy as np
  6. import socket
  7. import time
  8. import binascii
  9. cap = cv2.VideoCapture(0)
  10. while(1):    # get a frame and show   
  11.     ret, frame = cap.read()
  12.     if(ret):
  13.         cv2.imshow('Capture', frame)
复制代码

【智控万物】掌控监视器图2


2、图像灰度处理:

  1. <font face="微软雅黑"><blockquote>def main():</font>
复制代码



【智控万物】掌控监视器图3


3、图片黑白二值化处理
  1. def main():
  2. import cv2
  3. import numpy as np
  4. import socket
  5. import time
  6. import binascii
  7. cap = cv2.VideoCapture(0)
  8. while(1): # get a frame and show
  9.     ret, frame = cap.read()
  10.     if(ret):
  11.         gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
  12.         BIN= cv2.adaptiveThreshold(gray,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,11,2)
  13.         cv2.imshow('Capture1', frame)
  14.         cv2.imshow('Capture2', BIN)
  15.         if cv2.waitKey(1) & 0xFF == ord('q'):
  16.             break
  17. cv2.destroyAllWindows()
  18. if __name__=='__main__':
  19.     main()
复制代码
【智控万物】掌控监视器图4


void adaptiveThreshold(InputArray src, OutputArray dst, double maxValue,int adaptiveMethod, int thresholdType, int blockSize, double C)
这种办法就是自适应阈值法(adaptiveThreshold),它的思想不是计算全局图像的阈值,而是根据图像不同区域亮度分布,计算其局部阈值,所以对于图像不同区域,能够自适应计算不同的阈值,因此被称为自适应阈值法。(其实就是局部阈值法)

说明下各参数:

InputArray src:源图像

OutputArray dst:输出图像,与源图像大小一致

int adaptiveMethod:在一个邻域内计算阈值所采用的算法,有两个取值,分别为 ADAPTIVE_THRESH_MEAN_C 和 ADAPTIVE_THRESH_GAUSSIAN_C 。

ADAPTIVE_THRESH_MEAN_C的计算方法是计算出领域的平均值再减去第七个参数double C的值。

ADAPTIVE_THRESH_GAUSSIAN_C的计算方法是计算出领域的高斯均值再减去第七个参数double C的值。

int thresholdType:这是阈值类型,只有两个取值,分别为 THRESH_BINARY 和THRESH_BINARY_INV  具体的请看官方的说明,这里不多做解释。

int blockSize:adaptiveThreshold的计算单位是像素的邻域块,这是局部邻域大小,3、5、7等。

double C:这个参数实际上是一个偏移值调整量,用均值和高斯计算阈值后,再减或加这个值就是最终阈值。


可自行调整相应参数:
【智控万物】掌控监视器图5

【智控万物】掌控监视器图6

【数据处理】

1、图像压缩
压缩为128*64(掌控板oled屏幕分辨率)


  1. <font face="微软雅黑">def main():
  2. import cv2
  3. import numpy as np
  4. import socket
  5. import time
  6. import binascii
  7. cap = cv2.VideoCapture(0)
  8. W=128
  9. H=64
  10. size = (W,H)
  11. while(1): # get a frame and show
  12.     ret, frame = cap.read()
  13.     if(ret):
  14.         frame = cv2.resize(frame, size)
  15.         gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
  16.         BIN= cv2.adaptiveThreshold(gray,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,25,5)
  17.         cv2.imshow('Capture1', frame)
  18.         cv2.imshow('Capture2', BIN)
  19.         if cv2.waitKey(1) & 0xFF == ord('q'):
  20.             break
  21. cv2.destroyAllWindows()
  22. if __name__=='__main__':
  23.     main()</font>
复制代码
【智控万物】掌控监视器图7



2、查看二值化后的数据:

  1. def main():
  2. import cv2
  3. import numpy as np
  4. import socket
  5. import time
  6. import binascii
  7. cap = cv2.VideoCapture(0)
  8. W=128
  9. H=64
  10. size = (W,H)
  11. while(1): # get a frame and show
  12.     ret, frame = cap.read()
  13.     if(ret):
  14.         frame = cv2.resize(frame, size)
  15.         gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
  16.         BIN= cv2.adaptiveThreshold(gray,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,25,5)
  17.         cv2.imshow('Capture1', frame)
  18.         cv2.imshow('Capture2', BIN)
  19.         for h in range(H):
  20.             for w in range(W):
  21.                     print(BIN[h][w],end="")
  22.             print()
  23.         #if cv2.waitKey(1) & 0xFF == ord('q'):
  24.         break
  25. cv2.destroyAllWindows()
  26. if __name__=='__main__':
  27.     main()
复制代码

【智控万物】掌控监视器图8



从上图看出,大于阈值的都显示为“255”,但“255”不是我想要的,我要的是“1”。

修改下面的代码,大于阈值的输出为“1”。


BIN= cv2.adaptiveThreshold(gray,1,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,25,5)

但这样,窗口就无法显示图像了。“
1”相对“255”接近于“0”,窗口显示为全黑。所以将图像拷贝一份用来窗口显示,另一份用来进行数据处理。

  1. <font face="微软雅黑">def main():
  2. import cv2
  3. import numpy as np
  4. import socket
  5. import time
  6. import binascii
  7. cap = cv2.VideoCapture(0)
  8. W=128
  9. H=64
  10. size = (W,H)
  11. while(1): # get a frame and show
  12.     ret, frame1 = cap.read()
  13.     if(ret):
  14.         frame2=frame1.copy()
  15.         frame1 = cv2.resize(frame1, size)
  16.         gray1 = cv2.cvtColor(frame1, cv2.COLOR_BGR2GRAY)
  17.         gray2 = cv2.cvtColor(frame2, cv2.COLOR_BGR2GRAY)
  18.         BIN1= cv2.adaptiveThreshold(gray1,1,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,7,3)
  19.         BIN2= cv2.adaptiveThreshold(gray2,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,7,3)
  20.         cv2.imshow('Capture1', frame2)
  21.         cv2.imshow('Capture2', BIN2)
  22.         for h in range(H):
  23.             for w in range(W):
  24.               print(BIN1[h][w],end="")
  25.             print()
  26.         #if cv2.waitKey(1) & 0xFF == ord('q'):
  27.         break
  28. cv2.destroyAllWindows()
  29. if __name__=='__main__':
  30.     main()</font>
复制代码
【智控万物】掌控监视器图19
"0"和“1”展示自我

【分析数据】

掌控板能显示“pbm”图像文件,看一下Bad Apple“123.pbm”文件数据内容:
下载附件5帧badapple_pbm.zip


【智控万物】掌控监视器图10

发现它是以“十六进制”存储,每四位16进制数为一组。
需要把我的数据处理成它这种形式


  1. def main():
  2. import cv2
  3. import numpy as np
  4. import socket
  5. import time
  6. import binascii
  7. cap = cv2.VideoCapture(0)
  8. W=128
  9. H=64
  10. size = (W,H)
  11. val=0
  12. str1=''
  13. while(1): # get a frame and show
  14.     ret, frame1 = cap.read()
  15.     if(ret):
  16.         frame2=frame1.copy()
  17.         frame1 = cv2.resize(frame1, size)
  18.         gray1 = cv2.cvtColor(frame1, cv2.COLOR_BGR2GRAY)
  19.         gray2 = cv2.cvtColor(frame2, cv2.COLOR_BGR2GRAY)
  20.         BIN1= cv2.adaptiveThreshold(gray1,1,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,7,3)
  21.         BIN2= cv2.adaptiveThreshold(gray2,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,7,3)
  22.         cv2.imshow('Capture1', frame2)
  23.         cv2.imshow('Capture2', BIN2)
  24.         str1=""
  25.         for h in range(H):
  26.           for w in range(0,W,16):
  27.              for i in range(4):
  28.                   val=(int(BIN1[h][w+i*4+0])*8 + int(BIN1[h][w+i*4+1])*4 + int(BIN1[h][w+i*4+2])*2 + int(BIN1[h][w+i*4+3])*1)
  29.                   if val>=10:
  30.                     if val == 10:
  31.                       str1=str1+'A'
  32.                     if val==11:
  33.                       str1=str1+'B'
  34.                     if val==12:
  35.                       str1=str1+'C'
  36.                     if val==13:
  37.                       str1=str1+'D'
  38.                     if val==14:
  39.                       str1=str1+'E'
  40.                     if val==15:
  41.                       str1=str1+'F'
  42.                   else:
  43.                       str1=str1+str(val)
  44.              str1=str1+" "
  45.         print(str1)
  46.         '''for h in range(H):
  47.             for w in range(W):
  48.               print(BIN1[h][w],end="")
  49.             print()'''
  50.         #if cv2.waitKey(1) & 0xFF == ord('q'):
  51.         break
  52. cv2.destroyAllWindows()
  53. if __name__=='__main__':
  54.     main()
复制代码
【智控万物】掌控监视器图12

但这个字符串是不能发送给掌控板的,需要用bytearray.fromhex(str1)进行处理

【wifi传数据】

下面的是的传送“Bad Apple”pbm文件的电脑端程序,其中“192.168.31.93”,需要改成自己掌控板的IP,“pic\{}.pbm”,改成自己”pbm“文件所在的目录。

  1. import socket
  2. import time
  3. def main():
  4.   for i in range(1,1098):
  5.     s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  6.     s.connect(('<font color="#ff0000">192.168.31.93</font>',10000))
  7.     with open(r'<font color="#ff0000">pic\{}.pbm</font>'.format(i),'rb') as f:
  8.       #注意到需要用二次 f.readline() 把前二行的数据处理掉。
  9.       #数据内容如下:
  10.       #第一行:P4,即 PBM 二进制数据
  11.       #第三行:图像的像素为88*64
  12.       f.readline()
  13.       f.readline()
  14.       data=f.read()
  15.       s.send(data)
  16.     print(i)
  17.     time.sleep(0.19)
  18.     s.close()
  19. if __name__=='__main__':
  20.         main()
复制代码


【掌控板程序】

  1. from mpython import *
  2. import usocket
  3. import network
  4. my_wifi = wifi()
  5. my_wifi.connectWiFi('###', '##########')
  6. while not my_wifi.sta.isconnected():
  7.      pass
  8. oled.fill(0)
  9. oled.DispChar(my_wifi.sta.ifconfig()[0], 0, 0, 1)
  10. oled.show()
  11. #socket.socket() 创建了一个 socket 对象,并且支持 context manager type,你可以使用 with 语句,这样你就不用再手动调用 s.close() 来关闭 socket 了
  12. s=usocket.socket(usocket.AF_INET,usocket.SOCK_STREAM)
  13. #bind() 方法的入参取决于 socket 的地址族,在这个例子中我们使用了 socket.AF_INET (IPv4),它接收一个二元组(host, port)入参
  14. #端口号应该是 1-65535 之间的整数(0是保留的),这个整数就是用来接受客户端链接的 TCP 端口号,如果端口号小于 1024,有的操作系统会要求管理员权限
  15. s.bind((my_wifi.sta.ifconfig()[0],10000))
  16. #listen() 方法调用使服务器可以接受连接请求,这使它成为一个「监听中」的 socket
  17. #listen() 方法有一个 backlog 参数。它指定在拒绝新的连接之前系统将允许使用的 未接受的连接 数量。从 Python 3.5 开始,这是可选参数。如果不指定,Python 将取一个默认值
  18. s.listen(5)
  19. while True:
  20.       #accept() 方法阻塞并等待传入连接。当一个客户端连接时,它将返回一个新的 socket 对象,对象中有表示当前连接的 conn 和一个由主机、端口号组成的 IPv4/v6 连接的元组
  21.       con=s.accept()[0]
  22.       data=con.recv(1024)
  23.       #framebuf.FrameBuffer(buffer, width, height, format) 可以构建帧缓存对象, buffer 为缓存区数据,width 为图片宽度,height 为图片高度,format 为FrameBuffer的格式,即对应图片取模时数据输出的扫描模式:framebuf.MONO_HLSB 为水平方向;framebuf.MONO_VLSB 为垂直方向。
  24.       fbuf=framebuf.FrameBuffer(bytearray(data),88,64,framebuf.MONO_HLSB)
  25.       oled.fill(0)
  26.       #oled.blit(fbuf, x, y) 使用OLED显示图片帧,fbuf 为FrameBuffer对象,x 、y 为起始点的坐标x、y。
  27.       oled.blit(fbuf,19,0)
  28.       oled.show()
  29.       con.close()
复制代码

88”是“Bad Apple”的,接收实时视频流时要改成“128”,“19”改成“0”。


【智控万物】掌控监视器图13


在Mind+中,扩展选择掌控板,右上角选择MicroPython,手动编辑。


【智控万物】掌控监视器图14
也可使用mPython

【实时视频流显示完整代码】


电脑端

结合传送“Bad Apple”pbm文件的程序,完成实时视频流传送。

  1. <font face="微软雅黑">def main():
  2. import cv2
  3. import numpy as np
  4. import socket
  5. import time
  6. import binascii
  7. import socket
  8. import time
  9. cap = cv2.VideoCapture(0)
  10. W=128
  11. H=64
  12. size = (W,H)
  13. val=0
  14. str1=''
  15. while(1): # get a frame and show
  16.     ret, frame1 = cap.read()
  17.     if(ret):
  18.         frame2=frame1.copy()
  19.         frame1 = cv2.resize(frame1, size)
  20.         gray1 = cv2.cvtColor(frame1, cv2.COLOR_BGR2GRAY)
  21.         gray2 = cv2.cvtColor(frame2, cv2.COLOR_BGR2GRAY)
  22.         BIN1= cv2.adaptiveThreshold(gray1,1,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,7,3)
  23.         BIN2= cv2.adaptiveThreshold(gray2,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,7,3)
  24.         cv2.imshow('Capture1', frame2)
  25.         cv2.imshow('Capture2', BIN2)
  26.         str1=""
  27.         for h in range(H):
  28.           for w in range(0,W,16):
  29.              for i in range(4):
  30.                   val=(int(BIN1[h][w+i*4+0])*8 + int(BIN1[h][w+i*4+1])*4 + int(BIN1[h][w+i*4+2])*2 + int(BIN1[h][w+i*4+3])*1)
  31.                   if val>=10:
  32.                     if val == 10:
  33.                       str1=str1+'A'
  34.                     if val==11:
  35.                       str1=str1+'B'
  36.                     if val==12:
  37.                       str1=str1+'C'
  38.                     if val==13:
  39.                       str1=str1+'D'
  40.                     if val==14:
  41.                       str1=str1+'E'
  42.                     if val==15:
  43.                       str1=str1+'F'
  44.                   else:
  45.                       str1=str1+str(val)
  46.              str1=str1+" "
  47.         #print(str1)
  48.         s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  49.         s.connect(('192.168.31.93',10000))
  50.         s.send(bytearray.fromhex(str1))
  51.         time.sleep(0.19)
  52.         if cv2.waitKey(1) & 0xFF == ord('q'):
  53.          break
  54. cv2.destroyAllWindows()
  55. if __name__=='__main__':
  56.     main()</font>
复制代码


【源文件】
这里使用代码格式,总是去掉我的缩进空格,Python采用代码缩进和冒号( : )来区分代码块之间的层次。所以附上源文件,我很厚道。
下载附件掌控监视器.zip

直播协议

一、RTMP、RTSP、HTTP协议
这三个协议都属于互联网 TCP/IP 五层体系结构中应用层的协议。理论上这三种都可以用来做视频直播或点播。但通常来说,直播一般用 RTMP、RTSP。而点播用 HTTP。下面分别介绍下三者的特点。

1,RTMP协议
(1)是流媒体协议。
(2)RTMP协议是 Adobe 的私有协议,未完全公开。
(3)RTMP协议一般传输的是 flv,f4v 格式流。
(4)RTMP一般在 TCP 1个通道上传输命令和数据。

2,RTSP协议
(1)是流媒体协议。
(2)RTSP协议是共有协议,并有专门机构做维护。.
(3)RTSP协议一般传输的是 ts、mp4 格式的流。
(4)RTSP传输一般需要 2-3 个通道,命令和数据通道分离。

3,HTTP协议
(1)不是是流媒体协议。
(2)HTTP协议是共有协议,并有专门机构做维护。 (3)HTTP协议没有特定的传输流。
(4)HTTP传输一般需要 2-3 个通道,命令和数据通道分离。

二、传送RTMP视频流


rtmp://58.200.131.2:1935/livetv/cctv1    cctv1综合   

rtmp://58.200.131.2:1935/livetv/cctv2    cctv2财经   

rtmp://58.200.131.2:1935/livetv/cctv3    cctv3综艺   

rtmp://58.200.131.2:1935/livetv/cctv4    cctv4中文国际   

rtmp://58.200.131.2:1935/livetv/cctv5    cctv5体育 (测试有效)   

rtmp://58.200.131.2:1935/livetv/cctv6    cctv6电影   

......后边到cctvn自己测-----


代码只需修改: cap = cv2.VideoCapture(0)为 cap = cv2.VideoCapture(‘rtmp://58.200.131.2:1935/livetv/cctv5’),网速不好,会有些卡顿。同时我没有修改time.sleep(0.19),大家可以改小一些,如time.sleep(0.04),效果会更好。


【智控万物】掌控监视器图17


【本地视频】

代码修改: cap = cv2.VideoCapture(0)为 cap = cv2.VideoCapture(‘CCTV.mp4’),‘CCTV.mp4’视频文件最好与代码文件放在一个目录下。同时我没有修改time.sleep(0.19),大家可以改小一些,如time.sleep(0.04),效果会更好。


【智控万物】掌控监视器图18


【设想计划】

把电脑换成树莓派,做为服务器,向掌控板传送图像。

hnyzcj  版主

发表于 2021-1-21 15:42:53

8错
回复

使用道具 举报

rzyzzxw  版主

发表于 2021-1-21 15:55:49

超赞
回复

使用道具 举报

gray6666  初级技神

发表于 2021-1-23 12:53:42

还是CV2好用,而且教程也经典
回复

使用道具 举报

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

本版积分规则

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

硬件清单

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

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

mail