Browse Source

3dtof 可视化

zx 1 year ago
commit
6b0f4298e3
10 changed files with 1337 additions and 0 deletions
  1. 302 0
      Viewer/CustomFrame.py
  2. 110 0
      Viewer/GrpcClient.py
  3. 57 0
      Viewer/MainWnd.py
  4. 385 0
      Viewer/PCViewer.py
  5. 63 0
      Viewer/def.proto
  6. 42 0
      Viewer/def_pb2.py
  7. 91 0
      Viewer/def_pb2.pyi
  8. 264 0
      Viewer/def_pb2_grpc.py
  9. 22 0
      Viewer/main.py
  10. 1 0
      Viewer/proto.sh

+ 302 - 0
Viewer/CustomFrame.py

@@ -0,0 +1,302 @@
+
+from PyQt5.QtWidgets import QTabWidget,QSplitter, QLineEdit,QCheckBox,QLabel,QFrame,QPushButton,QMenu,QAction
+from PyQt5.QtGui import QPixmap,QImage,QPainter,QResizeEvent,QCloseEvent,QPaintEvent,QFont
+from PyQt5.QtCore import QSize,QTimer,QRect,Qt
+import numpy as np
+import def_pb2 as pb
+from concurrent.futures import ThreadPoolExecutor, as_completed, wait
+import GrpcClient as rpc
+from PCViewer import PCLViewer
+
+class ControlFrame(QFrame):
+    def __init__(self):
+        QFrame.__init__(self)
+        self.threadPool_ = ThreadPoolExecutor(5)
+        self.setGeometry(0, 0, 500, 500)
+        self.InitUI()
+        self.setFrameShape(self.StyledPanel)
+        #self.timer_ = QTimer()
+        #self.timer_.timeout.connect(self.Update)
+        #self.timer_.start(100)
+    def DisplayMeasureInfo(self,info : pb.MeasureInfo):
+        self.ErrorInfo.setText(info.error)
+    def OnAction(self,dtype,id):
+        client=rpc.GrpcStream()
+        ip=self.IPEdit.text()
+        port=int(self.PortEdit.text())
+        if dtype==1:
+            self.threadPool_.submit(client.GrabImage,ip,port,id)
+        if dtype==2:
+            self.threadPool_.submit(client.GrabCloud,ip,port,id)
+    def InitUI(self):
+
+        self.begstatic = QLabel(self)
+        self.begstatic.setText("   IP:")
+        self.begstatic.setGeometry(20, 5, 80, 30)
+        self.IPEdit = QLineEdit(self)
+        self.IPEdit.setText("192.168.2.45")
+        self.IPEdit.setGeometry(90, 5, 150, 30)
+
+        self.endstatic = QLabel(self)
+        self.endstatic.setText("Port:")
+        self.endstatic.setGeometry(20, 50, 80, 30)
+        self.PortEdit = QLineEdit(self)
+        self.PortEdit.setText("9876")
+        self.PortEdit.setGeometry(90, 50, 150, 30)
+
+        self.btnGrab = QPushButton(self)
+        self.btnGrab.setGeometry(20, 140, 100, 40)
+        self.btnGrab.setText("抓取图像")
+        self.btnGrab.clicked.connect(self.btnGrabImageClick)
+
+        self.btnCancel = QPushButton(self)
+        self.btnCancel.setGeometry(150, 140, 100, 40)
+        self.btnCancel.setText("抓取点云")
+        self.btnCancel.clicked.connect(self.btnGrabCloudClick)
+
+
+        self.btnImageStreamCheck = QCheckBox("实时图像", self)
+        self.btnImageStreamCheck.setGeometry(20, 90, 120, 40)
+        self.btnImageStreamCheck.clicked.connect(self.RealTimeImagecb)
+
+        self.btnDataStreamCheck = QCheckBox("实时结果打印", self)
+        self.btnDataStreamCheck.setGeometry(150, 90, 120, 40)
+        self.btnDataStreamCheck.clicked.connect(self.RealTimeDatacb)
+
+        self.ErrorInfo = QLabel(self)
+        self.ErrorInfo.setGeometry(20, 200, 250, 400)
+        self.ErrorInfo.setWordWrap(True)
+        self.ErrorInfo.setAlignment(Qt.AlignTop)
+    def RealTimeDatacb(self):
+        if self.btnDataStreamCheck.checkState()==Qt.Checked:
+            client=rpc.GrpcStream()
+            ip=self.IPEdit.text()
+            port=int(self.PortEdit.text())
+            self.threadPool_.submit(client.OpenDataStream,ip,port)
+        else:
+            client=rpc.GrpcStream()
+            ip=self.IPEdit.text()
+            port=int(self.PortEdit.text())
+            self.threadPool_.submit(client.CloseDataStream,ip,port)
+    def RealTimeImagecb(self):
+        if self.btnImageStreamCheck.checkState()==Qt.Checked:
+            self.btnGrab.setEnabled(False)
+            client=rpc.GrpcStream()
+            ip=self.IPEdit.text()
+            port=int(self.PortEdit.text())
+            self.threadPool_.submit(client.OpenImageStream,ip,port)
+        else:
+            self.btnGrab.setEnabled(True)
+            client=rpc.GrpcStream()
+            ip=self.IPEdit.text()
+            port=int(self.PortEdit.text())
+            self.threadPool_.submit(client.CloseImageStream,ip,port)
+    def closeEvent(self, a0: QCloseEvent) -> None:
+        if self.btnImageStreamCheck.checkState()==Qt.Checked:
+            client=rpc.GrpcStream()
+            ip=self.IPEdit.text()
+            port=int(self.PortEdit.text())
+            self.threadPool_.submit(client.CloseImageStream,ip,port)
+        if self.btnDataStreamCheck.checkState()==Qt.Checked:
+            client=rpc.GrpcStream()
+            ip=self.IPEdit.text()
+            port=int(self.PortEdit.text())
+            self.threadPool_.submit(client.CloseDataStream,ip,port)
+        self.threadPool_.shutdown(wait=False)
+        rpc.GrpcStream().close()
+    def btnGrabImageClick(self):
+        if self.btnImageStreamCheck.checkState()==Qt.Checked:
+            print(" 先关闭实时显示")
+        else :
+            client=rpc.GrpcStream()
+            ip=self.IPEdit.text()
+            port=int(self.PortEdit.text())
+            self.threadPool_.submit(client.GrabImage,ip,port,0)
+    def btnGrabCloudClick(self):
+        client=rpc.GrpcStream()
+        ip=self.IPEdit.text()
+        port=int(self.PortEdit.text())
+        for id in range(4):
+            self.threadPool_.submit(client.GrabCloud,ip,port,id+1)
+    def btnCancelClick(self):
+        pass
+class ImageViewer(QLabel):
+    def __init__(self,parent,OnAction,id):
+        super(ImageViewer,self).__init__(parent=parent)
+        self.OnAction=OnAction
+        self.dtype=1
+        self.id=id
+        self.image=None
+        self.show = False
+        self.setStyleSheet("border-width:1px;border-style:solid;border-color:rgb(150,150,150)")
+        self.timer=QTimer()
+        self.timer.timeout.connect(self.OnTimer)
+    def FlashImg(self,pixmap):
+        self.image=pixmap
+        if self.timer.isActive()==False:
+            self.timer.start(500)
+    def ShowImg(self,pixmap):
+        self.timer.stop()
+        self.show=True
+        self.image=pixmap
+        self.repaint()
+    def updataData(self):
+        self.OnAction(self.dtype,self.id)
+        print("%d,%d"%(self.dtype,self.id))
+
+    def contextMenuEvent(self, a0):
+        menu=QMenu(self)
+        updata_act=QAction("更新")
+        updata_act.triggered.connect(self.updataData)
+        menu.addAction(updata_act)
+        ret=menu.exec_(a0.globalPos())
+
+    def OnTimer(self):
+        self.show=not self.show
+        self.repaint()
+
+    def paintEvent(self, a0: QPaintEvent) -> None:
+        if self.show==True:
+            if not self.image == None:
+                w, h = self.size().width(),self.size().height()
+                iw, ih = self.image.width(), self.image.height()
+                painter=QPainter(self)
+                painter.drawPixmap(QRect(0,0,w,h),self.image,QRect(0,0,iw,ih))
+
+class PointCLViwer(QSplitter):
+    def __init__(self,OnAction,id):
+        super(PointCLViwer, self).__init__()
+        self.OnAction=OnAction
+        self.dtype=2
+        self.id=id
+        self.InitUI()
+    def InitUI(self):
+        self.pclViewer=PCLViewer()
+        self.addWidget(self.pclViewer)
+        self.setStretchFactor(0,4)
+    def save(self):
+        print("save")
+    def displayCloud(self,points:np.array):
+        self.pclViewer.displayPCL(points)
+    def resetViewer(self):
+        self.pclViewer.resetViewer()
+    def updataData(self):
+        self.OnAction(self.dtype,self.id)
+    def contextMenuEvent(self, a0):
+        menu=QMenu(self)
+        updata_act=QAction("更新点云")
+        updata_act.triggered.connect(self.updataData)
+        menu.addAction(updata_act)
+
+        act=QAction("还原视野")
+        act.triggered.connect(self.resetViewer)
+        menu.addAction(act)
+
+        actSave=QAction("保存")
+        actSave.triggered.connect(self.save)
+        menu.addAction(actSave)
+        ret=menu.exec_(a0.globalPos())
+
+class ViewerFrame(QFrame):
+    def __init__(self,OnAction):
+        super(ViewerFrame, self).__init__()
+        self.OnAction=OnAction
+        self.InitUI()
+    def InitUI(self):
+
+        self.table1=QTabWidget(self)
+        self.table2=QTabWidget(self)
+        self.table3=QTabWidget(self)
+        self.table4=QTabWidget(self)
+        self.table1.setTabPosition(QTabWidget.TabPosition.North)
+        self.table2.setTabPosition(QTabWidget.TabPosition.North)
+        self.table3.setTabPosition(QTabWidget.TabPosition.North)
+        self.table4.setTabPosition(QTabWidget.TabPosition.North)
+
+        self.panel1=ImageViewer(self,self.OnAction,1)
+        self.panel2=ImageViewer(self,self.OnAction,2)
+        self.panel3=ImageViewer(self,self.OnAction,3)
+        self.panel4=ImageViewer(self,self.OnAction,4)
+
+        self.pcViewer1=PointCLViwer(self.OnAction,1)
+        self.pcViewer2=PointCLViwer(self.OnAction,2)
+        self.pcViewer3=PointCLViwer(self.OnAction,3)
+        self.pcViewer4=PointCLViwer(self.OnAction,4)
+
+        self.table1.addTab(self.panel1,"图像")
+        self.table1.addTab(self.pcViewer1,"点云")
+        self.table2.addTab(self.panel2,"图像")
+        self.table2.addTab(self.pcViewer2,"点云")
+        self.table3.addTab(self.panel3,"图像")
+        self.table3.addTab(self.pcViewer3,"点云")
+        self.table4.addTab(self.panel4,"图像")
+        self.table4.addTab(self.pcViewer4,"点云")
+
+    def closeEvent(self, a0: QCloseEvent) -> None:
+        pass
+    def resizeEvent(self, a0: QResizeEvent) -> None:
+        w, h = self.size().width(), self.size().height()
+        w=w-15
+        h=h-15
+        self.table1.setGeometry(5, 5, w/2, h/2)
+        self.table2.setGeometry(10+w/2, 5, w/2, h/2)
+        self.table3.setGeometry(5, 10+h/2, w/2, h/2)
+        self.table4.setGeometry(10+w/2, 10+h/2, w/2, h/2)
+
+    def PbImg2QPix(self,image:pb.Image):
+        img1=image
+        w=img1.width
+        h=img1.height
+        c=img1.channel
+        btarry=bytearray(img1.data)
+        npdata = np.frombuffer(btarry, dtype=np.uint8)
+        if c==3:
+            npdata = npdata.reshape([h,w,c])
+            qimg=QImage(npdata.data,w,h,QImage.Format_RGB888)
+        if c==1:
+            npdata = npdata.reshape([h,w])
+            qimg=QImage(npdata.data,w,h,QImage.Format_Grayscale8)
+        pix=QPixmap(qimg)
+        return pix
+    def PbCloud2Pts(self,cloud:pb.PointCloud):
+
+        size=cloud.size
+        btarry=bytearray(cloud.data)
+        npdata = np.frombuffer(btarry, dtype=np.short)
+        points= npdata.reshape([size,4])/32750.0 *5.0
+        return points
+    def DisplayFrame(self,frame : pb.ResFrame):
+        if frame.HasField("images"):
+            self.DisplayImage(frame.images)
+        if frame.HasField("clouds"):
+            self.DisplayCloud(frame.clouds)
+    def DisplayImage(self,images:pb.ResImage):
+        if images.HasField("img1"):
+            self.panel1.ShowImg(self.PbImg2QPix(images.img1))
+        if images.HasField("img2"):
+            self.panel2.ShowImg(self.PbImg2QPix(images.img2))
+        if images.HasField("img3"):
+            self.panel3.ShowImg(self.PbImg2QPix(images.img3))
+        if images.HasField("img4"):
+            self.panel4.ShowImg(self.PbImg2QPix(images.img4))
+    def DisplayCloud(self,clouds:pb.ResCloud):
+        if clouds.HasField("cloud1"):
+            self.pcViewer1.displayCloud(self.PbCloud2Pts(clouds.cloud1))
+        if clouds.HasField("cloud2"):
+            self.pcViewer2.displayCloud(self.PbCloud2Pts(clouds.cloud2))
+        if clouds.HasField("cloud3"):
+            self.pcViewer3.displayCloud(self.PbCloud2Pts(clouds.cloud3))
+        if clouds.HasField("cloud4"):
+            self.pcViewer4.displayCloud(self.PbCloud2Pts(clouds.cloud4))
+
+
+
+
+
+
+
+
+
+
+
+

