CustomFrame.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. from PyQt5.QtWidgets import (QWidget,QVBoxLayout,QTabWidget,QSplitter, QFileDialog,
  2. QLineEdit,QCheckBox,QLabel,QFrame,QPushButton,QMenu,QAction)
  3. from PyQt5.QtGui import QPixmap,QImage,QPainter,QResizeEvent,QCloseEvent,QPaintEvent
  4. from PyQt5.QtCore import QSize,QTimer,QRect,Qt
  5. import numpy as np
  6. import def_pb2 as pb
  7. from concurrent.futures import ThreadPoolExecutor, as_completed, wait
  8. import GrpcClient as rpc
  9. import vtk
  10. from vtkmodules.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
  11. #from vtk.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
  12. import threading
  13. class ControlFrame(QFrame):
  14. def __init__(self):
  15. QFrame.__init__(self)
  16. self.threadPool_ = ThreadPoolExecutor(5)
  17. self.setGeometry(0, 0, 500, 500)
  18. self.InitUI()
  19. self.setFrameShape(self.StyledPanel)
  20. #self.timer_ = QTimer()
  21. #self.timer_.timeout.connect(self.Update)
  22. #self.timer_.start(100)
  23. def DisplayMeasureInfo(self,info : pb.MeasureInfo):
  24. self.ErrorInfo.setText(info.error)
  25. def OnAction(self,dtype,id):
  26. client=rpc.GrpcStream()
  27. ip=self.IPEdit.text()
  28. port=int(self.PortEdit.text())
  29. if dtype==1:
  30. self.threadPool_.submit(client.GrabImage,ip,port,id)
  31. if dtype==2:
  32. self.threadPool_.submit(client.GrabCloud,ip,port,id)
  33. def InitUI(self):
  34. self.begstatic = QLabel(self)
  35. self.begstatic.setText(" IP:")
  36. self.begstatic.setGeometry(20, 5, 80, 30)
  37. self.IPEdit = QLineEdit(self)
  38. self.IPEdit.setText("192.168.2.45")
  39. self.IPEdit.setGeometry(90, 5, 150, 30)
  40. self.endstatic = QLabel(self)
  41. self.endstatic.setText("Port:")
  42. self.endstatic.setGeometry(20, 50, 80, 30)
  43. self.PortEdit = QLineEdit(self)
  44. self.PortEdit.setText("9876")
  45. self.PortEdit.setGeometry(90, 50, 150, 30)
  46. self.btnGrab = QPushButton(self)
  47. self.btnGrab.setGeometry(20, 140, 100, 40)
  48. self.btnGrab.setText("抓取图像")
  49. self.btnGrab.clicked.connect(self.btnGrabImageClick)
  50. self.btnCancel = QPushButton(self)
  51. self.btnCancel.setGeometry(150, 140, 100, 40)
  52. self.btnCancel.setText("抓取点云")
  53. self.btnCancel.clicked.connect(self.btnGrabCloudClick)
  54. self.btnImageStreamCheck = QCheckBox("实时图像", self)
  55. self.btnImageStreamCheck.setGeometry(20, 90, 120, 40)
  56. self.btnImageStreamCheck.clicked.connect(self.RealTimeImagecb)
  57. self.btnDataStreamCheck = QCheckBox("实时结果打印", self)
  58. self.btnDataStreamCheck.setGeometry(150, 90, 120, 40)
  59. self.btnDataStreamCheck.clicked.connect(self.RealTimeDatacb)
  60. self.ErrorInfo = QLabel(self)
  61. self.ErrorInfo.setGeometry(20, 200, 250, 400)
  62. self.ErrorInfo.setWordWrap(True)
  63. self.ErrorInfo.setAlignment(Qt.AlignTop)
  64. def RealTimeDatacb(self):
  65. if self.btnDataStreamCheck.checkState()==Qt.Checked:
  66. client=rpc.GrpcStream()
  67. ip=self.IPEdit.text()
  68. port=int(self.PortEdit.text())
  69. self.threadPool_.submit(client.OpenDataStream,ip,port)
  70. else:
  71. client=rpc.GrpcStream()
  72. ip=self.IPEdit.text()
  73. port=int(self.PortEdit.text())
  74. self.threadPool_.submit(client.CloseDataStream,ip,port)
  75. def RealTimeImagecb(self):
  76. if self.btnImageStreamCheck.checkState()==Qt.Checked:
  77. self.btnGrab.setEnabled(False)
  78. client=rpc.GrpcStream()
  79. ip=self.IPEdit.text()
  80. port=int(self.PortEdit.text())
  81. self.threadPool_.submit(client.OpenImageStream,ip,port)
  82. else:
  83. self.btnGrab.setEnabled(True)
  84. client=rpc.GrpcStream()
  85. ip=self.IPEdit.text()
  86. port=int(self.PortEdit.text())
  87. self.threadPool_.submit(client.CloseImageStream,ip,port)
  88. def closeEvent(self, a0: QCloseEvent) -> None:
  89. if self.btnImageStreamCheck.checkState()==Qt.Checked:
  90. client=rpc.GrpcStream()
  91. ip=self.IPEdit.text()
  92. port=int(self.PortEdit.text())
  93. self.threadPool_.submit(client.CloseImageStream,ip,port)
  94. if self.btnDataStreamCheck.checkState()==Qt.Checked:
  95. client=rpc.GrpcStream()
  96. ip=self.IPEdit.text()
  97. port=int(self.PortEdit.text())
  98. self.threadPool_.submit(client.CloseDataStream,ip,port)
  99. self.threadPool_.shutdown(wait=False)
  100. rpc.GrpcStream().close()
  101. def btnGrabImageClick(self):
  102. if self.btnImageStreamCheck.checkState()==Qt.Checked:
  103. print(" 先关闭实时显示")
  104. else :
  105. client=rpc.GrpcStream()
  106. ip=self.IPEdit.text()
  107. port=int(self.PortEdit.text())
  108. self.threadPool_.submit(client.GrabImage,ip,port,0)
  109. def btnGrabCloudClick(self):
  110. client=rpc.GrpcStream()
  111. ip=self.IPEdit.text()
  112. port=int(self.PortEdit.text())
  113. for id in range(4):
  114. self.threadPool_.submit(client.GrabCloud,ip,port,id+1)
  115. def btnCancelClick(self):
  116. pass
  117. class ImageViewer(QLabel):
  118. def __init__(self,parent,OnAction,id):
  119. super(ImageViewer,self).__init__(parent=parent)
  120. self.OnAction=OnAction
  121. self.dtype=1
  122. self.id=id
  123. self.image=None
  124. self.show = False
  125. self.setStyleSheet("border-width:1px;border-style:solid;border-color:rgb(150,150,150)")
  126. def ShowImg(self,pixmap):
  127. self.show=True
  128. self.image=pixmap
  129. self.update()
  130. def updataData(self):
  131. self.OnAction(self.dtype,self.id)
  132. print("%d,%d"%(self.dtype,self.id))
  133. def contextMenuEvent(self, a0):
  134. menu=QMenu(self)
  135. updata_act=QAction("更新")
  136. updata_act.triggered.connect(self.updataData)
  137. menu.addAction(updata_act)
  138. ret=menu.exec_(a0.globalPos())
  139. def paintEvent(self, a0: QPaintEvent) -> None:
  140. if not self.image == None:
  141. w, h = self.size().width(),self.size().height()
  142. iw, ih = self.image.width(), self.image.height()
  143. painter=QPainter(self)
  144. painter.drawPixmap(QRect(0,0,w,h),self.image,QRect(0,0,iw,ih))
  145. class VtkPointCloud:
  146. def __init__(self, zMin=-10.0, zMax=10.0, maxNumPoints=1e7):
  147. self.maxNumPoints = maxNumPoints
  148. self.vtkPolyData = vtk.vtkPolyData()
  149. self.clearPoints()
  150. mapper = vtk.vtkPolyDataMapper()
  151. mapper.SetInputData(self.vtkPolyData)
  152. mapper.SetColorModeToDefault()
  153. mapper.SetScalarRange(zMin, zMax)
  154. mapper.SetScalarVisibility(1)
  155. self.vtkActor = vtk.vtkActor()
  156. self.vtkActor.SetMapper(mapper)
  157. self.vtkActor.GetProperty().SetPointSize(1)
  158. self.vtkActor.GetProperty().SetColor(1, 1, 1)
  159. def addPoint(self, point):
  160. if self.vtkPoints.GetNumberOfPoints() < self.maxNumPoints:
  161. pointId = self.vtkPoints.InsertNextPoint(point[0:-1])
  162. self.vtkDepth.InsertNextValue(point[2])
  163. self.vtkCells.InsertNextCell(1)
  164. self.vtkCells.InsertCellPoint(pointId)
  165. self.vtkCells.Modified()
  166. self.vtkPoints.Modified()
  167. self.vtkDepth.Modified()
  168. def clearPoints(self):
  169. self.vtkPoints = vtk.vtkPoints()
  170. self.vtkCells = vtk.vtkCellArray()
  171. self.vtkDepth = vtk.vtkDoubleArray()
  172. self.vtkDepth.SetName('DepthArray')
  173. self.vtkPolyData.SetPoints(self.vtkPoints)
  174. self.vtkPolyData.SetVerts(self.vtkCells)
  175. #self.vtkPolyData.GetPointData().SetScalars(self.vtkDepth)
  176. self.vtkPolyData.GetPointData().SetActiveScalars('DepthArray')
  177. class pclViewer(QVTKRenderWindowInteractor):
  178. def __init__(self,parent=None):
  179. super(pclViewer,self).__init__(parent=parent)
  180. def mousePressEvent(self, ev):
  181. btn = ev.button()
  182. if btn == Qt.RightButton:
  183. print(" r btn")
  184. else:
  185. QVTKRenderWindowInteractor.mousePressEvent(self,ev)
  186. class VtkPointCloudCanvas(QWidget):
  187. def __init__(self, *args, **kwargs):
  188. super(VtkPointCloudCanvas, self).__init__(*args, **kwargs)
  189. self.lock_=threading.RLock()
  190. self._layout = QVBoxLayout()
  191. self.setLayout(self._layout)
  192. self._vtk_widget = pclViewer(self)
  193. self._vtk_widget.SetInteractorStyle(vtk.vtkInteractorStyleTrackballCamera()) # 设置交互方式==常用的方式 移动摄像机
  194. self._layout.addWidget(self._vtk_widget)
  195. self._render = vtk.vtkRenderer()
  196. self._vtk_widget.GetRenderWindow().AddRenderer(self._render)
  197. self._iren = self._vtk_widget.GetRenderWindow().GetInteractor()
  198. self._point_cloud = VtkPointCloud()
  199. self._render.AddActor(self._point_cloud.vtkActor)
  200. transform = vtk.vtkTransform()
  201. transform.Translate(0, 0.0, 0.0)
  202. axes = vtk.vtkAxesActor()
  203. axes.SetUserTransform(transform)
  204. colors = vtk.vtkNamedColors()
  205. axes.GetXAxisCaptionActor2D().GetCaptionTextProperty().SetColor(colors.GetColor3d("Red"))
  206. axes.GetYAxisCaptionActor2D().GetCaptionTextProperty().SetColor(colors.GetColor3d("Green"))
  207. axes.GetZAxisCaptionActor2D().GetCaptionTextProperty().SetColor(colors.GetColor3d("Blue"))
  208. self._render.AddActor(axes)
  209. self.camera=self._render.GetActiveCamera()
  210. self.show()
  211. self._iren.Initialize()
  212. def close(self) -> bool:
  213. print(" tk close")
  214. self._point_cloud.clearPoints()
  215. def displayPCL(self,cloud:np.array):
  216. colors = vtk.vtkUnsignedCharArray()
  217. colors.SetNumberOfComponents(3)
  218. colors.SetName("Colors")
  219. self._point_cloud.clearPoints()
  220. for point in cloud:
  221. self._point_cloud.addPoint(point)
  222. prob=point[-1]
  223. colors.InsertNextTypedTuple((int(255*prob),int(255-prob*255),255-int(prob*255)))
  224. self._point_cloud.vtkPolyData.GetPointData().SetScalars(colors)
  225. self._vtk_widget.update()
  226. def resetViewer(self):
  227. self.update()
  228. class PointCLViwer(QSplitter):
  229. def __init__(self,OnAction,id):
  230. super(PointCLViwer, self).__init__()
  231. self.OnAction=OnAction
  232. self.dtype=2
  233. self.id=id
  234. self.pointCloud=[]
  235. self.InitUI()
  236. def InitUI(self):
  237. self.pclViewer=VtkPointCloudCanvas(self)
  238. self.addWidget(self.pclViewer)
  239. self.setStretchFactor(0,4)
  240. def save(self):
  241. fileName2, ok2 = QFileDialog.getSaveFileName(self, "文件保存", "C:/","All Files (*);;Text Files (*.txt)")
  242. print(fileName2 ,ok2)
  243. with open(fileName2,"w+") as f:
  244. for point in self.pointCloud:
  245. prob=point[3]
  246. f.write("%f %f %f %d %d %d\n"%(point[0],point[1],point[2],int(255*prob),int(255-prob*255),255-int(prob*255)))
  247. print("Save Cloud to %s"%(fileName2))
  248. def displayCloud(self,points:np.array):
  249. self.pointCloud=points
  250. self.pclViewer.displayPCL(points)
  251. def resetViewer(self):
  252. self.pclViewer.resetViewer()
  253. def updataData(self):
  254. self.OnAction(self.dtype,self.id)
  255. def contextMenuEvent(self, a0):
  256. menu=QMenu(self)
  257. updata_act=QAction("更新点云")
  258. updata_act.triggered.connect(self.updataData)
  259. menu.addAction(updata_act)
  260. #act=QAction("还原视野")
  261. #act.triggered.connect(self.resetViewer)
  262. #menu.addAction(act)
  263. actSave=QAction("保存")
  264. actSave.triggered.connect(self.save)
  265. menu.addAction(actSave)
  266. ret=menu.exec_(a0.globalPos())
  267. class ViewerFrame(QFrame):
  268. def __init__(self,OnAction):
  269. super(ViewerFrame, self).__init__()
  270. self.OnAction=OnAction
  271. self.InitUI()
  272. def InitUI(self):
  273. self.table1=QTabWidget(self)
  274. self.table2=QTabWidget(self)
  275. self.table3=QTabWidget(self)
  276. self.table4=QTabWidget(self)
  277. self.table1.setTabPosition(QTabWidget.TabPosition.North)
  278. self.table2.setTabPosition(QTabWidget.TabPosition.North)
  279. self.table3.setTabPosition(QTabWidget.TabPosition.North)
  280. self.table4.setTabPosition(QTabWidget.TabPosition.North)
  281. self.panel1=ImageViewer(self,self.OnAction,1)
  282. self.panel2=ImageViewer(self,self.OnAction,2)
  283. self.panel3=ImageViewer(self,self.OnAction,3)
  284. self.panel4=ImageViewer(self,self.OnAction,4)
  285. self.pcViewer1=PointCLViwer(self.OnAction,1)
  286. self.pcViewer2=PointCLViwer(self.OnAction,2)
  287. self.pcViewer3=PointCLViwer(self.OnAction,3)
  288. self.pcViewer4=PointCLViwer(self.OnAction,4)
  289. self.table1.addTab(self.panel1,"图像")
  290. self.table1.addTab(self.pcViewer1,"点云")
  291. self.table2.addTab(self.panel2,"图像")
  292. self.table2.addTab(self.pcViewer2,"点云")
  293. self.table3.addTab(self.panel3,"图像")
  294. self.table3.addTab(self.pcViewer3,"点云")
  295. self.table4.addTab(self.panel4,"图像")
  296. self.table4.addTab(self.pcViewer4,"点云")
  297. def closeEvent(self, a0: QCloseEvent) -> None:
  298. pass
  299. def resizeEvent(self, a0: QResizeEvent) -> None:
  300. w, h = self.size().width(), self.size().height()
  301. w=w-15
  302. h=h-15
  303. self.table1.setGeometry(5, 5, w/2, h/2)
  304. self.table2.setGeometry(10+w/2, 5, w/2, h/2)
  305. self.table3.setGeometry(5, 10+h/2, w/2, h/2)
  306. self.table4.setGeometry(10+w/2, 10+h/2, w/2, h/2)
  307. def PbImg2QPix(self,image:pb.Image):
  308. img1=image
  309. w=img1.width
  310. h=img1.height
  311. c=img1.channel
  312. btarry=bytearray(img1.data)
  313. npdata = np.frombuffer(btarry, dtype=np.uint8)
  314. if c==3:
  315. npdata = npdata.reshape([h,w,c])
  316. qimg=QImage(npdata.data,w,h,QImage.Format_RGB888)
  317. if c==1:
  318. npdata = npdata.reshape([h,w])
  319. qimg=QImage(npdata.data,w,h,QImage.Format_Grayscale8)
  320. pix=QPixmap(qimg)
  321. return pix
  322. def PbCloud2Pts(self,cloud:pb.PointCloud):
  323. size=cloud.size
  324. btarry=bytearray(cloud.data)
  325. npdata = np.frombuffer(btarry, dtype=np.short)
  326. points= npdata.reshape([size,4])/32750.0 *5.0
  327. return points
  328. def DisplayFrame(self,frame : pb.ResFrame):
  329. if frame.HasField("images"):
  330. self.DisplayImage(frame.images)
  331. if frame.HasField("clouds"):
  332. self.DisplayCloud(frame.clouds)
  333. def DisplayImage(self,images:pb.ResImage):
  334. if images.HasField("img1"):
  335. self.panel1.ShowImg(self.PbImg2QPix(images.img1))
  336. if images.HasField("img2"):
  337. self.panel2.ShowImg(self.PbImg2QPix(images.img2))
  338. if images.HasField("img3"):
  339. self.panel3.ShowImg(self.PbImg2QPix(images.img3))
  340. if images.HasField("img4"):
  341. self.panel4.ShowImg(self.PbImg2QPix(images.img4))
  342. def DisplayCloud(self,clouds:pb.ResCloud):
  343. if clouds.HasField("cloud1"):
  344. self.pcViewer1.displayCloud(self.PbCloud2Pts(clouds.cloud1))
  345. if clouds.HasField("cloud2"):
  346. self.pcViewer2.displayCloud(self.PbCloud2Pts(clouds.cloud2))
  347. if clouds.HasField("cloud3"):
  348. self.pcViewer3.displayCloud(self.PbCloud2Pts(clouds.cloud3))
  349. if clouds.HasField("cloud4"):
  350. self.pcViewer4.displayCloud(self.PbCloud2Pts(clouds.cloud4))