示例#1
0
    def openValkka(self):
        self.thread = QValkkaThread() # the thread that's watching the mvision_processes
        self.thread.start()
        
        self.mvision_process.start()
        self.thread.addProcess(self.mvision_process)
        
        # """
        self.livethread = LiveThread(         # starts live stream services (using live555)
            name="live_thread",
            verbose=False
        )

        self.filethread = FileThread(
            name="file_thread",
            verbose=False
        )

        self.openglthread = OpenGLThread(     # starts frame presenting services
            name="mythread",
            n_720p=10,
            n_1080p=10,
            n_1440p=10,
            n_4K=10,
            verbose=False,
            msbuftime=100,
            affinity=-1
        )

        # this filterchain creates a shared memory server
        self.chain = ShmemFilterchain1(       # decoding and branching the stream happens here
            openglthread = self.openglthread,
            slot = 1,
            shmem_name = self.shmem_name,
            shmem_image_dimensions = self.shmem_image_dimensions,
            shmem_image_interval = self.shmem_image_interval,
            shmem_ringbuffer_size = self.shmem_ringbuffer_size
        )

        shmem_name, n_buffer, shmem_image_dimensions = self.chain.getShmemPars()
        self.video = QtWidgets.QWidget(self.video_area)
        self.win_id = int(self.video.winId())

        self.video_lay.addWidget(self.video, 0, 0)
        self.token = self.openglthread.connect(slot = 1, window_id = self.win_id)

        self.chain.decodingOn()  # tell the decoding thread to start its job

        self.mvision_process.activate(
            n_buffer                = self.shmem_ringbuffer_size, 
            image_dimensions        = self.shmem_image_dimensions, 
            shmem_name              = self.shmem_name  
        )
