ROV采集与通信系统之上位机设计
前言
时间一晃,我已经是一名即将步入研三的老学长,趁着这个假期抓紧时间把毕业设计的大体框架完成,后续细节的优化工作再慢慢处理。毕设的课题是ROV采集与通信系统,简单来说就是ROV水下实时采集高清图像信息及各种传感器数据,通过光纤传输至水上经DDR3进行缓存,最后通过千兆以太网上传至上位机进行数据的可视化操作。整体的工作量相对来说还是比较大的,硬件部分设计会在之后的博客进行更新,今天主要来谈一下上位机设计,主要介绍udp数据的接收、图像数据的显示、传感器数据的可视化分析三部分。
UDP数据的接收
udp—–数据报文协议,是一个无连接的简单的面向数据报的运输层协议,UDP不提供可靠性,他只是将应用程序传送给IP层的数据报文发送出去,并不保证能否达到目的地。由于UDP在传输的过程中不需要和服务器建立链接。且没有超时重发的的机制。故而传输速率较快,非常适合作为图像传输的方式。
udp数据的接收部分代码相对固定化,下面直接上代码:
def udp_connect(self):# 创建套接字udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)#local_addr = ('192.168.0.3', 8080)# 绑定本地的相关信息,如果一个网络程序不绑定,则系统会随机分配,下面是从pyqt5的文本框中获取ip地址 和端口号local_addr = (str(self.ui.lineEdit_2.text()), int(self.ui.lineEdit.text()))udp_socket.bind(local_addr)#关闭套接字udp_socket.close()
图像数据的显示
图像的显示此部分比较闹心,当时查阅资料并没有发现有关与RGB格式的图像数据流接收显示这部分内容,有的大多是服务器和客户端都采用Python实现,传输的视频流格式多是JPIE。由于传输数据是二进制流数据,所以客户端把需要传输的数据编码成二进制码流,服务器接收到再解码进行显示。
那么我的这个设计该怎么实现的图像显示呢???
像素点摆放
按像素点顺序一个像素一个像素摆放,当一帧图像的像素全部摆放完成,那么这帧数据也就成功显示出来。首先进行测试的是RGB565格式的图像数据,一个udp数据包传输一行图像数据,开头两字节为图像的行号。代码如下所示:for y in range(480): # 接收一帧图像数据data, addr = udp_socket.recvfrom(1282) data_list[y] = data # 创建一个三维数组,填充图像数据后准备成像 picture = np.zeros((480, 640, 3), dtype=np.uint8)for y in range(480):linenumber = (data_list[y][0] << 8) + data_list[y][1]for x in range(640):# 由于上传图像数据格式为RGB565,即两个字节表示一个像素值,所以需要进行通道分离,这里运用到RGB568——RGB888的方法:采用移位方式实现高位对齐;低位补零。picture [linenumber, x] = [((data_list[y][2*x+2])& 0xF8), ((((data_list[y][2*x+2])& 0x07) <<3) + (data_list[y][2*x+3]& 0xE0) >> 5)<<2, ((data_list[y][2*x+3])& 0x1F)<<3] # 调用Image将数组转换为图像 img = Image.fromarray(data5, 'RGB') # 显示图像 img.imshow()
按像素点实现还有一种函数可采用,上代码:
def draw_picture(self):self.image = QtGui.QImage()self.im = Image.open("timg.jpg")im_1 = self.im.resize((640, 480))#缩放im_2 = Image.new("RGB",(640,480))#创建图片for x in range(640):for y in range(480):im_2.putpixel((x, y),(255,255,0))
单通道函数显示黑白图像
为什么会有第2小节呢? em em em,还不是因为第一种没有成功…
这种结果其实也在意料之中,虽然C和C++的图像成像的确有这种方式,但是由于C和C++的执行效率远超Python,所以这种成像方式虽比较费事,也在承受范围之内。Python就不一样了,640*480分辨率的图像按像素操作要执行30多万次,结果可想而知。即使这样也不能放弃哈,因为Python最大的优势就行集成度高,拥有大量的现成函数可用。
现在进行测试的是单通道的图像数据,同样是一个udp数据包传输一行图像数据,开头两字节为图像的行号。代码如下所示:while True:frame_data, addr = self.udp_socket.recvfrom(642) # 接收数据if((frame_data[0]<<8)+frame_data[1] == 1): # 按行号接收一帧分辨率为640*480的图像数据breakfor y in range(479):row_data, addr = self.udp_socket.recvfrom(642) # 接收数据frame_data = frame_data +row_dataprint('ok')# 数组拷贝frame_list = list(frame_data)self.video_display() # 图像显示def video_display(self):frame = np.array(frame_list).reshape(480,642) # 将数组转换为二维矩阵进行图像显示前的准备工作frame_img = Image.fromarray(np.uint8(frame), 'L') # L代表每个像素8bit的灰度图# im_1 = new_im.resize((320, 240)) # 缩放self.image = ImageQt.toqpixmap(frame_img)self.image.imshow()
三通道函数显示彩色图像
话不多说,直接上彩色图像的参考代码,如下所示:def draw_color_image(self):#彩色图像测试h, w = 640, 480data = np.zeros((w, h, 3), dtype=np.uint8)print(data)data[240, 320] = [255, 255, 0]img = Image.fromarray(data, 'RGB')def video_display(self):frame_coms = np.array(frame_list_coms).reshape(720, 1280, 3)frame_img_coms = Image.fromarray(np.uint8(frame_coms), 'RGB')#frame_img = frame_img.resize((641,360)) #缩放self.image_coms = ImageQt.toqpixmap(frame_img_coms)self.ui.label_12.setPixmap(self.image_coms)
图像放置在pyqt5的Label中
要想将不同类生成的图像放置在pyqt5的Label中显示,首先需要将不同类的图像进行转换为QPixmap格式,然后调用函数就能成功显示。代码如下所示:# PIL Image 与 pyqt5中Qimage互转 # self.image = ImageQt.toqimage(im_2) self.image = ImageQt.toqpixmap(im_2) self.ui.label_11.setPixmap(self.image)# 调用QPixmap将本地图片显示至Label pixmap = QtGui.QPixmap("timg.jpg").scaled(640,480) self.ui.label_11.setPixmap(pixmap)
传感器数据的可视化分析(绘图)
传感器的数据包通过以太网包序列号接收后进行解析,将解析后的数据进行分别绘图。绘图采用matplotlib功能包进行设计。
matplotlib简介
matplotlib是基于Python语言的开源项目,旨在为Python提供一个数据绘图包。matplotlib是受matlab的启发构建的,matlab是数据绘图领域广泛使用的语言和工具。matlab语言是面向过程的。利用函数的调用,matlab中可以轻松的利用一行命令来绘制直线,然后再用一系列的函数调整结果。我们所使用的matplotlib可分为面向函数编程与面向对象编程。面向函数编程
Python中的函数式编程是通过封装对象实现的。matplotlib中的函数式调用其实也是如此。matplotlib本质上还是构建对象来构建图像,函数式编程将构建对象的过程封装在函数中供我们使用。面向函数编程静态/动态图代码如下所示。import matplotlib.pyplot as plt#plt.plot(x, y, '点和线的样式', label=设置图例, linewidth=设置线的粗细) def static_drawing(self):self. x = np.arange(0, 2 * np.pi, 0.1)self. y = np.sin(self.x)plt.plot(x, y, "bo")plt.plot([1, 2, 3], [1, 2, 3], 'go-', label='line 1', linewidth=2, antialiased=False)plt.plot([1, 2, 3], [1, 4, 9], 'rs--', label='line 2')plt.axis([0, 4, 0, 10])plt.legend()plt.show()def dynamic_drawing(self):#交互式绘图plt.ion() # 开启interactive mode 成功的关键函数plt.figure(1)t = [0]m = [0]for i in range(2000):plt.clf() # 清空画布上的所有内容t_now = i * 0.1t.append(t_now) # 模拟数据增量流入,保存历史数据m.append(random.randint(5,26)) # 模拟数据增量流入,保存历史数据plt.plot(t, m, '-r')plt.pause(0.1)
面向对象编程
尽管函数式绘图很便利,但利用函数式编程会有以下缺点:增加了一层“函数”调用,降低了效率;隶属关系被函数掩盖。面向对象编程静态/动态图代码如下所示。from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvasclass Figure_Canvas(FigureCanvas): # 通过继承FigureCanvas类,使得该类既是一个PyQt5的Qwidget,又是一个matplotlib的FigureCanvas,这是连接pyqt5与matplotlib的关键def __init__(self, parent=None, width=11, height=5, dpi=100):plt.rcParams['figure.facecolor'] = 'w' # 设置窗体颜色plt.rcParams['axes.facecolor'] = 'y' # 设置绘图区颜色self.fig = Figure(figsize=(width, height), dpi=100)super(Figure_Canvas, self).__init__(self.fig)def static_drawing(self):self.SensorFigure = Figure_Canvas()# 深度图t = np.linspace(0, 12, 101)self.SensorFigure.axes_1 =self.SensorFigure.fig.add_subplot(221)self.SensorFigure.axes_1.set_xlim(0, 12)self.SensorFigure.axes_1.set_ylim(-1, 1)self.SensorFigure.axes_1.plot(t, np.sin(t + time.time()))self.SensorFigure.axes_1.set_title("depth")# 浑浊度图self.SensorFigure.axes_2 = self.SensorFigure.fig.add_subplot(222)self.SensorFigure.axes_2.scatter(np.random.rand(20), np.random.rand(20))self.SensorFigure.axes_2.set_title("turbidity")self.LineFigureLayout = QtWidgets.QGridLayout(self.ui.groupBox)self.LineFigureLayout.addWidget(self.SensorFigure, 0, 2)self.SensorFigure.fig.suptitle("SensorFigure")
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas import matplotlib.pyplot as pltdef dynamic_drawing_init(self): #添加定时器定时更新图 self.timer = QTimer()self.timer.start(1)self.timer.timeout.connect(self.dynamic_drawing) # 数组初始化self.x = []self.y = []self.z = []self.u = []self.figure = plt.figure(edgecolor ='blue', frameon=True)self.figure.suptitle('Sensor_Figure')#标题self.canvas = FigureCanvas(self.figure)self.LineFigureLayout = QtWidgets.QGridLayout(self.ui.groupBox)self.LineFigureLayout.addWidget(self.canvas)#图显示于groupBox控件中def dynamic_drawing_display(self): depth = np.random.random_sample() * 10 # 返回一个[0,1)之间的浮点型随机数*10self.x.append(depth) # 数组更新turbidity = np.random.random_sample() * 8 # 返回一个[0,1)之间的浮点型随机数*10self.y.append(turbidity) # 数组更新ultrasound = np.random.random_sample() * 5 # 返回一个[0,1)之间的浮点型随机数*10self.z.append(ultrasound) # 数组更新temperature = np.random.random_sample() * 3 # 返回一个[0,1)之间的浮点型随机数*10self.u.append(temperature) # 数组更新axes_1 = self.figure.add_subplot(2, 2, 1)axes_1.yaxis.set_tick_params(color='red', colors='red') # 设置X轴刻度颜色axes_1.xaxis.set_tick_params(color='red', colors='red') # 设置X轴刻度颜色axes_1.clear()axes_1.set_title('depth')axes_1.plot(self.x)axes_2 = self.figure.add_subplot(2, 2, 2)axes_2.clear()axes_2.set_title('turbidity')axes_2.plot(self.y, 'k--')axes_3 = self.figure.add_subplot(2, 2, 3)axes_3.clear()axes_3.set_title('ultrasound')axes_3.plot(self.z, 'b--')axes_4 = self.figure.add_subplot(2, 2, 4)axes_4.clear()axes_4.set_title('temperature')axes_4.plot(self.u, 'r')self.figure.tight_layout() # 调整整体空白plt.subplots_adjust(wspace =0.2, hspace =0.3) # 调整子图间距self.canvas.draw()
ROV采集与通信系统之上位机设计相关推荐
- 服务器网页版上位机设计 - 03 - 上位机 (完结)
服务器网页版上位机设计 03 上位机 (完结) 本设计主要涉及三个方面: 服务器,网页版,上位机. 书接上回,介绍完网页页面的设计,现在来说说上位机的功能设计. 也就是js文件的内容编写. 1.获取h ...
- 漏电检测系统客户端上位机设计
漏电检测系统客户端 整体介绍 登录 连接 时间校准 数据解析展示 整体介绍 该上位机客户端使用C#语言进行编写,运行环境是visio studio 2019,该项目整体代码简洁使用,主要有登录进入主界 ...
- 如何给上位机设计好看的ICON
前文 上位机软件,一般需要一个简单清晰好看的icon来方便使用者使用,今天这里说下怎么来实现. 正文 首先我们先建立一个winform程序 这里不用和我一样哈,只需要你添加一个button就行了. 打 ...
- 【QT上位机设计——串口收发和波形显示】
一.简介 最近粗略地学习了一下上位机的编程,大致了解了底层硬件与上位机之间的串口通信逻辑,TCP通信和UDP通信暂时还未学习. 本次把学习思路分享一下,主要学习视频是b站上北京迅为的QT教学视频,我的 ...
- CanOpen上位机设计
先看单个CAN数据帧: 单位是bit,sof占1bit,identifier就是11bit_ID值,DLC4bit表示字节有效数,0-8字节表示64bit DLC的0~8字节:决定64bit内有效字节 ...
- 超声波探伤器上位机设计
1.主菜单栏:文件&视图&工具 2.文件/保存&另存为&打开&退出:视图/矩形扇形转换&扇形矩形转换&插值并重新成像&图像播放& ...
- 采集温度数据,用串口传输到上位机
这里写目录标题 一.实验要求 二.I2C总线通信协议 (一)概念 (二)I2C总线特征 (三)I2C总线协议 (四)I2C的两种方式--硬件I2C和软件I2C 三.AHT20采集温度并上传上位机 四. ...
- 上位机开发(架构设计)
[ 声明:版权所有,欢迎转载,请勿用于商业用途. 联系信箱:feixiaoxing @163.com] 和一般的上位机开发相比,固件下载软件的流程是比较简单.清晰的.所谓的架构设计,一般都是从各种业务 ...
- 实战项目(一)嵌入式基础学习与上位机入门设计
Hello,大家好,首先自我介绍一下,我是大家的新朋友,也是这个教程的主要创建人,大家可以称呼我David,我个人从大学一直到研究生,甚至到工作一直在学习应用嵌入式,从最初的51单片机,到后期深度学习 ...
最新文章
- SQL Select语句完整的执行顺序:
- [Python爬虫] 中文编码问题:raw_input输入、文件读取、变量比较等str、unicode、utf-8转换问题
- @Autowired和@Resource注解的区别?
- 【USACO Feb 2014】Cow Decathlon
- B端数据表格设计实战指南(建议收藏)
- exists 实现查看表Activity中FmyId=1(具体数字在程序中动态给定)的好友发起的活动
- 列表视图案例1——阅读古诗
- antd select option 设置字体颜色_匹配颜色是照片合成重要关键点
- WinEdt LaTex(一)—— hello world!
- 使用正交表法设计测试用例
- 连接服务器显示用户账户无效,发现MT4真实账户无效该怎么办?
- xshell堡垒机_XShell运维工具之跳板机配置
- 修复XP图片和传真查看器!
- 在哈尔滨的寒风中EOJ 3461【组合数学】
- 计算机的垃圾站是在硬盘,电脑垃圾回收站在哪里
- 2022CTFSHOW菜狗杯部分MISC(一)
- Referring Image Segmentation 综述
- 鸿图之下服务器维护10月25,鸿图之下11月25日维护更新公告
- 在虚拟机上安装gho、esd(wim)系统镜像文件
- 如何在保持营养均衡的同时不长肉