+ 110 - 0
Viewer/GrpcClient.py

@@ -0,0 +1,110 @@
+import time
+
+import grpc
+import def_pb2 as pb
+import def_pb2_grpc as mrpc
+import threading
+def singleton(cls):
+    _instance = {}
+
+    def inner():
+        if cls not in _instance:
+            _instance[cls] = cls()
+        return _instance[cls]
+    return inner
+@singleton
+class GrpcStream(threading.Thread):
+    def __init__(self):
+        threading.Thread.__init__(self)
+        self.exit_=False
+        self.features_=None
+        self.measures_=None
+        self.imagesCallBack=None
+        self.cloudCallBack=None
+        self.MeasureDataCallBack=None
+    def SetDataCallBack(self,ImagesCallback,CloudsCallBack,MeasureDataCallback):
+        self.imagesCallBack=ImagesCallback
+        self.cloudCallBack=CloudsCallBack
+        self.MeasureDataCallBack=MeasureDataCallback
+    def GrabImage(self,ip,port,id): # id:1-4,其他表示所有
+        connectstr='%s:%d'%(ip,port)
+        self.channel=grpc.insecure_channel(connectstr)
+        self.stub = mrpc.StreamServerStub(self.channel)
+        cmd=pb.RequestCmd()
+        cmd.Id=id
+        try:
+            resImage=self.stub.GetImage(cmd)
+            if self.imagesCallBack is not None:
+                self.imagesCallBack(resImage)
+        except Exception as e:
+            print(e)
+    def GrabCloud(self,ip,port,id): # id:1-4,其他表示所有
+        connectstr='%s:%d'%(ip,port)
+        self.channel=grpc.insecure_channel(connectstr)
+        self.stub = mrpc.StreamServerStub(self.channel)
+        cmd=pb.RequestCmd()
+        cmd.Id=id
+        try:
+            resCloud=self.stub.GetCloud(cmd)
+            if self.cloudCallBack is not None:
+                self.cloudCallBack(resCloud)
+        except Exception as e:
+            print(e)
+    def OpenDataStream(self,ip,port):
+        connectstr='%s:%d'%(ip,port)
+        channel=grpc.insecure_channel(connectstr)
+        stub = mrpc.StreamServerStub(channel)
+        cmd=pb.RequestCmd()
+        self.measures_ = stub.OpenMeasureDataStream(cmd)
+    def CloseDataStream(self,ip,port):
+        connectstr='%s:%d'%(ip,port)
+        channel=grpc.insecure_channel(connectstr)
+        stub = mrpc.StreamServerStub(channel)
+        cmd=pb.RequestCmd()
+        stub.CloseMeasureDataStream(cmd)
+    def OpenImageStream(self,ip,port):
+        connectstr='%s:%d'%(ip,port)
+        channel=grpc.insecure_channel(connectstr)
+        stub = mrpc.StreamServerStub(channel)
+        cmd=pb.RequestCmd()
+        self.features_ = stub.OpenImageStream(cmd)
+
+    def CloseImageStream(self,ip,port):
+        connectstr='%s:%d'%(ip,port)
+        channel=grpc.insecure_channel(connectstr)
+        stub = mrpc.StreamServerStub(channel)
+        cmd=pb.RequestCmd()
+        stub.CloseImageStream(cmd)
+
+    def loopImageStream(self):
+        if self.features_ is not None:
+            try:
+                for feature in self.features_:  #流式返回的结果
+                    if self.imagesCallBack is not None:
+                        self.imagesCallBack(feature)
+                    break
+            except Exception as e:
+                self.features_=None
+    def loopDataStream(self):
+        if self.measures_ is not None:
+            try:
+                for measure in self.measures_:
+                    if self.MeasureDataCallBack is not None:
+                        self.MeasureDataCallBack(measure)
+                    break
+            except Exception as e:
+                if self.MeasureDataCallBack is not None:
+                    info=pb.MeasureInfo()
+                    info.error=str(e)
+                    self.MeasureDataCallBack(info)
+                self.measures_=None
+    def run(self):
+        while self.exit_==False:
+            time.sleep(0.001)
+            self.loopImageStream()
+            self.loopDataStream()
+
+        print(" close ")
+    def close(self):
+        self.exit_=True
+        self.join()

