前言
時間一晃,我已經是一名即將步入研三的老學長,趁着這個假期抓緊時間把畢業設計的大體框架完成,後續細節的優化工作再慢慢處理。畢設的課題是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的圖像數據 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()
-
三通道函數顯示彩色圖像
話不多說,直接上彩色圖像的參考代碼,如下所示: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')
-
圖像放置在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)
傳感器數據的可視化分析
這部分後續更新