camera 影像以 socket 傳送到 client 的測試,目前是用 socket,將來還要改成用 websocket 處理,用以接受多個 client 連線的問題。
numpy
numpy 可以快速地將 bytearray 及 martix 進行轉換,透過這邊的程式碼,我們可以了解到,圖片就是一個二維陣列的矩陣,矩陣中每一個點,代表圖片中的一個像素點,而 OpenCV 是以 BGR 的形式儲存像素點的資料。
#!/usr/bin/python
# coding=utf-8
import cv2
import numpy
import os
import time
# 亂數產生 120000 個 bytes, 轉換為 numpy array
randomByteArray = bytearray(os.urandom(120000))
flatNumpyArray = numpy.array(randomByteArray)
# reshape 成 300x400 的矩陣並存成 gray scale 圖片
grayImage = flatNumpyArray.reshape(300,400)
cv2.imwrite('RandomGray.png', grayImage)
# reshape 成 400x100 的矩陣並存成 BGR 圖片
bgrImage = flatNumpyArray.reshape(100,400, 3)
cv2.imwrite('RandomBGR.png', bgrImage)
camera 影像以 socket 傳送到 client
- 版本1
server.py 等待 client.py 連接,server 接收 client 的 camera 資料
server.py
import socket
import cv2
import numpy
def recvall(sock, count):
buf = b''
while count:
newbuf = sock.recv(count)
if not newbuf: return None
buf += newbuf
count -= len(newbuf)
return buf
TCP_IP = "192.168.1.152"
TCP_PORT = 8002
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((TCP_IP, TCP_PORT))
s.listen(True)
conn, addr = s.accept()
while 1:
length = recvall(conn,16)
stringData = recvall(conn, int(length))
data = numpy.fromstring(stringData, dtype='uint8')
decimg=cv2.imdecode(data,1)
cv2.imshow('SERVER',decimg)
cv2.waitKey(30)
s.close()
cv2.destroyAllWindows()
client.py
import socket
import cv2
import numpy
TCP_IP = "192.168.1.152"
TCP_PORT = 8002
sock = socket.socket()
capture = cv2.VideoCapture(0)
ret, frame = capture.read()
sock.connect((TCP_IP, TCP_PORT))
encode_param=[int(cv2.IMWRITE_JPEG_QUALITY),90]
while ret:
result, imgencode = cv2.imencode('.jpg', frame, encode_param)
data = numpy.array(imgencode)
stringData = data.tostring()
sock.send( str(len(stringData)).ljust(16));
sock.send( stringData );
ret, frame = capture.read()
decimg=cv2.imdecode(data,1)
cv2.imshow('CLIENT',decimg)
cv2.waitKey(30)
sock.close()
cv2.destroyAllWindows()
- 版本2
server.py 等待 client.py 連接,client 接收 server 的 camera 資料,顯示在畫面上
server2.py
import socket
import cv2
import numpy
capture = cv2.VideoCapture(0)
TCP_IP = "192.168.1.159"
TCP_PORT = 8002
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((TCP_IP, TCP_PORT))
s.listen(True)
conn, addr = s.accept()
ret, frame = capture.read()
encode_param=[int(cv2.IMWRITE_JPEG_QUALITY),90]
while ret:
result, imgencode = cv2.imencode('.jpg', frame, encode_param)
data = numpy.array(imgencode)
stringData = data.tostring()
conn.send( str(len(stringData)).ljust(16));
conn.send( stringData );
ret, frame = capture.read()
decimg=cv2.imdecode(data,1)
cv2.imshow('SERVER2',decimg)
cv2.waitKey(30)
conn.close()
cv2.destroyAllWindows()
client2.py
import socket
import cv2
import numpy
def recvall(sock, count):
buf = b''
while count:
newbuf = sock.recv(count)
if not newbuf: return None
buf += newbuf
count -= len(newbuf)
return buf
TCP_IP = "192.168.1.159"
TCP_PORT = 8002
sock = socket.socket()
sock.connect((TCP_IP, TCP_PORT))
while 1:
length = recvall(sock,16)
stringData = recvall(sock, int(length))
data = numpy.fromstring(stringData, dtype='uint8')
decimg=cv2.imdecode(data,1)
cv2.imshow('CLIENT2',decimg)
cv2.waitKey(1)
sock.close()
cv2.destroyAllWindows()
改用 wxPython 作為 GUI
wxWidget 是一個開放原始碼且跨平台的物件工具集(widget toolkit),可用來建立基本的圖形使用者介面,先前測試時,都是以 cv2.imshow 進行畫面 preview,未來為了要製作更複雜的 GUI,所以先測試將畫面改為利用 wxPython 處理。
# mac 上要安裝 py27-wxpython
sudo port install py27-wxpython-3.0
# -*- coding: utf-8 -*-
import wx
import cv2
import time
class TestOpenCV ( wx.Frame ):
windowWidth = 500
windowHeight = 320
def __init__( self, parent=None ):
wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = u"單一視訊畫面", pos = wx.DefaultPosition, size = wx.Size( self.windowWidth, self.windowHeight), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize )
bSizer1 = wx.BoxSizer( wx.VERTICAL )
self.stbmp1 = wx.StaticBitmap( self, wx.ID_ANY, wx.NullBitmap, wx.DefaultPosition, wx.DefaultSize, 0 )
bSizer1.Add( self.stbmp1, 1, wx.ALL|wx.EXPAND, 5 )
## self.stbmp1.SetBitmap(wx.Bitmap( u"../image/heats1-f1-02_gray_pressed.png", wx.BITMAP_TYPE_ANY ))
self.SetSizer( bSizer1 )
self.Layout()
self.Centre( wx.BOTH )
def __del__( self ):
pass
def scale_bitmap(self, bitmap, width, height):
image = wx.ImageFromBitmap(bitmap)
image = image.Scale(width, height, wx.IMAGE_QUALITY_NORMAL)
newimg = wx.BitmapFromImage(image)
return newimg
def updateImage(self, bitmap):
# 縮小圖片符合視窗的大小
newbitmap = self.scale_bitmap(bitmap, self.windowWidth-10, self.windowHeight-30)
self.stbmp1.SetBitmap(newbitmap)
class App(wx.App):
"""Application class."""
def OnInit(self):
self.frame = TestOpenCV()
self.frame.Show()
self.SetTopWindow(self.frame)
self.run()
return True
def rot90(self, img, angle):
if(angle == 270 or angle == -90):
img = cv2.transpose(img)
img = cv2.flip(img, 0) # transpose+flip(0)=CCW
elif (angle == 180 or angle == -180):
img = cv2.flip(img, -1) # transpose+flip(-1)=180
elif (angle == 90 or angle == -270):
img = cv2.transpose(img)
img = cv2.flip(img, 1) # transpose+flip(1)=CW
elif (angle == 360 or angle == 0 or angle == -360):
pass
else :
raise Exception("Unknown rotation angle({})".format(angle))
return img
def run(self):
cap = cv2.VideoCapture(0);
while True:
ret, frame = cap.read()
if ret == True:
# 畫面旋轉 90度
srcBGR = self.rot90(frame, -90)
# wxPython 只能處理 RGB 的圖片,要從 BGR 轉 RGB
srcRGB = cv2.cvtColor(srcBGR, cv2.COLOR_BGR2RGB)
#print dst.shape w=720, h=1280
w, h = srcRGB.shape[:2]
#dst = cv2.resize(srcRGB, (h/2,w/2), interpolation = cv2.INTER_AREA)
#wxImage = wx.ImageFromBuffer(h/2, w/2, dst)
wxImage = wx.ImageFromBuffer(h, w, srcRGB)
bitmap = wx.BitmapFromImage(wxImage)
# 更新 視窗上的圖片
self.frame.updateImage(bitmap)
#cv2.imshow('frame', dst)
#if cv2.waitKey(30) & 0xFF == ord('q'):
# break
# sleep 30ms
time.sleep(0.03)
else:
break
cap.release()
cv2.destroyAllWindows()
def main():
app = App()
app.MainLoop()
if __name__ == '__main__':
main()
請問在虛擬區網路或外網時,嚴重的延遲該怎麼解決
回覆刪除這是用圖片傳遞,資料量大,網路傳輸當然會延遲,基本上是無解,要解決的話,必須要做影像壓縮。
回覆刪除請問後面需要";"分號嗎?
回覆刪除conn.send( str(len(stringData)).ljust(16));
conn.send( stringData );
python 可以在句末加上分號,也可以不寫
刪除