+ 57 - 0
Viewer/MainWnd.py

@@ -0,0 +1,57 @@
+
+import math
+import time
+import sys
+from PyQt5.QtGui import *
+from PyQt5.QtWidgets import *
+from PyQt5.QtCore import *
+from CustomFrame import *
+
+
+class MainWindow(QMainWindow):
+    """docstring for Mainwindow"""
+
+    def __init__(self, parent = None):
+        super(MainWindow,self).__init__(parent)
+        self.basic()
+        self.Controller = ControlFrame()
+        self.viewerFrame = ViewerFrame(self.Controller.OnAction)
+
+
+        splitter= self.split_()
+        self.setCentralWidget(splitter)
+
+    #窗口基础属性
+    def basic(self):
+        #设置标题,大小,图标
+        self.setWindowTitle("RPC3DView")
+        self.resize(490*2+300, 370*2)
+        #self.setWindowIcon(QIcon("./image/Gt.png"))
+        #居中显示
+        screen = QDesktopWidget().geometry()
+        self_size = self.geometry()
+        self.move(int((screen.width() - self_size.width())/2),int((screen.height() - self_size.height())/2))
+
+    def closeEvent(self, QCloseEvent):
+        self.Controller.close()
+        self.viewerFrame.close()
+
+    #分割窗口
+    def split_(self):
+
+        splitter = QSplitter(Qt.Horizontal)
+
+        splitter.addWidget(self.viewerFrame)
+        splitter.addWidget(self.Controller)
+
+        splitter.setStretchFactor(0,3)
+        splitter.setStretchFactor(1,1)
+        return splitter
+    def OnImagesHandle(self,images:pb.ResImage):
+        self.viewerFrame.DisplayImage(images)
+
+    def OnCloudHandle(self,clouds:pb.ResCloud):
+        self.viewerFrame.DisplayCloud(clouds)
+
+    def OnMeasureDataHandle(self,measure:pb.MeasureInfo):
+        self.Controller.DisplayMeasureInfo(measure)

