Esempio n. 1
0
    def change_parameter(self, parm_name, value, affect_slider=False):
        """改變相機參數

        會驗證參數在 setting 所設定的最大最小值,通過後再送給 slave

        Args:
            parm_name: 參數名稱
            value: 參數數值

        """
        if self._is_recording:
            log.error("Can't change parameter due to wrong camera state")
            return

        parm = self._parameters[parm_name]
        result = parm.set(value)

        if result == 'min':
            log.error(f'{parm_name} value too small ({value})')
        elif result == 'max':
            log.error(f'{parm_name} value too big ({value})')
        elif result == 'OK':
            message_manager.send_message(
                MessageType.CAMERA_PARM,
                {'camera_parm': (parm_name, parm.get_value())}
            )
            log.debug(f'Parameter <{parm_name}> changes to {value}')
            ui.dispatch_event(
                UIEventType.CAMERA_PARAMETER,
                (parm_name, value, affect_slider)
            )
Esempio n. 2
0
    def _run(self):
        while self._running:
            shot_meta = self._queue.get()

            if shot_meta is None:
                break

            shot_path = shot_meta.get_path()
            if shot_path is None:
                continue

            # 如果 self._file 是空的或者不是所需的檔案路徑,取代掉
            if not (self._file is not None
                    and self._file.get_path() == shot_path):
                if isinstance(self._file, CameraShotFileLoader):
                    self._file.close()
                self._file = CameraShotFileLoader(shot_path, self._log)

            camera_image = self._file.load(shot_meta.frame)
            if camera_image is None:
                continue

            message_manager.send_message(
                MessageType.SHOT_IMAGE, shot_meta.get_parms(),
                camera_image.convert_jpeg(shot_meta.quality,
                                          shot_meta.scale_length))
Esempio n. 3
0
    def retrigger(self):
        log.info('Retrigger')

        message_manager.send_message(
            MessageType.RETRIGGER
        )

        self.stop_capture()
Esempio n. 4
0
 def _request_camera_status(self):
     message_manager.send_message(
         MessageType.CAMERA_STATUS,
         {
             'calibrate_frame': self._camera_list[
                 setting.get_working_camera_ids()[0]
             ].current_frame
         }
     )
Esempio n. 5
0
    def on_entity_event(self, event, entity):
        """聆聽實體事件

        當專案與 Shot 有事件發生時的處理

        Args:
            event: 實體事件
            entity: 發生事件的實體

        """
        # 如果有實體刪除
        if event is EntityEvent.REMOVE:
            # 專案: 同時在 self._projects 刪除並確認是否是 current 來清空
            if isinstance(entity, ProjectEntity):
                log.info('Remove project: {}'.format(entity))
                self._projects.remove(entity)
                ui.dispatch_event(UIEventType.PROJECT_MODIFIED,
                                  [*self._projects])
                if self.current_project == entity:
                    self.select_project(None)
            # Shot: 如果是 current 清空,並傳送給 slave 通知刪除檔案
            elif isinstance(entity, ShotEntity):
                log.info('Remove shot: {}'.format(entity))
                if self.current_shot == entity:
                    self.select_shot(None)

                ui.dispatch_event(UIEventType.SHOT_MODIFIED,
                                  [*self.current_project.shots])

                message_manager.send_message(MessageType.REMOVE_SHOT,
                                             {'shot_id': entity.get_id()})
            elif isinstance(entity, JobEntity):
                log.info('Remove job: {}'.format(entity))
                if self.current_job == entity:
                    self.select_job(None)

                ui.dispatch_event(UIEventType.JOB_MODIFIED,
                                  [*self.current_shot.jobs])

        # 如果有實體創建
        elif event is EntityEvent.CREATE:
            log.info(f'Create {entity.print_name}: {entity}')

            if isinstance(entity, ShotEntity):
                ui.dispatch_event(UIEventType.SHOT_MODIFIED,
                                  [*self.current_project.shots])
                self.select_shot(entity)

            elif isinstance(entity, JobEntity):
                ui.dispatch_event(UIEventType.JOB_MODIFIED,
                                  [*self.current_shot.jobs])

        # 如果有實體更改
        elif event is EntityEvent.MODIFY:
            log.info(f'Modify:\n {entity.print_name}')
Esempio n. 6
0
    def _stop_record(self):
        """停止運作,將錄製做收尾,並整理錄製報告傳給 master"""
        report = self._file.get_report()
        self._file.close()

        report.update({
            'camera_id': self._shot_meta.camera_id,
            'shot_id': self._shot_meta.shot_id
        })

        message_manager.send_message(MessageType.RECORD_REPORT, report)
Esempio n. 7
0
    def _slave_request(self, camera_pixmap):
        """向 slave 索取指定圖像

        藉由 camera_pixmap 的資料去向 slave 索取圖像

        Args:
            camera_pixmap: CameraPixmap

        """
        message_manager.send_message(MessageType.GET_SHOT_IMAGE,
                                     camera_pixmap.get_parms())
Esempio n. 8
0
    def _run(self):
        while self._running:
            camera_image = self._get_buffer()

            if camera_image is None:
                break

            encoded_data = camera_image.convert_jpeg(**self._encode_parms)

            message_manager.send_message(MessageType.LIVE_VIEW_IMAGE,
                                         {'camera_id': self._camera_id},
                                         encoded_data)
