CustomFrame.py 15 KB

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