+ 385 - 0
Viewer/PCViewer.py

@@ -0,0 +1,385 @@
+from OpenGL import GLUT
+# -*-coding: utf-8 -*-
+#===============================================================================
+
+from PyQt5 import QtCore, QtGui, QtOpenGL
+import math
+import numpy
+import numpy.linalg as linalg
+import OpenGL
+OpenGL.ERROR_CHECKING = True
+from OpenGL.GL import *
+from OpenGL.GLU import *
+
+class PyGLWidget(QtOpenGL.QGLWidget):
+
+    # Qt signals
+    signalGLMatrixChanged = QtCore.pyqtSignal()
+    rotationBeginEvent = QtCore.pyqtSignal()
+    rotationEndEvent = QtCore.pyqtSignal()
+
+    def __init__(self, parent = None):
+        format = QtOpenGL.QGLFormat()
+        format.setSampleBuffers(True)
+        QtOpenGL.QGLWidget.__init__(self, format, parent)
+        self.setCursor(QtCore.Qt.OpenHandCursor)
+        self.setMouseTracking(True)
+
+        self.modelview_matrix_  = [
+            [1,0,0,0],
+            [0,1,0,0],
+            [0,0,1,0],
+            [-10.53889084,-2.01535511,-25.95999146,1. ]]
+        self.translate_vector_  = [0, 0, 0.0]
+        self.viewport_matrix_   = []
+        self.projection_matrix_ = []
+        self.near_   = 0.1
+        self.far_    = 100.0
+        self.fovy_   = 45.0
+        self.radius_ = 10.0
+        self.last_point_2D_ = QtCore.QPoint()
+        self.last_point_ok_ = False
+        self.last_point_3D_ = [1.0, 0.0, 0.0]
+        self.isInRotation_  = False
+
+
+
+        # connections
+        #self.signalGLMatrixChanged.connect(self.printModelViewMatrix)
+
+    @QtCore.pyqtSlot()
+    def printModelViewMatrix(self):
+        print (self.modelview_matrix_)
+
+    def initializeGL(self):
+        # OpenGL state
+        glClearColor(0.3, 0.3, 0.3, 0.5)
+        glEnable(GL_DEPTH_TEST)
+        self.reset_view()
+        self.translate([0,0,-5])
+
+    def resizeGL(self, width, height):
+        glViewport(0, 0, width, height );
+        self.set_projection( self.near_, self.far_, self.fovy_ );
+        self.updateGL()
+
+    def paintGL(self):
+        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
+
+        glMatrixMode(GL_MODELVIEW)
+        glLoadMatrixd(self.modelview_matrix_)
+        #self.printModelViewMatrix()
+
+    def set_projection(self, _near, _far, _fovy):
+        self.near_ = _near
+        self.far_ = _far
+        self.fovy_ = _fovy
+        self.makeCurrent()
+        glMatrixMode( GL_PROJECTION )
+        glLoadIdentity()
+        gluPerspective( self.fovy_, float(self.width()) / float(self.height()),
+                        self.near_, self.far_ )
+        self.updateGL()
+
+    def set_center(self, _cog):
+        self.center_ = _cog
+        self.view_all()
+
+    def set_radius(self, _radius):
+        self.radius_ = _radius
+        self.set_projection(_radius / 100.0, _radius * 100.0, self.fovy_)
+        self.reset_view()
+        self.translate([0, 0, -_radius * 2.0])
+        self.view_all()
+        self.updateGL()
+
+    def reset_view(self):
+        # scene pos and size
+        glMatrixMode( GL_MODELVIEW )
+        glLoadIdentity();
+        self.modelview_matrix_ = glGetDoublev( GL_MODELVIEW_MATRIX )
+        self.set_center([0.0, 0.0, 0.0])
+
+
+    def reset_rotation(self):
+        self.modelview_matrix_[0] = [1.0, 0.0, 0.0, 0.0]
+        self.modelview_matrix_[1] = [0.0, 1.0, 0.0, 0.0]
+        self.modelview_matrix_[2] = [0.0, 0.0, 1.0, 0.0]
+        glMatrixMode(GL_MODELVIEW)
+        glLoadMatrixd(self.modelview_matrix_)
+        self.updateGL()
+
+    def translate(self, _trans):
+        # Translate the object by _trans
+        # Update modelview_matrix_
+        self.makeCurrent()
+        glMatrixMode(GL_MODELVIEW)
+        glLoadIdentity()
+        glTranslated(_trans[0], _trans[1], _trans[2])
+        glMultMatrixd(self.modelview_matrix_)
+        self.modelview_matrix_ = glGetDoublev(GL_MODELVIEW_MATRIX)
+        self.translate_vector_[0] = self.modelview_matrix_[3][0]
+        self.translate_vector_[1] = self.modelview_matrix_[3][1]
+        self.translate_vector_[2] = self.modelview_matrix_[3][2]
+        self.signalGLMatrixChanged.emit()
+
+    def rotate(self, _axis, _angle):
+        t = [self.modelview_matrix_[0][0] * self.center_[0] +
+             self.modelview_matrix_[1][0] * self.center_[1] +
+             self.modelview_matrix_[2][0] * self.center_[2] +
+             self.modelview_matrix_[3][0],
+             self.modelview_matrix_[0][1] * self.center_[0] +
+             self.modelview_matrix_[1][1] * self.center_[1] +
+             self.modelview_matrix_[2][1] * self.center_[2] +
+             self.modelview_matrix_[3][1],
+             self.modelview_matrix_[0][2] * self.center_[0] +
+             self.modelview_matrix_[1][2] * self.center_[1] +
+             self.modelview_matrix_[2][2] * self.center_[2] +
+             self.modelview_matrix_[3][2]]
+
+        self.makeCurrent()
+        glLoadIdentity()
+        glTranslatef(t[0], t[1], t[2])
+        glRotated(_angle, _axis[0], _axis[1], _axis[2])
+        glTranslatef(-t[0], -t[1], -t[2])
+        glMultMatrixd(self.modelview_matrix_)
+        self.modelview_matrix_ = glGetDoublev(GL_MODELVIEW_MATRIX)
+        self.signalGLMatrixChanged.emit()
+
+    def view_all(self):
+        self.translate( [ -( self.modelview_matrix_[0][0] * self.center_[0] +
+                             self.modelview_matrix_[0][1] * self.center_[1] +
+                             self.modelview_matrix_[0][2] * self.center_[2] +
+                             self.modelview_matrix_[0][3]),
+                          -( self.modelview_matrix_[1][0] * self.center_[0] +
+                             self.modelview_matrix_[1][1] * self.center_[1] +
+                             self.modelview_matrix_[1][2] * self.center_[2] +
+                             self.modelview_matrix_[1][3]),
+                          -( self.modelview_matrix_[2][0] * self.center_[0] +
+                             self.modelview_matrix_[2][1] * self.center_[1] +
+                             self.modelview_matrix_[2][2] * self.center_[2] +
+                             self.modelview_matrix_[2][3] +
+                             self.radius_ / 2.0 )])
+
+    def map_to_sphere(self, _v2D):
+        _v3D = [0.0, 0.0, 0.0]
+        # inside Widget?
+        if (( _v2D.x() >= 0 ) and ( _v2D.x() <= self.width() ) and
+                ( _v2D.y() >= 0 ) and ( _v2D.y() <= self.height() ) ):
+            # map Qt Coordinates to the centered unit square [-0.5..0.5]x[-0.5..0.5]
+            x  = float( _v2D.x() - 0.5 * self.width())  / self.width()
+            y  = float( 0.5 * self.height() - _v2D.y()) / self.height()
+
+            _v3D[0] = x;
+            _v3D[1] = y;
+            # use Pythagoras to comp z-coord (the sphere has radius sqrt(2.0*0.5*0.5))
+            z2 = 2.0*0.5*0.5-x*x-y*y;
+            # numerical robust sqrt
+            _v3D[2] = math.sqrt(max( z2, 0.0 ))
+
+            # normalize direction to unit sphere
+            n = linalg.norm(_v3D)
+            _v3D = numpy.array(_v3D) / n
+
+            return True, _v3D
+        else:
+            return False, _v3D
+
+    def wheelEvent(self, _event):
+        # Use the mouse wheel to zoom in/out
+
+        d =  (_event.angleDelta().y()) / 1000.0 * self.radius_
+
+        self.translate([0.0, 0.0, d])
+        self.updateGL()
+        _event.accept()
+
+    def mousePressEvent(self, _event):
+        self.last_point_2D_ = _event.pos()
+        self.last_point_ok_, self.last_point_3D_ = self.map_to_sphere(self.last_point_2D_)
+
+    def mouseMoveEvent(self, _event):
+        newPoint2D = _event.pos()
+
+        if ((newPoint2D.x() < 0) or (newPoint2D.x() > self.width()) or
+                (newPoint2D.y() < 0) or (newPoint2D.y() > self.height())):
+            return
+
+        # Left button: rotate around center_
+        # Middle button: translate object
+        # Left & middle button: zoom in/out
+
+        value_y = 0
+        newPoint_hitSphere, newPoint3D = self.map_to_sphere(newPoint2D)
+
+        dx = float(newPoint2D.x() - self.last_point_2D_.x())
+        dy = float(newPoint2D.y() - self.last_point_2D_.y())
+
+        w  = float(self.width())
+        h  = float(self.height())
+
+        # enable GL context
+        self.makeCurrent()
+
+        # move in z direction
+        if (((_event.buttons() & QtCore.Qt.LeftButton) and (_event.buttons() & QtCore.Qt.MidButton))
+                or (_event.buttons() & QtCore.Qt.LeftButton and _event.modifiers() & QtCore.Qt.ControlModifier)):
+            value_y = self.radius_ * dy * 2.0 / h;
+            self.translate([0.0, 0.0, value_y])
+
+        #rotate
+        elif (_event.buttons() & QtCore.Qt.LeftButton):
+            #左键  旋转
+            if (not self.isInRotation_):
+                self.isInRotation_ = True
+                self.rotationBeginEvent.emit()
+
+            axis = [0.0, 0.0, 0.0]
+            angle = 0.0
+
+            if (self.last_point_ok_ and newPoint_hitSphere):
+                axis = numpy.cross(self.last_point_3D_, newPoint3D)
+                cos_angle = numpy.dot(self.last_point_3D_, newPoint3D)
+                if (abs(cos_angle) < 1.0):
+                    angle = math.acos(cos_angle) * 180.0 / math.pi
+                    angle *= 2.0
+                self.rotate(axis, angle)
+
+        #  move in x,y direction
+        elif (_event.buttons() & QtCore.Qt.MidButton
+              or (_event.buttons() & QtCore.Qt.LeftButton and _event.modifiers() & QtCore.Qt.ShiftModifier)):
+            #中间键移动
+
+            z = - (self.modelview_matrix_[0][2] * self.center_[0] +
+                   self.modelview_matrix_[1][2] * self.center_[1] +
+                   self.modelview_matrix_[2][2] * self.center_[2] +
+                   self.modelview_matrix_[3][2]) / (self.modelview_matrix_[0][3] * self.center_[0] +
+                                                    self.modelview_matrix_[1][3] * self.center_[1] +
+                                                    self.modelview_matrix_[2][3] * self.center_[2] +
+                                                    self.modelview_matrix_[3][3])
+
+            fovy   = 45.0
+            aspect = w / h
+            n      = 0.01 * self.radius_
+            up     = math.tan(fovy / 2.0 * math.pi / 180.0) * n
+            right  = aspect * up
+
+            self.translate( [2.0 * dx / w * right / n * z,
+                             -2.0 * dy / h * up / n * z,
+                             0.0] )
+        # remember this point
+        self.last_point_2D_ = newPoint2D
+        self.last_point_3D_ = newPoint3D
+        self.last_point_ok_ = newPoint_hitSphere
+
+        # trigger redraw
+        self.updateGL()
+
+    def mouseReleaseEvent(self, _event):
+        if (self.isInRotation_):
+            self.isInRotation_ = False
+            self.rotationEndEvent.emit()
+        last_point_ok_ = False
+
+#===============================================================================
+
+
+class PCLViewer(PyGLWidget):
+    def __init__(self):
+        PyGLWidget.__init__(self)
+        GLUT.glutInit()
+        self.points=[]
+    def resetViewer(self):
+        self.reset_view()
+        self.translate([0,0,-5])
+        self.update()
+    def displayPCL(self,points):
+        self.points=points
+        self.update()
+    def drawTrajWithPoint(self, poses, ptsize, color):
+        glPointSize(ptsize)
+        glDepthMask(GL_FALSE)
+        glBegin(GL_POINTS)
+        glColor3f(color[0], color[1], color[2])
+        for pt in poses:
+            [x, y, _] = pt
+            glVertex2d(x, y)
+        glEnd()
+
+    @staticmethod
+    def RotatePoint(point, yaw):
+        [x, y] = point
+        nx = math.cos(yaw) * x - y * math.sin(yaw)
+        ny = x * math.sin(yaw) + y * math.cos(yaw)
+        return [nx, ny]
+    @staticmethod
+    def Transform(point,yaw,dt=None):
+        [x,y]=point
+        nx = math.cos(yaw) * x - y * math.sin(yaw)
+        ny = x * math.sin(yaw) + y * math.cos(yaw)
+        if dt is not None:
+            [dx,dy]=dt
+            nx+=dx
+            ny+=dy
+        return [nx, ny]
+    def DrawText(self,pt,text,width,size,rgb):
+        glDisable(GL_TEXTURE_2D)
+        glLineWidth(width)
+        glPointSize(width)
+        r, g, b = rgb
+        glPushMatrix()
+        glColor3f(r, g, b)
+        glTranslatef(pt[0],pt[1],0)
+        s = size*0.005
+        glScalef(s, s, s)
+        for char in text:
+            GLUT.glutStrokeCharacter(GLUT.GLUT_STROKE_ROMAN, ord(char))
+        glPopMatrix()
+        glEnable(GL_TEXTURE_2D)
+
+    def drawAxis(self, len, width):
+
+        glDepthMask(GL_FALSE)
+        glColor3f(1, 0, 0)
+        glLineWidth(width)
+        glBegin(GL_LINES)
+        glVertex3f(0, 0,0)
+        glVertex3f(len, 0,0)
+        glEnd()
+
+        glColor3f(0, 1, 0)
+        glBegin(GL_LINES)
+        glVertex3f(0, 0,0)
+        glVertex3f(0, len,0)
+        glEnd()
+
+        glColor3f(0, 0, 1)
+        glBegin(GL_LINES)
+        glVertex3f(0, 0,0)
+        glVertex3f(0, 0,len)
+        glEnd()
+
+    def drawPCL(self,points):
+        if len(points)==0:
+            return
+        glPointSize(0.5)
+        glBegin(GL_POINTS)
+
+        for pt in points:
+            [x, y, z,p] = pt
+            if p<0.85:
+                glColor3f(1, 1, 1)
+            else:
+                glColor3f(0, 1, 0)
+            glVertex3f(x, y,z)
+        glEnd()
+
+    def paintGL(self):
+        PyGLWidget.paintGL(self)
+
+        self.drawPCL(self.points)
+
+        self.drawAxis( 1, 2)
+
+
+