class MyGui(QtWidgets.QMainWindow):

  debug=False
  # debug=True

  def __init__(self):
    super(MyGui, self).__init__()
    # self.pardic=pardic
    self.initVars()
    self.setupUi()
    if (self.debug): 
      return
    self.openValkka()
    self.startProcesses()
    
    
  def initVars(self):
    self.messages=[]
    self.mode="file"
    self.slot_reserved=False


  def setupUi(self):
    self.setGeometry(QtCore.QRect(100,100,800,800))
    self.w=QtWidgets.QWidget(self)
    self.setCentralWidget(self.w)
    self.lay=QtWidgets.QVBoxLayout(self.w)
    
    # divide window into three parts
    self.upper  =QtWidgets.QWidget(self.w)
    self.lower  =QtWidgets.QWidget(self.w)
    self.lowest =QtWidgets.QWidget(self.w)
    self.lay.addWidget(self.upper)
    self.lay.addWidget(self.lower)
    self.lay.addWidget(self.lowest)
    
    # upper part: license plate list and the video
    self.upperlay   =QtWidgets.QHBoxLayout(self.upper)
    self.msg_list  =QtWidgets.QTextEdit(self.upper)
    
    self.video_area =QtWidgets.QWidget(self.upper)
    self.video_lay  =QtWidgets.QGridLayout(self.video_area)
    
    self.upperlay.addWidget(self.msg_list)
    self.upperlay.addWidget(self.video_area)
    self.msg_list.setSizePolicy(QtWidgets.QSizePolicy.Minimum,  QtWidgets.QSizePolicy.Minimum)
    self.video_area.setSizePolicy(QtWidgets.QSizePolicy.Expanding,QtWidgets.QSizePolicy.Expanding)
    
    # lower part: [Open File] [Close Live] [Play] [Stop] [Rewind]
    self.lowerlay  =QtWidgets.QHBoxLayout(self.lower)
    self.open_file_button =QtWidgets.QPushButton("Open File", self.lower)
    self.close_file_button=QtWidgets.QPushButton("Close File",self.lower)
    self.play_button      =QtWidgets.QPushButton("Play",self.lower)
    self.stop_button      =QtWidgets.QPushButton("Stop",self.lower)
    self.rewind_button    =QtWidgets.QPushButton("<<",  self.lower)
    
    self.lowerlay.addWidget(self.open_file_button)
    self.lowerlay.addWidget(self.close_file_button)
    self.lowerlay.addWidget(self.play_button)
    self.lowerlay.addWidget(self.stop_button)
    self.lowerlay.addWidget(self.rewind_button)
    
    self.open_file_button.clicked. connect(self.open_file_button_slot)
    self.close_file_button.clicked.connect(self.close_file_button_slot)
    self.play_button.clicked.      connect(self.play_button_slot)
    self.stop_button.clicked.      connect(self.stop_button_slot)
    self.rewind_button.clicked.    connect(self.rewind_button_slot)
    
    # lowest part: some text
    self.lowestlay=QtWidgets.QVBoxLayout(self.lowest)
    self.infotext =QtWidgets.QLabel("info text",self.lowest)
    self.lowestlay.addWidget(self.infotext)
    
    
  def openValkka(self):
    self.livethread=LiveThread(         # starts live stream services (using live555)
      name   ="live_thread",
      verbose=False
    )

    self.filethread=FileThread(
      name  ="file_thread",
      verbose=False
    )

    self.openglthread=OpenGLThread(     # starts frame presenting services
      name    ="mythread",
      n_720p   =10,
      n_1080p  =10,
      n_1440p  =10,
      n_4K     =10,
      verbose =False,
      msbuftime=100,
      affinity=-1
      )
    
    if (self.openglthread.hadVsync()):
      w=QtWidgets.QMessageBox.warning(self,"VBLANK WARNING","Syncing to vertical refresh enabled\n THIS WILL DESTROY YOUR FRAMERATE\n Disable it with 'export vblank_mode=0' for nvidia proprietary drivers, use 'export __GL_SYNC_TO_VBLANK=0'")
    
    cc=1
    
    self.chain=ShmemFilterchain1(       # decoding and branching the stream happens here
      openglthread=self.openglthread,
      slot        =cc,
      # this filterchain creates a shared memory server
      shmem_name             ="test_studio_file_"+str(cc),
      shmem_image_dimensions =(1920//4,1080//4),  # Images passed over shmem are quarter of the full-hd reso
      shmem_image_interval   =1000,               # YUV => RGB interpolation to the small size is done each 1000 milliseconds and passed on to the shmem ringbuffer
      shmem_ringbuffer_size  =10                  # Size of the shmem ringbuffer
      )
    
    shmem_name, n_buffer, shmem_image_dimensions =self.chain.getShmemPars()    
    # print(pre,"shmem_name, n_buffer, n_bytes",shmem_name,n_buffer,n_bytes)
    
    self.process=QValkkaMovementDetectorProcess("process_"+str(cc),shmem_name=shmem_name, n_buffer=n_buffer, image_dimensions=shmem_image_dimensions)
    
    self.process.signals.start_move.connect(self.set_moving_slot)
    self.process.signals.stop_move. connect(self.set_still_slot)
    
    if (valkka_xwin):
      # (1) Let OpenGLThread create the window
      self.win_id      =self.openglthread.createWindow(show=False)
      self.widget_pair =WidgetPair(self.video_area,self.win_id,TestWidget0)
      self.video       =self.widget_pair.getWidget()
    else:
      # (2) Let Qt create the window
      self.video     =QtWidgets.QWidget(self.video_area)
      self.win_id    =int(self.video.winId())
    
    self.video_lay.addWidget(self.video,0,0)
    self.token =self.openglthread.connect(slot=cc,window_id=self.win_id)
    
    self.chain.decodingOn() # tell the decoding thread to start its job
    
    # finally, give the multiprocesses to a qthread that's reading their message pipe
    self.thread =QValkkaThread(processes=[self.process])
    
  
  def startProcesses(self):
    self.process.start()
    self.thread.start()
  
  
  def stopProcesses(self):
    print(pre,"stopProcesses :",self.process)
    self.process.stop()
    self.thread.stop()
    print(pre,"QThread stopped")
    
    
  def closeValkka(self):
    self.livethread.close()
    self.chain.close()
    self.chain =None
    self.openglthread.close()
    
    
  def closeEvent(self,e):
    print(pre,"closeEvent!")
    self.stopProcesses()
    self.closeValkka()
    super().closeEvent(e)
    
    
  # *** slot ****
  def open_file_button_slot(self):
    if (self.slot_reserved):
      self.infotext.setText("Close the current file first")
      return
    fname=QtWidgets.QFileDialog.getOpenFileName(filter="*.mkv")[0]
    if (len(fname)>0):
      print(pre,"open_file_button_slot: got filename",fname)
      self.chain.setFileContext(fname)
      self.filethread.openStream(self.chain.file_ctx)
      self.slot_reserved=True
      if (self.chain.fileStatusOk()):
        self.infotext.setText("Opened file "+fname)
      else:
        self.infotext.setText("Can't play file "+fname)
    else:
      self.infotext.setText("No file opened")
    
  
  def close_file_button_slot(self):
    if (not self.slot_reserved):
      self.infotext.setText("Open a file first")
      return
    self.filethread.closeStream(self.chain.file_ctx)
    self.slot_reserved=False
    self.infotext.setText("Closed file")
  
  
  def open_live_button_slot(self):
    pass
  
  
  def play_button_slot(self):
    if (self.mode=="file"):
      if (not self.slot_reserved):
        self.infotext.setText("Open a file first")
        return
      self.filethread.playStream(self.chain.file_ctx)
    else:
      pass
    
    
  def rewind_button_slot(self):
    if (self.mode=="file"):
      if (not self.slot_reserved):
        self.infotext.setText("Open a file first")
        return
      self.chain.file_ctx.seektime_=0;
      self.filethread.seekStream(self.chain.file_ctx)
    else:
      pass
    
    
  def stop_button_slot(self):
    if (self.mode=="file"):
      if (not self.slot_reserved):
        self.infotext.setText("Open a file first")
        return
      self.filethread.stopStream(self.chain.file_ctx)
    else:
      pass
    
  
  def set_still_slot(self):
    self.infotext.setText("still")
    self.messages.append("Movement stopped at ")
    if (len(self.messages)>10): self.messages.pop(0)
    st=""
    for message in self.messages:
      st+=message+"\n"
    self.msg_list.setText(st)
    
      
  def set_moving_slot(self):
    self.infotext.setText("MOVING")
    self.messages.append("Movement started at ")
    if (len(self.messages)>10): self.messages.pop(0)
    st=""
    for message in self.messages:
      st+=message+"\n"
    self.msg_list.setText(st)
  def openValkka(self):
    self.livethread=LiveThread(         # starts live stream services (using live555)
      name   ="live_thread",
      verbose=False
    )

    self.filethread=FileThread(
      name  ="file_thread",
      verbose=False
    )

    self.openglthread=OpenGLThread(     # starts frame presenting services
      name    ="mythread",
      n_720p   =10,
      n_1080p  =10,
      n_1440p  =10,
      n_4K     =10,
      verbose =False,
      msbuftime=100,
      affinity=-1
      )
    
    if (self.openglthread.hadVsync()):
      w=QtWidgets.QMessageBox.warning(self,"VBLANK WARNING","Syncing to vertical refresh enabled\n THIS WILL DESTROY YOUR FRAMERATE\n Disable it with 'export vblank_mode=0' for nvidia proprietary drivers, use 'export __GL_SYNC_TO_VBLANK=0'")
    
    cc=1
    
    self.chain=ShmemFilterchain1(       # decoding and branching the stream happens here
      openglthread=self.openglthread,
      slot        =cc,
      # this filterchain creates a shared memory server
      shmem_name             ="test_studio_file_"+str(cc),
      shmem_image_dimensions =(1920//4,1080//4),  # Images passed over shmem are quarter of the full-hd reso
      shmem_image_interval   =1000,               # YUV => RGB interpolation to the small size is done each 1000 milliseconds and passed on to the shmem ringbuffer
      shmem_ringbuffer_size  =10                  # Size of the shmem ringbuffer
      )
    
    shmem_name, n_buffer, shmem_image_dimensions =self.chain.getShmemPars()    
    # print(pre,"shmem_name, n_buffer, n_bytes",shmem_name,n_buffer,n_bytes)
    
    self.process=QValkkaMovementDetectorProcess("process_"+str(cc),shmem_name=shmem_name, n_buffer=n_buffer, image_dimensions=shmem_image_dimensions)
    
    self.process.signals.start_move.connect(self.set_moving_slot)
    self.process.signals.stop_move. connect(self.set_still_slot)
    
    if (valkka_xwin):
      # (1) Let OpenGLThread create the window
      self.win_id      =self.openglthread.createWindow(show=False)
      self.widget_pair =WidgetPair(self.video_area,self.win_id,TestWidget0)
      self.video       =self.widget_pair.getWidget()
    else:
      # (2) Let Qt create the window
      self.video     =QtWidgets.QWidget(self.video_area)
      self.win_id    =int(self.video.winId())
    
    self.video_lay.addWidget(self.video,0,0)
    self.token =self.openglthread.connect(slot=cc,window_id=self.win_id)
    
    self.chain.decodingOn() # tell the decoding thread to start its job
    
    # finally, give the multiprocesses to a qthread that's reading their message pipe
    self.thread =QValkkaThread(processes=[self.process])
示例#4
0
class FileGUI(QtWidgets.QMainWindow):
    """Test your machine vision mvision_process and its widget with video files
    
    :param mvision_process:          QValkkaMultimvision_process-derived class
    :param shmem_image_interval:     How often the image is interpolated into rgb and passed to the mvision_process (milliseconds)
    """
    def __init__(self,
                 mvision_process,
                 mvision_master_process,
                 shmem_image_interval=1000,
                 shmem_ringbuffer_size=10,
                 shmem_image_dimensions=(1920 // 2, 1080 // 2),
                 shmem_name="test",
                 init_filename=None):

        super().__init__()
        assert (issubclass(mvision_process.__class__, QShmemProcess))

        self.mvision_process = mvision_process
        self.mvision_master_process = mvision_master_process

        # self.mvision_class          = mvision_class,
        self.shmem_image_interval = shmem_image_interval
        self.shmem_ringbuffer_size = shmem_ringbuffer_size
        self.shmem_image_dimensions = shmem_image_dimensions
        self.shmem_name = shmem_name

        self.init_filename = init_filename

        self.initVars()
        self.setupUi()

        self.mvision_widget = self.mvision_process.getWidget()
        # self.mvision_widget = QtWidgets.QWidget()
        self.mvision_widget.setParent(self.widget)
        self.widget_lay.addWidget(self.mvision_widget)

        self.mvision_widget.setSizePolicy(QtWidgets.QSizePolicy.Minimum,
                                          QtWidgets.QSizePolicy.Minimum)

        self.openValkka()

        if len(sys.argv) > 2:
            self.open_file_button_slot(fname_=sys.argv[2])

    def initVars(self):
        self.mode = "file"
        self.slot_reserved = False

    def setupUi(self):

        rec = QtWidgets.QApplication.desktop().screenGeometry()
        height = rec.height()
        width = rec.width()

        self.setGeometry(QtCore.QRect(0, 0, width, height // 2))
        self.w = QtWidgets.QWidget(self)
        self.setCentralWidget(self.w)
        self.lay = QtWidgets.QVBoxLayout(self.w)

        # return

        # divide window into three parts
        self.upper = QtWidgets.QWidget(self.w)
        self.middle = QtWidgets.QWidget(self.w)
        self.lower = QtWidgets.QWidget(self.w)
        self.lowest = QtWidgets.QWidget(self.w)
        self.lay.addWidget(self.upper)
        self.lay.addWidget(self.middle)
        self.lay.addWidget(self.lower)
        self.lay.addWidget(self.lowest)

        # upper part: detectors widget and the video itself
        self.upperlay = QtWidgets.QHBoxLayout(self.upper)

        # self.widget  =QtWidgets.QTextEdit(self.upper)
        self.widget = QtWidgets.QWidget(self.upper)
        self.widget_lay = QtWidgets.QVBoxLayout(self.widget)

        # self.widget = self.mvision_process.getWidget()
        # self.widget.setParent(self.upper)

        self.video_area = QtWidgets.QWidget(self.upper)
        self.video_lay = QtWidgets.QGridLayout(self.video_area)

        self.upperlay.addWidget(self.widget)
        self.upperlay.addWidget(self.video_area)
        self.widget.setSizePolicy(QtWidgets.QSizePolicy.Minimum,
                                  QtWidgets.QSizePolicy.Minimum)
        self.video_area.setSizePolicy(QtWidgets.QSizePolicy.Expanding,
                                      QtWidgets.QSizePolicy.Expanding)
        """
        [------|--------------------------------------]
        [Open File] [Close Live] [Play] [Stop] [Rewind]
        """

        self.middlelay = QtWidgets.QHBoxLayout(self.middle)
        self.slider = QtWidgets.QSlider(QtCore.Qt.Orientation.Horizontal,
                                        self.middle)
        self.middlelay.addWidget(self.slider)
        self.slider.setTracking(False)

        self.lowerlay = QtWidgets.QHBoxLayout(self.lower)
        self.open_file_button = QtWidgets.QPushButton("Open File", self.lower)
        self.close_file_button = QtWidgets.QPushButton("Close File",
                                                       self.lower)
        self.play_button = QtWidgets.QPushButton("Play", self.lower)
        self.stop_button = QtWidgets.QPushButton("Stop", self.lower)
        self.rewind_button = QtWidgets.QPushButton("<<", self.lower)
        self.seek_label = QtWidgets.QLabel("<<", self.lower)

        self.lowerlay.addWidget(self.open_file_button)
        self.lowerlay.addWidget(self.close_file_button)
        self.lowerlay.addWidget(self.play_button)
        self.lowerlay.addWidget(self.stop_button)
        self.lowerlay.addWidget(self.rewind_button)
        self.lowerlay.addWidget(self.seek_label)

        self.open_file_button.clicked.connect(self.open_file_button_slot)
        self.close_file_button.clicked.connect(self.close_file_button_slot)
        self.play_button.clicked.connect(self.play_button_slot)
        self.stop_button.clicked.connect(self.stop_button_slot)
        self.rewind_button.clicked.connect(self.rewind_button_slot)
        self.slider.valueChanged.connect(self.slider_slot)

        # lowest part: some text
        self.lowestlay = QtWidgets.QVBoxLayout(self.lowest)
        self.infotext = QtWidgets.QLabel("info text", self.lowest)
        self.lowestlay.addWidget(self.infotext)

    def openValkka(self):
        self.mvision_process.go()

        if self.mvision_master_process is not None:
            assert (issubclass(self.mvision_master_process.__class__,
                               QShmemProcess))
            self.mvision_master_process.go()

        self.livethread = LiveThread(  # starts live stream services (using live555)
            name="live_thread",
            verbose=False)

        self.filethread = FileThread(name="file_thread", verbose=False)

        self.openglthread = OpenGLThread(  # starts frame presenting services
            name="mythread",
            n_720p=10,
            n_1080p=10,
            n_1440p=10,
            n_4K=10,
            verbose=False,
            msbuftime=100,
            affinity=-1)

        # this filterchain creates a shared memory server
        self.chain = ShmemFilterchain1(  # decoding and branching the stream happens here
            openglthread=self.openglthread,
            slot=1,
            shmem_name=self.shmem_name,
            shmem_image_dimensions=self.shmem_image_dimensions,
            shmem_image_interval=self.shmem_image_interval,
            shmem_ringbuffer_size=self.shmem_ringbuffer_size)

        shmem_name, n_buffer, shmem_image_dimensions = self.chain.getShmemPars(
        )

        self.video = QtWidgets.QWidget(self.video_area)

        if hasattr(self.mvision_process, "analyzer_video_widget_class"):
            # the machine vision class may declare what video widget it wants to use to define the machine vision parameters (line crossing, zone intrusion, etc.)
            self.analyzer_widget = AnalyzerWidget(
                parent=self.video_area,
                analyzer_video_widget_class=self.mvision_process.
                analyzer_video_widget_class)
        else:
            self.analyzer_widget = AnalyzerWidget(parent=self.video_area)

        self.mvision_process.connectAnalyzerWidget(self.analyzer_widget)
        self.analyzer_widget.activate()

        self.win_id = int(self.video.winId())

        self.video_lay.addWidget(self.video, 0, 0)
        self.video_lay.addWidget(self.analyzer_widget, 0, 1)
        self.token = self.openglthread.connect(slot=1, window_id=self.win_id)

        self.chain.decodingOn()  # tell the decoding thread to start its job

        self.mvision_process.activate(
            n_buffer=self.shmem_ringbuffer_size,
            image_dimensions=self.shmem_image_dimensions,
            shmem_name=self.shmem_name)

        if self.mvision_master_process:
            self.mvision_process.setMasterProcess(self.mvision_master_process)

    def closeValkka(self):
        if self.mvision_master_process:
            self.mvision_process.unsetMasterProcess()
        self.mvision_process.disconnectAnalyzerWidget(self.analyzer_widget)
        self.livethread.close()
        self.chain.close()
        self.chain = None
        self.openglthread.close()

        self.mvision_process.requestStop()
        self.mvision_process.waitStop()

        if self.mvision_master_process:
            self.mvision_master_process.requestStop()
            self.mvision_master_process.waitStop()

    def showEvent(self, e):
        if self.init_filename is not None:
            self.open_file_button_slot(fname_=self.init_filename)
        e.accept()

    def closeEvent(self, e):
        print(pre, "closeEvent!")
        self.closeValkka()
        self.analyzer_widget.close()  # wtf do we need this!
        # super().closeEvent(e)
        e.accept()

    # *** slot ****

    def open_file_button_slot(self, fname_=None):
        if (self.slot_reserved):
            self.infotext.setText("Close the current file first")
            return
        if not fname_:
            fname = QtWidgets.QFileDialog.getOpenFileName(filter="*.mkv")[0]
        else:
            fname = fname_
        if (len(fname) > 0):
            print(pre, "open_file_button_slot: got filename", fname)
            self.chain.setFileContext(fname)
            self.filethread.openStream(self.chain.file_ctx)
            self.slot_reserved = True
            if (self.chain.fileStatusOk()):
                self.infotext.setText("Opened file " + fname)
                print("Duration:", self.chain.file_ctx.duration)
                self.slider.setMinimum(0)
                self.slider.setMaximum(self.chain.file_ctx.duration)
            else:
                self.infotext.setText("Can't play file " + fname)
        else:
            self.infotext.setText("No file opened")

    def close_file_button_slot(self):
        if (not self.slot_reserved):
            self.infotext.setText("Open a file first")
            return
        self.filethread.closeStream(self.chain.file_ctx)
        self.slot_reserved = False
        self.infotext.setText("Closed file")

    def open_live_button_slot(self):
        pass

    def play_button_slot(self):
        if (self.mode == "file"):
            if (not self.slot_reserved):
                self.infotext.setText("Open a file first")
                return
            self.filethread.playStream(self.chain.file_ctx)
        else:
            pass

    def rewind_button_slot(self):
        if (self.mode == "file"):
            if (not self.slot_reserved):
                self.infotext.setText("Open a file first")
                return
            self.chain.file_ctx.seektime_ = 0
            self.filethread.seekStream(self.chain.file_ctx)
        else:
            pass

    def stop_button_slot(self):
        if (self.mode == "file"):
            if (not self.slot_reserved):
                self.infotext.setText("Open a file first")
                return
            self.filethread.stopStream(self.chain.file_ctx)
        else:
            pass

    def slider_slot(self, v):
        print(">", v)
        self.chain.file_ctx.seektime_ = v
        # TODO: reset analyzer state
        self.seek_label.setText(str(v))
        self.mvision_process.resetAnalyzerState()
        self.filethread.seekStream(self.chain.file_ctx)

    def set_bounding_boxes_slot(self, bbox_list):
        self.openglthread.core.clearObjectsCall(self.token)
        for bbox in bbox_list:
            self.openglthread.core.addRectangleCall(
                self.token, bbox[0], bbox[1], bbox[2],
                bbox[3])  # left, right, top, bottom
示例#5
0
    def openValkka(self):
        self.mvision_process.go()

        if self.mvision_master_process is not None:
            assert (issubclass(self.mvision_master_process.__class__,
                               QShmemProcess))
            self.mvision_master_process.go()

        self.livethread = LiveThread(  # starts live stream services (using live555)
            name="live_thread",
            verbose=False)

        self.filethread = FileThread(name="file_thread", verbose=False)

        self.openglthread = OpenGLThread(  # starts frame presenting services
            name="mythread",
            n_720p=10,
            n_1080p=10,
            n_1440p=10,
            n_4K=10,
            verbose=False,
            msbuftime=100,
            affinity=-1)

        # this filterchain creates a shared memory server
        self.chain = ShmemFilterchain1(  # decoding and branching the stream happens here
            openglthread=self.openglthread,
            slot=1,
            shmem_name=self.shmem_name,
            shmem_image_dimensions=self.shmem_image_dimensions,
            shmem_image_interval=self.shmem_image_interval,
            shmem_ringbuffer_size=self.shmem_ringbuffer_size)

        shmem_name, n_buffer, shmem_image_dimensions = self.chain.getShmemPars(
        )

        self.video = QtWidgets.QWidget(self.video_area)

        if hasattr(self.mvision_process, "analyzer_video_widget_class"):
            # the machine vision class may declare what video widget it wants to use to define the machine vision parameters (line crossing, zone intrusion, etc.)
            self.analyzer_widget = AnalyzerWidget(
                parent=self.video_area,
                analyzer_video_widget_class=self.mvision_process.
                analyzer_video_widget_class)
        else:
            self.analyzer_widget = AnalyzerWidget(parent=self.video_area)

        self.mvision_process.connectAnalyzerWidget(self.analyzer_widget)
        self.analyzer_widget.activate()

        self.win_id = int(self.video.winId())

        self.video_lay.addWidget(self.video, 0, 0)
        self.video_lay.addWidget(self.analyzer_widget, 0, 1)
        self.token = self.openglthread.connect(slot=1, window_id=self.win_id)

        self.chain.decodingOn()  # tell the decoding thread to start its job

        self.mvision_process.activate(
            n_buffer=self.shmem_ringbuffer_size,
            image_dimensions=self.shmem_image_dimensions,
            shmem_name=self.shmem_name)

        if self.mvision_master_process:
            self.mvision_process.setMasterProcess(self.mvision_master_process)
示例#6
0
class FileGUI(QtWidgets.QMainWindow):
    """Test your machine vision mvision_process and its widget with video files
    
    :param mvision_process:          QValkkaMultimvision_process-derived class
    :param shmem_image_interval:     How often the image is interpolated into rgb and passed to the mvision_process (milliseconds)
    """

    def __init__(self, 
                 mvision_process, 
                 shmem_image_interval = 1000, 
                 shmem_ringbuffer_size = 10, 
                 shmem_image_dimensions = (1920 // 2, 1080 // 2),
                 shmem_name="test"):
        
        super().__init__()
        assert(issubclass(mvision_process.__class__, QValkkaShmemProcess2))
        
        self.mvision_process        = mvision_process
        self.shmem_image_interval   = shmem_image_interval
        self.shmem_ringbuffer_size  = shmem_ringbuffer_size
        self.shmem_image_dimensions = shmem_image_dimensions
        self.shmem_name             = shmem_name
        
        self.initVars()
        self.setupUi()
        
        self.mvision_widget = self.mvision_process.getWidget()
        # self.mvision_widget = QtWidgets.QWidget()
        self.mvision_widget.setParent(self.widget)
        self.widget_lay.addWidget(self.mvision_widget)
        
        self.openValkka()

    def initVars(self):
        self.mode = "file"
        self.slot_reserved = False

    def setupUi(self):
        self.setGeometry(QtCore.QRect(100, 100, 800, 800))
        self.w = QtWidgets.QWidget(self)
        self.setCentralWidget(self.w)
        self.lay = QtWidgets.QVBoxLayout(self.w)

        # return

        # divide window into three parts
        self.upper = QtWidgets.QWidget(self.w)
        self.lower = QtWidgets.QWidget(self.w)
        self.lowest = QtWidgets.QWidget(self.w)
        self.lay.addWidget(self.upper)
        self.lay.addWidget(self.lower)
        self.lay.addWidget(self.lowest)

        # upper part: detectors widget and the video itself
        self.upperlay = QtWidgets.QHBoxLayout(self.upper)

        # self.widget  =QtWidgets.QTextEdit(self.upper)
        self.widget  =QtWidgets.QWidget(self.upper)
        self.widget_lay = QtWidgets.QVBoxLayout(self.widget)

        # self.widget = self.mvision_process.getWidget()
        # self.widget.setParent(self.upper)

        self.video_area = QtWidgets.QWidget(self.upper)
        self.video_lay = QtWidgets.QGridLayout(self.video_area)

        self.upperlay.addWidget(self.widget)
        self.upperlay.addWidget(self.video_area)
        self.widget.setSizePolicy(
            QtWidgets.QSizePolicy.Minimum,
            QtWidgets.QSizePolicy.Minimum)
        self.video_area.setSizePolicy(
            QtWidgets.QSizePolicy.Expanding,
            QtWidgets.QSizePolicy.Expanding)

        # lower part: [Open File] [Close Live] [Play] [Stop] [Rewind]
        self.lowerlay = QtWidgets.QHBoxLayout(self.lower)
        self.open_file_button = QtWidgets.QPushButton("Open File", self.lower)
        self.close_file_button = QtWidgets.QPushButton(
            "Close File", self.lower)
        self.play_button = QtWidgets.QPushButton("Play", self.lower)
        self.stop_button = QtWidgets.QPushButton("Stop", self.lower)
        self.rewind_button = QtWidgets.QPushButton("<<", self.lower)

        self.lowerlay.addWidget(self.open_file_button)
        self.lowerlay.addWidget(self.close_file_button)
        self.lowerlay.addWidget(self.play_button)
        self.lowerlay.addWidget(self.stop_button)
        self.lowerlay.addWidget(self.rewind_button)

        self.open_file_button.clicked. connect(self.open_file_button_slot)
        self.close_file_button.clicked.connect(self.close_file_button_slot)
        self.play_button.clicked.      connect(self.play_button_slot)
        self.stop_button.clicked.      connect(self.stop_button_slot)
        self.rewind_button.clicked.    connect(self.rewind_button_slot)

        # lowest part: some text
        self.lowestlay = QtWidgets.QVBoxLayout(self.lowest)
        self.infotext = QtWidgets.QLabel("info text", self.lowest)
        self.lowestlay.addWidget(self.infotext)


    def openValkka(self):
        self.thread = QValkkaThread() # the thread that's watching the mvision_processes
        self.thread.start()
        
        self.mvision_process.start()
        self.thread.addProcess(self.mvision_process)
        
        # """
        self.livethread = LiveThread(         # starts live stream services (using live555)
            name="live_thread",
            verbose=False
        )

        self.filethread = FileThread(
            name="file_thread",
            verbose=False
        )

        self.openglthread = OpenGLThread(     # starts frame presenting services
            name="mythread",
            n_720p=10,
            n_1080p=10,
            n_1440p=10,
            n_4K=10,
            verbose=False,
            msbuftime=100,
            affinity=-1
        )

        # this filterchain creates a shared memory server
        self.chain = ShmemFilterchain1(       # decoding and branching the stream happens here
            openglthread = self.openglthread,
            slot = 1,
            shmem_name = self.shmem_name,
            shmem_image_dimensions = self.shmem_image_dimensions,
            shmem_image_interval = self.shmem_image_interval,
            shmem_ringbuffer_size = self.shmem_ringbuffer_size
        )

        shmem_name, n_buffer, shmem_image_dimensions = self.chain.getShmemPars()
        self.video = QtWidgets.QWidget(self.video_area)
        self.win_id = int(self.video.winId())

        self.video_lay.addWidget(self.video, 0, 0)
        self.token = self.openglthread.connect(slot = 1, window_id = self.win_id)

        self.chain.decodingOn()  # tell the decoding thread to start its job

        self.mvision_process.activate(
            n_buffer                = self.shmem_ringbuffer_size, 
            image_dimensions        = self.shmem_image_dimensions, 
            shmem_name              = self.shmem_name  
        )
        
        
    def closeValkka(self):
        # """
        self.livethread.close()
        self.chain.close()
        self.chain = None
        self.openglthread.close()
        # """
        print(self.mvision_process)
        self.thread.stop()
        

    def closeEvent(self, e):
        print(pre, "closeEvent!")
        self.closeValkka()
        super().closeEvent(e)

    # *** slot ****

    def open_file_button_slot(self):
        if (self.slot_reserved):
            self.infotext.setText("Close the current file first")
            return
        fname = QtWidgets.QFileDialog.getOpenFileName(filter="*.mkv")[0]
        if (len(fname) > 0):
            print(pre, "open_file_button_slot: got filename", fname)
            self.chain.setFileContext(fname)
            self.filethread.openStream(self.chain.file_ctx)
            self.slot_reserved = True
            if (self.chain.fileStatusOk()):
                self.infotext.setText("Opened file " + fname)
            else:
                self.infotext.setText("Can't play file " + fname)
        else:
            self.infotext.setText("No file opened")

    def close_file_button_slot(self):
        if (not self.slot_reserved):
            self.infotext.setText("Open a file first")
            return
        self.filethread.closeStream(self.chain.file_ctx)
        self.slot_reserved = False
        self.infotext.setText("Closed file")

    def open_live_button_slot(self):
        pass

    def play_button_slot(self):
        if (self.mode == "file"):
            if (not self.slot_reserved):
                self.infotext.setText("Open a file first")
                return
            self.filethread.playStream(self.chain.file_ctx)
        else:
            pass

    def rewind_button_slot(self):
        if (self.mode == "file"):
            if (not self.slot_reserved):
                self.infotext.setText("Open a file first")
                return
            self.chain.file_ctx.seektime_ = 0
            self.filethread.seekStream(self.chain.file_ctx)
        else:
            pass

    def stop_button_slot(self):
        if (self.mode == "file"):
            if (not self.slot_reserved):
                self.infotext.setText("Open a file first")
                return
            self.filethread.stopStream(self.chain.file_ctx)
        else:
            pass

    def set_bounding_boxes_slot(self, bbox_list):
        self.openglthread.core.clearObjectsCall(self.token)
        for bbox in bbox_list:
            self.openglthread.core.addRectangleCall(self.token, bbox[0], bbox[1], bbox[2], bbox[3]) # left, right, top, bottom