前言

时间一晃,我已经是一名即将步入研三的老学长,趁着这个假期抓紧时间把毕业设计的大体框架完成,后续细节的优化工作再慢慢处理。毕设的课题是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。由于传输数据是二进制流数据,所以客户端把需要传输的数据编码成二进制码流,服务器接收到再解码进行显示。
那么我的这个设计该怎么实现的图像显示呢???

  1. 像素点摆放
    按像素点顺序一个像素一个像素摆放,当一帧图像的像素全部摆放完成,那么这帧数据也就成功显示出来。首先进行测试的是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. 单通道函数显示黑白图像
    为什么会有第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()
    
  3. 三通道函数显示彩色图像
    话不多说,直接上彩色图像的参考代码,如下所示:

    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)
    
  4. 图像放置在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功能包进行设计。

  1. matplotlib简介
    matplotlib是基于Python语言的开源项目,旨在为Python提供一个数据绘图包。matplotlib是受matlab的启发构建的,matlab是数据绘图领域广泛使用的语言和工具。matlab语言是面向过程的。利用函数的调用,matlab中可以轻松的利用一行命令来绘制直线,然后再用一系列的函数调整结果。我们所使用的matplotlib可分为面向函数编程与面向对象编程。

  2. 面向函数编程
    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)
    
  3. 面向对象编程
    尽管函数式绘图很便利,但利用函数式编程会有以下缺点:增加了一层“函数”调用,降低了效率;隶属关系被函数掩盖。面向对象编程静态/动态图代码如下所示。

    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采集与通信系统之上位机设计相关推荐

  1. 服务器网页版上位机设计 - 03 - 上位机 (完结)

    服务器网页版上位机设计 03 上位机 (完结) 本设计主要涉及三个方面: 服务器,网页版,上位机. 书接上回,介绍完网页页面的设计,现在来说说上位机的功能设计. 也就是js文件的内容编写. 1.获取h ...

  2. 漏电检测系统客户端上位机设计

    漏电检测系统客户端 整体介绍 登录 连接 时间校准 数据解析展示 整体介绍 该上位机客户端使用C#语言进行编写,运行环境是visio studio 2019,该项目整体代码简洁使用,主要有登录进入主界 ...

  3. 如何给上位机设计好看的ICON

    前文 上位机软件,一般需要一个简单清晰好看的icon来方便使用者使用,今天这里说下怎么来实现. 正文 首先我们先建立一个winform程序 这里不用和我一样哈,只需要你添加一个button就行了. 打 ...

  4. 【QT上位机设计——串口收发和波形显示】

    一.简介 最近粗略地学习了一下上位机的编程,大致了解了底层硬件与上位机之间的串口通信逻辑,TCP通信和UDP通信暂时还未学习. 本次把学习思路分享一下,主要学习视频是b站上北京迅为的QT教学视频,我的 ...

  5. CanOpen上位机设计

    先看单个CAN数据帧: 单位是bit,sof占1bit,identifier就是11bit_ID值,DLC4bit表示字节有效数,0-8字节表示64bit DLC的0~8字节:决定64bit内有效字节 ...

  6. 超声波探伤器上位机设计

    1.主菜单栏:文件&视图&工具 2.文件/保存&另存为&打开&退出:视图/矩形扇形转换&扇形矩形转换&插值并重新成像&图像播放& ...

  7. 采集温度数据,用串口传输到上位机

    这里写目录标题 一.实验要求 二.I2C总线通信协议 (一)概念 (二)I2C总线特征 (三)I2C总线协议 (四)I2C的两种方式--硬件I2C和软件I2C 三.AHT20采集温度并上传上位机 四. ...

  8. 上位机开发(架构设计)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途. 联系信箱:feixiaoxing @163.com] 和一般的上位机开发相比,固件下载软件的流程是比较简单.清晰的.所谓的架构设计,一般都是从各种业务 ...

  9. 实战项目(一)嵌入式基础学习与上位机入门设计

    Hello,大家好,首先自我介绍一下,我是大家的新朋友,也是这个教程的主要创建人,大家可以称呼我David,我个人从大学一直到研究生,甚至到工作一直在学习应用嵌入式,从最初的51单片机,到后期深度学习 ...

最新文章

  1. SQL Select语句完整的执行顺序:
  2. [Python爬虫] 中文编码问题:raw_input输入、文件读取、变量比较等str、unicode、utf-8转换问题
  3. @Autowired和@Resource注解的区别?
  4. 【USACO Feb 2014】Cow Decathlon
  5. B端数据表格设计实战指南(建议收藏)
  6. exists 实现查看表Activity中FmyId=1(具体数字在程序中动态给定)的好友发起的活动
  7. 列表视图案例1——阅读古诗
  8. antd select option 设置字体颜色_匹配颜色是照片合成重要关键点
  9. WinEdt LaTex(一)—— hello world!
  10. 使用正交表法设计测试用例
  11. 连接服务器显示用户账户无效,发现MT4真实账户无效该怎么办?
  12. xshell堡垒机_XShell运维工具之跳板机配置
  13. 修复XP图片和传真查看器!
  14. 在哈尔滨的寒风中EOJ 3461【组合数学】
  15. 计算机的垃圾站是在硬盘,电脑垃圾回收站在哪里
  16. 2022CTFSHOW菜狗杯部分MISC(一)
  17. Referring Image Segmentation 综述
  18. 鸿图之下服务器维护10月25,鸿图之下11月25日维护更新公告
  19. 在虚拟机上安装gho、esd(wim)系统镜像文件
  20. 如何在保持营养均衡的同时不长肉

热门文章

  1. 田志刚:显性知识和隐性知识
  2. 小米电视产品的最后一个期货:登场脚步快了
  3. 专业音频编辑软件-Audition 2022 v22.6 macOS
  4. 78 ----二次曲面方程的化简: 移轴变换、转轴变换、伸缩变换
  5. 多个文件生成zip压缩包人后浏览器进行下载
  6. java微博自动转发_怎样做到让微博用户自动转发你推广的内容?
  7. 如何快速检查钢网开口面积比是否符合 IPC7525
  8. almaLinux上使用podman容器安装centos
  9. pdf设置研究保护色
  10. USB采集卡有画面没有声音