+ 63 - 0
Viewer/def.proto

@@ -0,0 +1,63 @@
+syntax = "proto3";
+package JetStream;
+
+message RequestCmd
+{
+  int32 Id=1;  // 对于获取对应id的相机数据。1,2,3,4,其他表示所有
+  //对于打开视频流
+}
+
+message Response{
+  string info=2;
+}
+
+message Image{
+  int32 width=1;
+  int32 height=2;
+  int32 channel=3;
+  bytes data=4;
+}
+
+message PointCloud{
+  int32 size=1;
+  bytes data=2;
+}
+
+message ResImage{
+  Image img1=1;
+  Image img2=2;
+  Image img3=3;
+  Image img4=4;
+}
+message ResCloud{
+  PointCloud cloud1=1;
+  PointCloud cloud2=2;
+  PointCloud cloud3=3;
+  PointCloud cloud4=4;
+}
+message MeasureInfo {
+  float x=1;
+  float y=2;
+  float theta=3;
+  float width=4;
+  float wheelbase=5;
+  float ftheta=6;
+  int32 border=7;
+  string error=8;
+}
+message ResFrame{
+  ResImage images=1;
+  ResCloud clouds=2;
+
+  MeasureInfo measure_info=3;
+}
+
+service StreamServer{
+  rpc OpenImageStream(RequestCmd) returns(stream ResImage){}
+  rpc OpenMeasureDataStream(RequestCmd) returns(stream MeasureInfo){}
+  rpc Detect(RequestCmd) returns(ResFrame){}
+  rpc CloseImageStream(RequestCmd) returns(Response){}
+  rpc CloseMeasureDataStream(RequestCmd) returns(Response){}
+  rpc GetCloud(RequestCmd) returns(ResCloud){}
+  rpc GetImage(RequestCmd) returns(ResImage){}
+}