Esempio n. 9
0
    def record(self):
        """開關錄製

        根據目前的 shot 選擇去啟動錄製
        如果已在錄製中便關閉,並創建該 shot 的錄製回報蒐集器

        """
        self._is_recording = not self._is_recording

        ui.dispatch_event(
            UIEventType.RECORDING,
            self._is_recording
        )

        parms = {
            'is_start': self._is_recording
        }

        shot_id = project_manager.current_shot.get_id()
        is_cali = project_manager.current_shot.is_cali()

        # 開啟錄製
        if self._is_recording:
            parms['shot_id'] = shot_id
            parms['is_cali'] = is_cali
            log.info('Start recording: {} / {}'.format(
                project_manager.current_project,
                project_manager.current_shot
            ))
        # 關閉錄製
        else:
            log.info('Stop recording')

            # 取得這次錄製的相機參數
            parameters = {}
            for name, parm in self._parameters.items():
                parameters[name] = parm.get_value()

            # 建立錄製報告容器
            self._report_collector.new_record_report_container(
                shot_id, parameters
            )

        message_manager.send_message(
            MessageType.TOGGLE_RECORDING,
            parms
        )

        if self._is_recording and is_cali:
            self.record()
Esempio n. 10
0
    def live_view(
        self, toggle, scale_length=150, close_up=None
    ):
        """開關相機預覽

        開關指定的相機預覽,同時設定串流品質跟尺寸

        Args:
            camera_ids: [相機ID]
            quality: 串流品質
            scale_length: 最長邊長度

        """

        if toggle:
            self._delay.execute(
                lambda:
                (
                    log.info('Toggle LiveView on'),
                    message_manager.send_message(
                        MessageType.TOGGLE_LIVE_VIEW,
                        {
                            'quality': setting.jpeg.live_view.quality,
                            'scale_length': scale_length,
                            'close_up': close_up,
                            'toggle': toggle
                        }
                    ),
                    ui.dispatch_event(
                        UIEventType.LIVE_VIEW,
                        True
                    )
                )
            )
        else:
            log.info('Toggle LiveView off')
            message_manager.send_message(
                MessageType.TOGGLE_LIVE_VIEW,
                {
                    'toggle': toggle
                }
            )
            ui.dispatch_event(
                UIEventType.LIVE_VIEW,
                False
            )
Esempio n. 11
0
    def submit_shot(self, name, frames, parameters):
        """到 deadline 放算"""
        shot = project_manager.current_shot
        log.info(f'Preparing to submit shot: {shot}')

        self._report_collector.new_submit_report_container(
            shot,
            name,
            frames,
            parameters
        )

        # 通知 Slaves 傳輸轉檔 Shot
        message_manager.send_message(
            MessageType.SUBMIT_SHOT,
            {
                'shot_id': shot.get_id(),
                'job_name': name,
                'frames': frames
            }
        )
Esempio n. 12
0
    def stop_capture(self, message=None):
        """停止擷取

        主要是用在有 slave 斷線的情況,或者要重置相機擷取的格數

        """
        for camera in self._camera_list.values():
            camera.update_status({'state': CameraState.CLOSE.value})

        if self._is_capturing and message is not None:
            node = message.unpack()
            log.warning(f'Slave [{node.get_name()}] down, restart cameras')
            time.sleep(1)
            message_manager.send_message(MessageType.MASTER_DOWN)

        self._is_capturing = False

        ui.dispatch_event(
            UIEventType.TRIGGER,
            False
        )
Esempio n. 13
0
    def _run(self):
        while self._running:
            shot_id, job_name, frames, shot_file_paths = self._queue.get()

            if shot_id is None:
                break

            self._log.info(
                'Submit shot: '
                f'{shot_id} ({frames[0]}-{frames[-1]} [{len(frames)}])')

            # 創建資料夾
            submit_image_path = f'{setting.submit_shot_path}{shot_id}/'
            os.makedirs(submit_image_path, exist_ok=True)
            self._log.debug(f'Save to {submit_image_path}')

            # 取出圖像
            for camera_id, shot_file_path in shot_file_paths.items():
                file_loader = CameraShotFileLoader(shot_file_path, self._log)

                # 進度定義
                current_count = 0
                total_count = len(frames)

                for frame in frames:
                    camera_image = file_loader.load(frame)

                    if camera_image is not None:
                        image_path = (
                            f'{submit_image_path}{camera_id}_{frame:06d}.jpg')

                        # 檢查是否有存在的檔案並大小差不多
                        is_exist = False
                        if os.path.isfile(image_path):
                            exist_size = os.stat(image_path).st_size

                            # 大小超過閥值,略過
                            if exist_size > setting.bypass_exist_size:
                                is_exist = True

                        # 轉檔與儲存
                        if not is_exist:
                            jpg_data = camera_image.convert_jpeg(
                                setting.jpeg.submit.quality)
                            with open(image_path, 'wb') as f:
                                f.write(jpg_data)

                    else:
                        self._log.error(f'{camera_id} missing frame {frame}')

                    # 進度整理
                    current_count += 1

                    # 傳送進度報告
                    message_manager.send_message(
                        MessageType.SUBMIT_REPORT, {
                            'camera_id': camera_id,
                            'shot_id': shot_id,
                            'job_name': job_name,
                            'progress': (current_count, total_count)
                        })
Esempio n. 14
0
 def _report_status(self):
     message_manager.send_message(MessageType.CAMERA_STATUS, {
         self._camera_connector.get_id():
         self._camera_connector.get_status()
     })