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。由於傳輸數據是二進制流數據,所以客戶端把需要傳輸的數據編碼成二進制碼流,服務器接收到再解碼進行顯示。
那麼我的這個設計該怎麼實現的圖像顯示呢???

  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的圖像數據
                break
        for y in range(479):
            row_data, addr = self.udp_socket.recvfrom(642)    # 接收數據
            frame_data = frame_data +row_data
        print('ok')
    	# 數組拷貝
        frame_list = list(frame_data)
    	self.video_display()								 # 圖像顯示
    	
    def video_receiving(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, 480
        data = np.zeros((w, h, 3), dtype=np.uint8)
        print(data)
        data[240, 320] = [255, 255, 0]
        img = Image.fromarray(data, 'RGB')
    
  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)
    

傳感器數據的可視化分析

這部分後續更新

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章