File diff suppressed because it is too large
+ 42 - 0
Viewer/def_pb2.py


+ 91 - 0
Viewer/def_pb2.pyi

@@ -0,0 +1,91 @@
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from typing import ClassVar as _ClassVar, Mapping as _Mapping, Optional as _Optional, Union as _Union
+
+DESCRIPTOR: _descriptor.FileDescriptor
+
+class RequestCmd(_message.Message):
+    __slots__ = ["Id"]
+    ID_FIELD_NUMBER: _ClassVar[int]
+    Id: int
+    def __init__(self, Id: _Optional[int] = ...) -> None: ...
+
+class Response(_message.Message):
+    __slots__ = ["info"]
+    INFO_FIELD_NUMBER: _ClassVar[int]
+    info: str
+    def __init__(self, info: _Optional[str] = ...) -> None: ...
+
+class Image(_message.Message):
+    __slots__ = ["width", "height", "channel", "data"]
+    WIDTH_FIELD_NUMBER: _ClassVar[int]
+    HEIGHT_FIELD_NUMBER: _ClassVar[int]
+    CHANNEL_FIELD_NUMBER: _ClassVar[int]
+    DATA_FIELD_NUMBER: _ClassVar[int]
+    width: int
+    height: int
+    channel: int
+    data: bytes
+    def __init__(self, width: _Optional[int] = ..., height: _Optional[int] = ..., channel: _Optional[int] = ..., data: _Optional[bytes] = ...) -> None: ...
+
+class PointCloud(_message.Message):
+    __slots__ = ["size", "data"]
+    SIZE_FIELD_NUMBER: _ClassVar[int]
+    DATA_FIELD_NUMBER: _ClassVar[int]
+    size: int
+    data: bytes
+    def __init__(self, size: _Optional[int] = ..., data: _Optional[bytes] = ...) -> None: ...
+
+class ResImage(_message.Message):
+    __slots__ = ["img1", "img2", "img3", "img4"]
+    IMG1_FIELD_NUMBER: _ClassVar[int]
+    IMG2_FIELD_NUMBER: _ClassVar[int]
+    IMG3_FIELD_NUMBER: _ClassVar[int]
+    IMG4_FIELD_NUMBER: _ClassVar[int]
+    img1: Image
+    img2: Image
+    img3: Image
+    img4: Image
+    def __init__(self, img1: _Optional[_Union[Image, _Mapping]] = ..., img2: _Optional[_Union[Image, _Mapping]] = ..., img3: _Optional[_Union[Image, _Mapping]] = ..., img4: _Optional[_Union[Image, _Mapping]] = ...) -> None: ...
+
+class ResCloud(_message.Message):
+    __slots__ = ["cloud1", "cloud2", "cloud3", "cloud4"]
+    CLOUD1_FIELD_NUMBER: _ClassVar[int]
+    CLOUD2_FIELD_NUMBER: _ClassVar[int]
+    CLOUD3_FIELD_NUMBER: _ClassVar[int]
+    CLOUD4_FIELD_NUMBER: _ClassVar[int]
+    cloud1: PointCloud
+    cloud2: PointCloud
+    cloud3: PointCloud
+    cloud4: PointCloud
+    def __init__(self, cloud1: _Optional[_Union[PointCloud, _Mapping]] = ..., cloud2: _Optional[_Union[PointCloud, _Mapping]] = ..., cloud3: _Optional[_Union[PointCloud, _Mapping]] = ..., cloud4: _Optional[_Union[PointCloud, _Mapping]] = ...) -> None: ...
+
+class MeasureInfo(_message.Message):
+    __slots__ = ["x", "y", "theta", "width", "wheelbase", "ftheta", "border", "error"]
+    X_FIELD_NUMBER: _ClassVar[int]
+    Y_FIELD_NUMBER: _ClassVar[int]
+    THETA_FIELD_NUMBER: _ClassVar[int]
+    WIDTH_FIELD_NUMBER: _ClassVar[int]
+    WHEELBASE_FIELD_NUMBER: _ClassVar[int]
+    FTHETA_FIELD_NUMBER: _ClassVar[int]
+    BORDER_FIELD_NUMBER: _ClassVar[int]
+    ERROR_FIELD_NUMBER: _ClassVar[int]
+    x: float
+    y: float
+    theta: float
+    width: float
+    wheelbase: float
+    ftheta: float
+    border: int
+    error: str
+    def __init__(self, x: _Optional[float] = ..., y: _Optional[float] = ..., theta: _Optional[float] = ..., width: _Optional[float] = ..., wheelbase: _Optional[float] = ..., ftheta: _Optional[float] = ..., border: _Optional[int] = ..., error: _Optional[str] = ...) -> None: ...
+
+class ResFrame(_message.Message):
+    __slots__ = ["images", "clouds", "measure_info"]
+    IMAGES_FIELD_NUMBER: _ClassVar[int]
+    CLOUDS_FIELD_NUMBER: _ClassVar[int]
+    MEASURE_INFO_FIELD_NUMBER: _ClassVar[int]
+    images: ResImage
+    clouds: ResCloud
+    measure_info: MeasureInfo
+    def __init__(self, images: _Optional[_Union[ResImage, _Mapping]] = ..., clouds: _Optional[_Union[ResCloud, _Mapping]] = ..., measure_info: _Optional[_Union[MeasureInfo, _Mapping]] = ...) -> None: ...

