CustomFrame.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626
  1. import os
  2. import subprocess
  3. from PyQt5.QtWidgets import (QWidget,QVBoxLayout,QTabWidget,QSplitter, QFileDialog,QMessageBox,QComboBox,
  4. QLineEdit,QTextEdit,QCheckBox,QLabel,QFrame,QPushButton,QMenu,QAction)
  5. from PyQt5.QtGui import QPixmap,QImage,QPainter,QResizeEvent,QCloseEvent,QPaintEvent
  6. from PyQt5.QtCore import QRect,Qt
  7. import numpy as np
  8. import math
  9. import def_pb2 as pb
  10. import GrpcClient as rpc
  11. import vtk
  12. import cv2
  13. import time
  14. import google.protobuf.text_format as tf
  15. from vtkmodules.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
  16. #from vtk.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
  17. import threading
  18. class ControlFrame(QFrame):
  19. cameraMap={"相机1":0,"相机2":1,"相机3":2,"相机4":3}
  20. def __init__(self):
  21. QFrame.__init__(self)
  22. self.setGeometry(0, 0, 500, 500)
  23. self.images_=pb.ResImage()
  24. self.InitUI()
  25. self.setFrameShape(self.StyledPanel)
  26. #self.timer_ = QTimer()
  27. #self.timer_.timeout.connect(self.Update)
  28. #self.timer_.start(100)
  29. def OnImages(self,images:pb.ResImage):
  30. self.images_=images
  31. def DisplayMeasureInfo(self,info : pb.MeasureInfo):
  32. xstr="x\t: %.3f\n"%(info.x) if info.HasField("x") else "x\t: None\n"
  33. ystr="y\t: %.3f\n"%(info.y) if info.HasField("y") else "y\t: None\n"
  34. thetastr="角度\t: %.3f\n"%(info.theta*180.0/np.pi) if info.HasField("theta") else "角度\t: None\n"
  35. widthstr="宽\t: %.3f\n"%(info.width) if info.HasField("width") else "宽\t: None\n"
  36. wheelbasestr="轴距\t: %.3f\n"%(info.wheelbase) if info.HasField("wheelbase") else "轴距\t: None\n"
  37. fthetastr="前轮角\t: %.3f\n"%(info.ftheta*180.0/np.pi) if info.HasField("ftheta") else "前轮角\t: None\n"
  38. error=info.error
  39. self.ErrorInfo.setText(xstr+ystr+thetastr+widthstr+wheelbasestr+fthetastr+error)
  40. def OnAction(self,dtype,id):
  41. client=rpc.GrpcStream()
  42. ip=self.IPEdit.text()
  43. port=int(self.PortEdit.text())
  44. try:
  45. if dtype==1:
  46. client.GrabImage(ip,port,id)
  47. if dtype==2:
  48. client.GrabCloud(ip,port,id)
  49. except Exception as e:
  50. QMessageBox.information(self, 'ERROR',str(e),QMessageBox.Ok,QMessageBox.Ok)
  51. def InitUI(self):
  52. self.begstatic = QLabel(self)
  53. self.begstatic.setText(" IP:")
  54. self.begstatic.setGeometry(20, 5, 80, 25)
  55. self.IPEdit = QLineEdit(self)
  56. self.IPEdit.setText("10.211.31.16")
  57. self.IPEdit.setGeometry(90, 5, 150, 25)
  58. self.endstatic = QLabel(self)
  59. self.endstatic.setText("Port:")
  60. self.endstatic.setGeometry(20, 35, 80, 25)
  61. self.PortEdit = QLineEdit(self)
  62. self.PortEdit.setText("9876")
  63. self.PortEdit.setGeometry(90, 35, 150, 25)
  64. self.btnImageStreamCheck = QCheckBox("实时图像", self)
  65. self.btnImageStreamCheck.setGeometry(20, 65, 120, 30)
  66. self.btnImageStreamCheck.clicked.connect(self.RealTimeImagecb)
  67. self.btnDataStreamCheck = QCheckBox("实时结果打印", self)
  68. self.btnDataStreamCheck.setGeometry(150, 65, 120, 30)
  69. self.btnDataStreamCheck.clicked.connect(self.RealTimeDatacb)
  70. self.btnGrab = QPushButton(self)
  71. self.btnGrab.setGeometry(20, 100, 100, 40)
  72. self.btnGrab.setText("抓取图像")
  73. self.btnGrab.clicked.connect(self.btnGrabImageClick)
  74. self.btnCancel = QPushButton(self)
  75. self.btnCancel.setGeometry(150, 100, 100, 30)
  76. self.btnCancel.setText("抓取点云")
  77. self.btnCancel.clicked.connect(self.btnGrabCloudClick)
  78. self.btnMergeSave = QPushButton(self)
  79. self.btnMergeSave.setGeometry(20, 160, 100, 40)
  80. self.btnMergeSave.setText("拼接保存")
  81. self.btnMergeSave.clicked.connect(self.btnMergeSaveClick)
  82. self.btnSaveAllCloud = QPushButton(self)
  83. self.btnSaveAllCloud.setGeometry(150, 135, 100, 30)
  84. self.btnSaveAllCloud.setText("合并保存点云")
  85. self.btnSaveWheelSampleCloud = QPushButton(self)
  86. self.btnSaveWheelSampleCloud.setGeometry(150, 170, 100, 30)
  87. self.btnSaveWheelSampleCloud.setText("保存轮胎样本")
  88. self.ParameterEdit = QTextEdit(self)
  89. self.ParameterEdit.setText("")
  90. self.ParameterEdit.setGeometry(20, 300, 130, 150)
  91. self.MatrixEdit = QTextEdit(self)
  92. self.MatrixEdit.setAlignment(Qt.AlignTop)
  93. self.MatrixEdit.setText("输入4x4变换矩阵")
  94. self.MatrixEdit.setGeometry(20, 205, 500, 90)
  95. self.MatrixEdit.textChanged.connect(self.matrix2rpy)
  96. self.CameraListEdit=QComboBox(self)
  97. self.CameraListEdit.addItems(self.cameraMap.keys())
  98. self.CameraListEdit.setGeometry(155, 300, 100, 30)
  99. self.btnChange = QPushButton(self)
  100. self.btnChange.setGeometry(155, 350, 100, 40)
  101. self.btnChange.setText("修改参数")
  102. self.btnChange.clicked.connect(self.ChangeCameraParameter)
  103. self.btnSave = QPushButton(self)
  104. self.btnSave.setGeometry(155, 410, 100, 40)
  105. self.btnSave.setText("写入参数")
  106. self.btnSave.clicked.connect(self.SaveCameraParameter)
  107. self.ErrorInfo = QLabel(self)
  108. self.ErrorInfo.setGeometry(20, 455, 250, 400)
  109. self.ErrorInfo.setWordWrap(True)
  110. self.ErrorInfo.setAlignment(Qt.AlignTop)
  111. def RealTimeDatacb(self):
  112. try:
  113. if self.btnDataStreamCheck.checkState()==Qt.Checked:
  114. client=rpc.GrpcStream()
  115. ip=self.IPEdit.text()
  116. port=int(self.PortEdit.text())
  117. client.OpenDataStream(ip,port)
  118. else:
  119. client=rpc.GrpcStream()
  120. ip=self.IPEdit.text()
  121. port=int(self.PortEdit.text())
  122. client.CloseDataStream(ip,port)
  123. except Exception as e:
  124. QMessageBox.information(self, 'ERROR',str(e),QMessageBox.Ok,QMessageBox.Ok)
  125. def RealTimeImagecb(self):
  126. try:
  127. if self.btnImageStreamCheck.checkState()==Qt.Checked:
  128. self.btnGrab.setEnabled(False)
  129. client=rpc.GrpcStream()
  130. ip=self.IPEdit.text()
  131. port=int(self.PortEdit.text())
  132. client.OpenImageStream(ip,port)
  133. else:
  134. self.btnGrab.setEnabled(True)
  135. client=rpc.GrpcStream()
  136. ip=self.IPEdit.text()
  137. port=int(self.PortEdit.text())
  138. client.CloseImageStream(ip,port)
  139. except Exception as e:
  140. QMessageBox.information(self, 'ERROR',str(e),QMessageBox.Ok,QMessageBox.Ok)
  141. def closeEvent(self, a0: QCloseEvent) -> None:
  142. if self.btnImageStreamCheck.checkState()==Qt.Checked:
  143. client=rpc.GrpcStream()
  144. ip=self.IPEdit.text()
  145. port=int(self.PortEdit.text())
  146. client.CloseImageStream(ip,port)
  147. if self.btnDataStreamCheck.checkState()==Qt.Checked:
  148. client=rpc.GrpcStream()
  149. ip=self.IPEdit.text()
  150. port=int(self.PortEdit.text())
  151. client.CloseDataStream(ip,port)
  152. rpc.GrpcStream().close()
  153. def btnGrabImageClick(self):
  154. if self.btnImageStreamCheck.checkState()==Qt.Checked:
  155. print(" 先关闭实时显示")
  156. else :
  157. client=rpc.GrpcStream()
  158. ip=self.IPEdit.text()
  159. port=int(self.PortEdit.text())
  160. try:
  161. client.GrabImage(ip,port,-1)
  162. except Exception as e:
  163. QMessageBox.information(self, 'ERROR',str(e),QMessageBox.Ok,QMessageBox.Ok)
  164. def btnMergeSaveClick(self):
  165. #
  166. if self.images_.HasField("img1") and self.images_.HasField("img2")\
  167. and self.images_.HasField("img3") and self.images_.HasField("img4"):
  168. img1=self.PbImg2numpy(self.images_.img1)
  169. img2=self.PbImg2numpy(self.images_.img2)
  170. img3=self.PbImg2numpy(self.images_.img3)
  171. img4=self.PbImg2numpy(self.images_.img4)
  172. img_up=np.concatenate([img1,img2],axis=1)
  173. img_down=np.concatenate([img3,img4],axis=1)
  174. image=np.concatenate([img_up,img_down],axis=0)
  175. file=time.strftime("%Y%m%d-%H%M%S")+'.jpg'
  176. cv2.imwrite("./images/"+file,image)
  177. else:
  178. print(" ---------------")
  179. def PbImg2numpy(self,image:pb.Image):
  180. img1=image
  181. w=img1.width
  182. h=img1.height
  183. c=img1.channel
  184. btarry=bytearray(img1.data)
  185. npdata = np.frombuffer(btarry, dtype=np.uint8)
  186. if c==3:
  187. npdata = npdata.reshape([h,w,c])
  188. if c==1:
  189. npdata = npdata.reshape([h,w])
  190. return npdata
  191. def btnGrabCloudClick(self):
  192. client=rpc.GrpcStream()
  193. ip=self.IPEdit.text()
  194. port=int(self.PortEdit.text())
  195. try:
  196. for id in range(4):
  197. client.GrabCloud(ip,port,id)
  198. except Exception as e:
  199. QMessageBox.information(self, 'ERROR',str(e),QMessageBox.Ok,QMessageBox.Ok)
  200. def rotationMatrixToEulerAngles(self,R) :
  201. sy = math.sqrt(R[0,0] * R[0,0] + R[1,0] * R[1,0])
  202. singular = sy < 1e-6
  203. if not singular :
  204. x = math.atan2(R[2,1] , R[2,2])
  205. y = math.atan2(-R[2,0], sy)
  206. z = math.atan2(R[1,0], R[0,0])
  207. else :
  208. x = math.atan2(-R[1,2], R[1,1])
  209. y = math.atan2(-R[2,0], sy)
  210. z = 0
  211. return np.array([x, y, z])
  212. def SaveCameraParameter(self):
  213. self.btnSave.setEnabled(False)
  214. camera=self.CameraListEdit.currentText()
  215. id=self.cameraMap[camera]
  216. text=self.ParameterEdit.toPlainText()
  217. transform=pb.CoordinateTransformation3D()
  218. try:
  219. tf.Parse(text, transform)
  220. except:
  221. QMessageBox.information(self, '格式错误',text,QMessageBox.Ok,QMessageBox.Ok)
  222. self.btnSave.setEnabled(True)
  223. print(" 保存相机%d参数:%s"%(id,transform))
  224. client=rpc.GrpcStream()
  225. ip=self.IPEdit.text()
  226. port=int(self.PortEdit.text())
  227. try:
  228. ret=client.SaveCameraParameter(ip,port,id,transform)
  229. QMessageBox.information(self, 'Info',ret.info,QMessageBox.Ok,QMessageBox.Ok)
  230. except Exception as e:
  231. QMessageBox.information(self, 'Info',str(e),QMessageBox.Ok,QMessageBox.Ok)
  232. self.btnSave.setEnabled(True)
  233. def ChangeCameraParameter(self):
  234. self.btnChange.setEnabled(False)
  235. camera=self.CameraListEdit.currentText()
  236. id=self.cameraMap[camera]
  237. text=self.ParameterEdit.toPlainText()
  238. transform=pb.CoordinateTransformation3D()
  239. try:
  240. tf.Parse(text, transform)
  241. except:
  242. QMessageBox.information(self, '格式错误',text,QMessageBox.Ok,QMessageBox.Ok)
  243. self.btnChange.setEnabled(True)
  244. return
  245. print(" 修改相机%d参数:%s"%(id,transform))
  246. client=rpc.GrpcStream()
  247. ip=self.IPEdit.text()
  248. port=int(self.PortEdit.text())
  249. try:
  250. ret=client.ChangeCameraParameter(ip,port,id,transform)
  251. QMessageBox.information(self, 'Info',ret.info,QMessageBox.Ok,QMessageBox.Ok)
  252. except Exception as e:
  253. QMessageBox.information(self, 'Info',str(e),QMessageBox.Ok,QMessageBox.Ok)
  254. self.btnChange.setEnabled(True)
  255. def matrix2rpy(self):
  256. text=""
  257. str=self.MatrixEdit.toPlainText()
  258. nums=str.split('\n')
  259. if not len(nums)==4:
  260. text="变换矩阵格式错误 需要4x4矩阵"
  261. else:
  262. matrix=np.zeros(shape=[4,4],dtype=np.float32)
  263. count=0
  264. for line in nums:
  265. datas=line.split(' ')
  266. if not len(datas)==4:
  267. text="变换矩阵格式错误 需要4x4矩阵"
  268. break
  269. else:
  270. matrix[count,:]=[float(datas[0]),float(datas[1]),float(datas[2]),float(datas[3])]
  271. count+=1
  272. rpy=self.rotationMatrixToEulerAngles(matrix)
  273. text="roll : %.3f,\npitch: %.3f,\nyaw: %.3f,\nx:%.3f,\ny:%.3f,\nz:%.3f,"%(math.degrees(rpy[0]),math.degrees(rpy[1]),math.degrees(rpy[2]),
  274. matrix[0,3],matrix[1,3],matrix[2,3])
  275. self.ParameterEdit.setText(text)
  276. #QMessageBox.information(self, '旋转变换转rpy-t',text,QMessageBox.Ok,QMessageBox.Ok)
  277. def btnCancelClick(self):
  278. pass
  279. class ImageViewer(QLabel):
  280. def __init__(self,parent,OnAction,id):
  281. super(ImageViewer,self).__init__(parent=parent)
  282. self.OnAction=OnAction
  283. self.dtype=1
  284. self.id=id
  285. self.image=None
  286. self.show = False
  287. self.setStyleSheet("border-width:1px;border-style:solid;border-color:rgb(150,150,150)")
  288. def ShowImg(self,pixmap):
  289. self.show=True
  290. self.image=pixmap
  291. self.update()
  292. def updataData(self):
  293. self.OnAction(self.dtype,self.id-1)
  294. print("%d,%d"%(self.dtype,self.id-1))
  295. def contextMenuEvent(self, a0):
  296. menu=QMenu(self)
  297. updata_act=QAction("更新")
  298. updata_act.triggered.connect(self.updataData)
  299. menu.addAction(updata_act)
  300. ret=menu.exec_(a0.globalPos())
  301. def paintEvent(self, a0: QPaintEvent) -> None:
  302. if not self.image == None:
  303. w, h = self.size().width(),self.size().height()
  304. iw, ih = self.image.width(), self.image.height()
  305. painter=QPainter(self)
  306. painter.drawPixmap(QRect(0,0,w,h),self.image,QRect(0,0,iw,ih))
  307. class VtkPointCloud:
  308. def __init__(self, zMin=-10.0, zMax=10.0, maxNumPoints=1e7):
  309. self.maxNumPoints = maxNumPoints
  310. self.vtkPolyData = vtk.vtkPolyData()
  311. self.clearPoints()
  312. mapper = vtk.vtkPolyDataMapper()
  313. mapper.SetInputData(self.vtkPolyData)
  314. mapper.SetColorModeToDefault()
  315. mapper.SetScalarRange(zMin, zMax)
  316. mapper.SetScalarVisibility(1)
  317. self.vtkActor = vtk.vtkActor()
  318. self.vtkActor.SetMapper(mapper)
  319. self.vtkActor.GetProperty().SetPointSize(1)
  320. self.vtkActor.GetProperty().SetColor(1, 1, 1)
  321. def addPoint(self, point):
  322. if self.vtkPoints.GetNumberOfPoints() < self.maxNumPoints:
  323. pointId = self.vtkPoints.InsertNextPoint(point[0:-1])
  324. self.vtkDepth.InsertNextValue(point[2])
  325. self.vtkCells.InsertNextCell(1)
  326. self.vtkCells.InsertCellPoint(pointId)
  327. self.vtkCells.Modified()
  328. self.vtkPoints.Modified()
  329. self.vtkDepth.Modified()
  330. def clearPoints(self):
  331. self.vtkPoints = vtk.vtkPoints()
  332. self.vtkCells = vtk.vtkCellArray()
  333. self.vtkDepth = vtk.vtkDoubleArray()
  334. self.vtkDepth.SetName('DepthArray')
  335. self.vtkPolyData.SetPoints(self.vtkPoints)
  336. self.vtkPolyData.SetVerts(self.vtkCells)
  337. #self.vtkPolyData.GetPointData().SetScalars(self.vtkDepth)
  338. self.vtkPolyData.GetPointData().SetActiveScalars('DepthArray')
  339. class pclViewer(QVTKRenderWindowInteractor):
  340. def __init__(self,parent=None):
  341. super(pclViewer,self).__init__(parent=parent)
  342. def mousePressEvent(self, ev):
  343. btn = ev.button()
  344. if btn == Qt.RightButton:
  345. print(" r btn")
  346. else:
  347. QVTKRenderWindowInteractor.mousePressEvent(self,ev)
  348. class VtkPointCloudCanvas(QWidget):
  349. def __init__(self, *args, **kwargs):
  350. super(VtkPointCloudCanvas, self).__init__(*args, **kwargs)
  351. self.lock_=threading.RLock()
  352. self._layout = QVBoxLayout()
  353. self.setLayout(self._layout)
  354. self._vtk_widget = pclViewer(self)
  355. self._vtk_widget.SetInteractorStyle(vtk.vtkInteractorStyleTrackballCamera()) # 设置交互方式==常用的方式 移动摄像机
  356. self._layout.addWidget(self._vtk_widget)
  357. self._render = vtk.vtkRenderer()
  358. self._vtk_widget.GetRenderWindow().AddRenderer(self._render)
  359. self._iren = self._vtk_widget.GetRenderWindow().GetInteractor()
  360. self._point_cloud = VtkPointCloud()
  361. self._render.AddActor(self._point_cloud.vtkActor)
  362. transform = vtk.vtkTransform()
  363. transform.Translate(0, 0.0, 0.0)
  364. axes = vtk.vtkAxesActor()
  365. axes.SetUserTransform(transform)
  366. colors = vtk.vtkNamedColors()
  367. axes.GetXAxisCaptionActor2D().GetCaptionTextProperty().SetColor(colors.GetColor3d("Red"))
  368. axes.GetYAxisCaptionActor2D().GetCaptionTextProperty().SetColor(colors.GetColor3d("Green"))
  369. axes.GetZAxisCaptionActor2D().GetCaptionTextProperty().SetColor(colors.GetColor3d("Blue"))
  370. self._render.AddActor(axes)
  371. self.camera=self._render.GetActiveCamera()
  372. self.show()
  373. self._iren.Initialize()
  374. def close(self) -> bool:
  375. print(" tk close")
  376. self._point_cloud.clearPoints()
  377. def displayPCL(self,cloud:np.array,type): #type 1:只显示轮胎,其他:显示所有
  378. colors = vtk.vtkUnsignedCharArray()
  379. colors.SetNumberOfComponents(3)
  380. colors.SetName("Colors")
  381. self._point_cloud.clearPoints()
  382. for point in cloud:
  383. prob=point[-1]
  384. if type==1:
  385. if prob>0.9:
  386. self._point_cloud.addPoint(point)
  387. colors.InsertNextTypedTuple((0,255,0))
  388. else:
  389. self._point_cloud.addPoint(point)
  390. if prob>0.9:
  391. colors.InsertNextTypedTuple((0,255,0))
  392. else:
  393. colors.InsertNextTypedTuple((255,0,0))
  394. self._point_cloud.vtkPolyData.GetPointData().SetScalars(colors)
  395. self._vtk_widget.update()
  396. def resetViewer(self):
  397. self.update()
  398. class PointCLViwer(QSplitter):
  399. def __init__(self,OnAction,id):
  400. super(PointCLViwer, self).__init__()
  401. self.OnAction=OnAction
  402. self.dtype=2
  403. self.id=id
  404. self.pointCloud=[]
  405. self.InitUI()
  406. def InitUI(self):
  407. self.pclViewer=VtkPointCloudCanvas(self)
  408. self.addWidget(self.pclViewer)
  409. self.setStretchFactor(0,4)
  410. def save(self):
  411. #fileName2, ok2 = QFileDialog.getSaveFileName(self, "文件保存", "C:/","All Files (*);;Text Files (*.txt)")
  412. #print(fileName2 ,ok2)
  413. fileName2="./cloud/%d.txt"%(self.id)
  414. with open(fileName2,"w+") as f:
  415. for point in self.pointCloud:
  416. prob=point[3]
  417. 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)))
  418. print("Save Cloud to %s"%(fileName2))
  419. subprocess.Popen(["cloudcompare.CloudCompare",fileName2])
  420. #os.system("cloudcompare.CloudCompare %s"%(fileName2))
  421. def saveWheel(self):
  422. #fileName2, ok2 = QFileDialog.getSaveFileName(self, "文件保存", "C:/","All Files (*);;Text Files (*.txt)")
  423. fileName2="./cloud/%d-wheel.txt"%(self.id)
  424. with open(fileName2,"w+") as f:
  425. for point in self.pointCloud:
  426. prob=point[3]
  427. if prob>0.9:
  428. 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)))
  429. print("Save Cloud to %s"%(fileName2))
  430. def displayCloud(self,points:np.array):
  431. self.pointCloud=points
  432. self.pclViewer.displayPCL(points,0)
  433. def resetViewer(self):
  434. self.pclViewer.resetViewer()
  435. def updataData(self):
  436. self.OnAction(self.dtype,self.id-1)
  437. def displayWheelPoints(self):
  438. self.pclViewer.displayPCL(self.pointCloud,1)
  439. def displayAllPoints(self):
  440. self.pclViewer.displayPCL(self.pointCloud,0)
  441. def contextMenuEvent(self, a0):
  442. menu=QMenu(self)
  443. updata_act=QAction("抓取点云")
  444. updata_act.triggered.connect(self.updataData)
  445. menu.addAction(updata_act)
  446. show_wheel=QAction("仅显示轮胎")
  447. show_wheel.triggered.connect(self.displayWheelPoints)
  448. menu.addAction(show_wheel)
  449. show_all=QAction("显示所有")
  450. show_all.triggered.connect(self.displayAllPoints)
  451. menu.addAction(show_all)
  452. #act=QAction("还原视野")
  453. #act.triggered.connect(self.resetViewer)
  454. #menu.addAction(act)
  455. actSave=QAction("保存所有点")
  456. actSave.triggered.connect(self.save)
  457. menu.addAction(actSave)
  458. actSaveWheel=QAction("保存轮胎点")
  459. actSaveWheel.triggered.connect(self.saveWheel)
  460. menu.addAction(actSaveWheel)
  461. ret=menu.exec_(a0.globalPos())
  462. class ViewerFrame(QFrame):
  463. def __init__(self,OnAction):
  464. super(ViewerFrame, self).__init__()
  465. self.OnAction=OnAction
  466. self.InitUI()
  467. def InitUI(self):
  468. self.table1=QTabWidget(self)
  469. self.table2=QTabWidget(self)
  470. self.table3=QTabWidget(self)
  471. self.table4=QTabWidget(self)
  472. self.table1.setTabPosition(QTabWidget.TabPosition.North)
  473. self.table2.setTabPosition(QTabWidget.TabPosition.North)
  474. self.table3.setTabPosition(QTabWidget.TabPosition.North)
  475. self.table4.setTabPosition(QTabWidget.TabPosition.North)
  476. self.panel1=ImageViewer(self,self.OnAction,1)
  477. self.panel2=ImageViewer(self,self.OnAction,2)
  478. self.panel3=ImageViewer(self,self.OnAction,3)
  479. self.panel4=ImageViewer(self,self.OnAction,4)
  480. self.pcViewer1=PointCLViwer(self.OnAction,1)
  481. self.pcViewer2=PointCLViwer(self.OnAction,2)
  482. self.pcViewer3=PointCLViwer(self.OnAction,3)
  483. self.pcViewer4=PointCLViwer(self.OnAction,4)
  484. self.table1.addTab(self.panel1,"图像")
  485. self.table1.addTab(self.pcViewer1,"点云")
  486. self.table2.addTab(self.panel2,"图像")
  487. self.table2.addTab(self.pcViewer2,"点云")
  488. self.table3.addTab(self.panel3,"图像")
  489. self.table3.addTab(self.pcViewer3,"点云")
  490. self.table4.addTab(self.panel4,"图像")
  491. self.table4.addTab(self.pcViewer4,"点云")
  492. def closeEvent(self, a0: QCloseEvent) -> None:
  493. pass
  494. def resizeEvent(self, a0: QResizeEvent) -> None:
  495. w, h = self.size().width(), self.size().height()
  496. w=w-15
  497. h=h-15
  498. self.table1.setGeometry(5, 5, w/2, h/2)
  499. self.table2.setGeometry(10+w/2, 5, w/2, h/2)
  500. self.table3.setGeometry(5, 10+h/2, w/2, h/2)
  501. self.table4.setGeometry(10+w/2, 10+h/2, w/2, h/2)
  502. def PbImg2QPix(self,image:pb.Image):
  503. img1=image
  504. w=img1.width
  505. h=img1.height
  506. c=img1.channel
  507. btarry=bytearray(img1.data)
  508. npdata = np.frombuffer(btarry, dtype=np.uint8)
  509. if c==3:
  510. npdata = npdata.reshape([h,w,c])
  511. qimg=QImage(npdata.data,w,h,QImage.Format_RGB888)
  512. if c==1:
  513. npdata = npdata.reshape([h,w])
  514. qimg=QImage(npdata.data,w,h,QImage.Format_Grayscale8)
  515. pix=QPixmap(qimg)
  516. return pix
  517. def PbCloud2Pts(self,cloud:pb.PointCloud):
  518. size=cloud.size
  519. btarry=bytearray(cloud.data)
  520. npdata = np.frombuffer(btarry, dtype=np.short)
  521. points= npdata.reshape([size,4])/32750.0 *5.0
  522. return points
  523. def DisplayFrame(self,frame : pb.ResFrame):
  524. if frame.HasField("images"):
  525. self.DisplayImage(frame.images)
  526. if frame.HasField("clouds"):
  527. self.DisplayCloud(frame.clouds)
  528. def DisplayImage(self,images:pb.ResImage):
  529. if images.HasField("img1"):
  530. self.panel1.ShowImg(self.PbImg2QPix(images.img1))
  531. if images.HasField("img2"):
  532. self.panel2.ShowImg(self.PbImg2QPix(images.img2))
  533. if images.HasField("img3"):
  534. self.panel3.ShowImg(self.PbImg2QPix(images.img3))
  535. if images.HasField("img4"):
  536. self.panel4.ShowImg(self.PbImg2QPix(images.img4))
  537. def DisplayCloud(self,clouds:pb.ResCloud):
  538. if clouds.HasField("cloud1"):
  539. self.pcViewer1.displayCloud(self.PbCloud2Pts(clouds.cloud1))
  540. if clouds.HasField("cloud2"):
  541. self.pcViewer2.displayCloud(self.PbCloud2Pts(clouds.cloud2))
  542. if clouds.HasField("cloud3"):
  543. self.pcViewer3.displayCloud(self.PbCloud2Pts(clouds.cloud3))
  544. if clouds.HasField("cloud4"):
  545. self.pcViewer4.displayCloud(self.PbCloud2Pts(clouds.cloud4))