+ 264 - 0
Viewer/def_pb2_grpc.py

@@ -0,0 +1,264 @@
+# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
+"""Client and server classes corresponding to protobuf-defined services."""
+import grpc
+
+import def_pb2 as def__pb2
+
+
+class StreamServerStub(object):
+    """Missing associated documentation comment in .proto file."""
+
+    def __init__(self, channel):
+        """Constructor.
+
+        Args:
+            channel: A grpc.Channel.
+        """
+        self.OpenImageStream = channel.unary_stream(
+                '/JetStream.StreamServer/OpenImageStream',
+                request_serializer=def__pb2.RequestCmd.SerializeToString,
+                response_deserializer=def__pb2.ResImage.FromString,
+                )
+        self.OpenMeasureDataStream = channel.unary_stream(
+                '/JetStream.StreamServer/OpenMeasureDataStream',
+                request_serializer=def__pb2.RequestCmd.SerializeToString,
+                response_deserializer=def__pb2.MeasureInfo.FromString,
+                )
+        self.Detect = channel.unary_unary(
+                '/JetStream.StreamServer/Detect',
+                request_serializer=def__pb2.RequestCmd.SerializeToString,
+                response_deserializer=def__pb2.ResFrame.FromString,
+                )
+        self.CloseImageStream = channel.unary_unary(
+                '/JetStream.StreamServer/CloseImageStream',
+                request_serializer=def__pb2.RequestCmd.SerializeToString,
+                response_deserializer=def__pb2.Response.FromString,
+                )
+        self.CloseMeasureDataStream = channel.unary_unary(
+                '/JetStream.StreamServer/CloseMeasureDataStream',
+                request_serializer=def__pb2.RequestCmd.SerializeToString,
+                response_deserializer=def__pb2.Response.FromString,
+                )
+        self.GetCloud = channel.unary_unary(
+                '/JetStream.StreamServer/GetCloud',
+                request_serializer=def__pb2.RequestCmd.SerializeToString,
+                response_deserializer=def__pb2.ResCloud.FromString,
+                )
+        self.GetImage = channel.unary_unary(
+                '/JetStream.StreamServer/GetImage',
+                request_serializer=def__pb2.RequestCmd.SerializeToString,
+                response_deserializer=def__pb2.ResImage.FromString,
+                )
+
+
+class StreamServerServicer(object):
+    """Missing associated documentation comment in .proto file."""
+
+    def OpenImageStream(self, request, context):
+        """Missing associated documentation comment in .proto file."""
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
+    def OpenMeasureDataStream(self, request, context):
+        """Missing associated documentation comment in .proto file."""
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
+    def Detect(self, request, context):
+        """Missing associated documentation comment in .proto file."""
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
+    def CloseImageStream(self, request, context):
+        """Missing associated documentation comment in .proto file."""
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
+    def CloseMeasureDataStream(self, request, context):
+        """Missing associated documentation comment in .proto file."""
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
+    def GetCloud(self, request, context):
+        """Missing associated documentation comment in .proto file."""
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
+    def GetImage(self, request, context):
+        """Missing associated documentation comment in .proto file."""
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
+
+def add_StreamServerServicer_to_server(servicer, server):
+    rpc_method_handlers = {
+            'OpenImageStream': grpc.unary_stream_rpc_method_handler(
+                    servicer.OpenImageStream,
+                    request_deserializer=def__pb2.RequestCmd.FromString,
+                    response_serializer=def__pb2.ResImage.SerializeToString,
+            ),
+            'OpenMeasureDataStream': grpc.unary_stream_rpc_method_handler(
+                    servicer.OpenMeasureDataStream,
+                    request_deserializer=def__pb2.RequestCmd.FromString,
+                    response_serializer=def__pb2.MeasureInfo.SerializeToString,
+            ),
+            'Detect': grpc.unary_unary_rpc_method_handler(
+                    servicer.Detect,
+                    request_deserializer=def__pb2.RequestCmd.FromString,
+                    response_serializer=def__pb2.ResFrame.SerializeToString,
+            ),
+            'CloseImageStream': grpc.unary_unary_rpc_method_handler(
+                    servicer.CloseImageStream,
+                    request_deserializer=def__pb2.RequestCmd.FromString,
+                    response_serializer=def__pb2.Response.SerializeToString,
+            ),
+            'CloseMeasureDataStream': grpc.unary_unary_rpc_method_handler(
+                    servicer.CloseMeasureDataStream,
+                    request_deserializer=def__pb2.RequestCmd.FromString,
+                    response_serializer=def__pb2.Response.SerializeToString,
+            ),
+            'GetCloud': grpc.unary_unary_rpc_method_handler(
+                    servicer.GetCloud,
+                    request_deserializer=def__pb2.RequestCmd.FromString,
+                    response_serializer=def__pb2.ResCloud.SerializeToString,
+            ),
+            'GetImage': grpc.unary_unary_rpc_method_handler(
+                    servicer.GetImage,
+                    request_deserializer=def__pb2.RequestCmd.FromString,
+                    response_serializer=def__pb2.ResImage.SerializeToString,
+            ),
+    }
+    generic_handler = grpc.method_handlers_generic_handler(
+            'JetStream.StreamServer', rpc_method_handlers)
+    server.add_generic_rpc_handlers((generic_handler,))
+
+
+ # This class is part of an EXPERIMENTAL API.
+class StreamServer(object):
+    """Missing associated documentation comment in .proto file."""
+
+    @staticmethod
+    def OpenImageStream(request,
+            target,
+            options=(),
+            channel_credentials=None,
+            call_credentials=None,
+            insecure=False,
+            compression=None,
+            wait_for_ready=None,
+            timeout=None,
+            metadata=None):
+        return grpc.experimental.unary_stream(request, target, '/JetStream.StreamServer/OpenImageStream',
+            def__pb2.RequestCmd.SerializeToString,
+            def__pb2.ResImage.FromString,
+            options, channel_credentials,
+            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+    @staticmethod
+    def OpenMeasureDataStream(request,
+            target,
+            options=(),
+            channel_credentials=None,
+            call_credentials=None,
+            insecure=False,
+            compression=None,
+            wait_for_ready=None,
+            timeout=None,
+            metadata=None):
+        return grpc.experimental.unary_stream(request, target, '/JetStream.StreamServer/OpenMeasureDataStream',
+            def__pb2.RequestCmd.SerializeToString,
+            def__pb2.MeasureInfo.FromString,
+            options, channel_credentials,
+            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+    @staticmethod
+    def Detect(request,
+            target,
+            options=(),
+            channel_credentials=None,
+            call_credentials=None,
+            insecure=False,
+            compression=None,
+            wait_for_ready=None,
+            timeout=None,
+            metadata=None):
+        return grpc.experimental.unary_unary(request, target, '/JetStream.StreamServer/Detect',
+            def__pb2.RequestCmd.SerializeToString,
+            def__pb2.ResFrame.FromString,
+            options, channel_credentials,
+            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+    @staticmethod
+    def CloseImageStream(request,
+            target,
+            options=(),
+            channel_credentials=None,
+            call_credentials=None,
+            insecure=False,
+            compression=None,
+            wait_for_ready=None,
+            timeout=None,
+            metadata=None):
+        return grpc.experimental.unary_unary(request, target, '/JetStream.StreamServer/CloseImageStream',
+            def__pb2.RequestCmd.SerializeToString,
+            def__pb2.Response.FromString,
+            options, channel_credentials,
+            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+    @staticmethod
+    def CloseMeasureDataStream(request,
+            target,
+            options=(),
+            channel_credentials=None,
+            call_credentials=None,
+            insecure=False,
+            compression=None,
+            wait_for_ready=None,
+            timeout=None,
+            metadata=None):
+        return grpc.experimental.unary_unary(request, target, '/JetStream.StreamServer/CloseMeasureDataStream',
+            def__pb2.RequestCmd.SerializeToString,
+            def__pb2.Response.FromString,
+            options, channel_credentials,
+            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+    @staticmethod
+    def GetCloud(request,
+            target,
+            options=(),
+            channel_credentials=None,
+            call_credentials=None,
+            insecure=False,
+            compression=None,
+            wait_for_ready=None,
+            timeout=None,
+            metadata=None):
+        return grpc.experimental.unary_unary(request, target, '/JetStream.StreamServer/GetCloud',
+            def__pb2.RequestCmd.SerializeToString,
+            def__pb2.ResCloud.FromString,
+            options, channel_credentials,
+            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+    @staticmethod
+    def GetImage(request,
+            target,
+            options=(),
+            channel_credentials=None,
+            call_credentials=None,
+            insecure=False,
+            compression=None,
+            wait_for_ready=None,
+            timeout=None,
+            metadata=None):
+        return grpc.experimental.unary_unary(request, target, '/JetStream.StreamServer/GetImage',
+            def__pb2.RequestCmd.SerializeToString,
+            def__pb2.ResImage.FromString,
+            options, channel_credentials,
+            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)

+ 22 - 0
Viewer/main.py

@@ -0,0 +1,22 @@
+
+import sys
+from PyQt5.QtWidgets import QWidget, QApplication,QMainWindow,QLabel
+from PyQt5.QtCore import Qt
+import MainWnd as mw
+import GrpcClient as Stream
+
+ip='192.168.2.45'
+port=9876
+
+if __name__=="__main__":
+
+    app = QApplication(sys.argv)
+    win = mw.MainWindow()
+    win.show()
+
+    stream=Stream.GrpcStream()
+    stream.SetDataCallBack(win.OnImagesHandle,win.OnCloudHandle,win.OnMeasureDataHandle)
+    stream.start()
+    sys.exit(app.exec_())
+
+

+ 1 - 0
Viewer/proto.sh

@@ -0,0 +1 @@
+python -m grpc_tools.protoc -I. --python_out=. --pyi_out=. --grpc_python_out=. def.proto