예제 #1
0
    def init_capture(self,uid,size,fps):


        if uid is not None:
            self.capture = uvc.Capture(uid)
        else:
            self.capture = Fake_Capture()
        self.uid = uid


        self.frame_size = size
        self.frame_rate = fps


        if 'C930e' in self.capture.name:
            logger.debug('Timestamp offset for c930 applied: -0.1sec')
            self.ts_offset = -0.1
        else:
            self.ts_offset = 0.0


        #UVC setting quirks:
        controls_dict = dict([(c.display_name,c) for c in self.capture.controls])
        try:
            controls_dict['Auto Focus'].value = 0
        except KeyError:
            pass

        if "Pupil Cam1" in self.capture.name or "USB2.0 Camera" in self.capture.name:
            self.capture.bandwidth_factor = 1.3

            if "ID0" in self.capture.name or "ID1" in self.capture.name:
                try:
                    # Auto Exposure Priority = 1 leads to reduced framerates under low light and corrupt timestamps.
                    controls_dict['Auto Exposure Priority'].value = 1
                except KeyError:
                    pass

                try:
                    controls_dict['Absolute Exposure Time'].value = 59
                except KeyError:
                    pass


        try:
            controls_dict['Auto Focus'].value = 0
        except KeyError:
            pass
예제 #2
0
    def init_capture(self,uid):
        self.uid = uid

        if uid is not None:
            self.capture = uvc.Capture(uid)
        else:
            self.capture = Fake_Capture()

        if 'C930e' in self.capture.name:
                logger.debug('Timestamp offset for c930 applied: -0.1sec')
                self.ts_offset = -0.1
        else:
            self.ts_offset = 0.0


        #UVC setting quirks:
        controls_dict = dict([(c.display_name,c) for c in self.capture.controls])
        try:
            controls_dict['Auto Focus'].value = 0
        except KeyError:
            pass

        if "Pupil Cam1" in self.capture.name or "USB2.0 Camera" in self.capture.name:
            self.capture.bandwidth_factor = 1.8
            if "ID0" in self.capture.name or "ID1" in self.capture.name:
                self.capture.bandwidth_factor = 1.3
                try:
                    controls_dict['Auto Exposure Priority'].value = 1
                except KeyError:
                    pass
                try:
                    controls_dict['Saturation'].value = 0
                except KeyError:
                    pass
                try:
                    controls_dict['Absolute Exposure Time'].value = 63
                except KeyError:
                    pass
            try:
                controls_dict['Auto Focus'].value = 0
            except KeyError:
                pass
예제 #3
0
파일: uvc_capture.py 프로젝트: tz-lom/pupil
    def init_capture(self,uid,size,fps):


        if uid is not None:
            self.capture = uvc.Capture(uid)
        else:
            self.capture = Fake_Capture()
        self.uid = uid


        self.frame_size = size
        self.frame_rate = fps


        if 'C930e' in self.capture.name:
            logger.debug('Timestamp offset for c930 applied: -0.1sec')
            self.ts_offset = -0.1
        else:
            self.ts_offset = 0.0


        #UVC setting quirks:
        controls_dict = dict([(c.display_name,c) for c in self.capture.controls])
        try:
            controls_dict['Auto Focus'].value = 0
        except KeyError:
            pass

        if "Pupil Cam1" in self.capture.name or "USB2.0 Camera" in self.capture.name:
            self.capture.bandwidth_factor = 1.3

            if "ID0" in self.capture.name or "ID1" in self.capture.name:
                try:
                    # Auto Exposure Priority = 1 leads to reduced framerates under low light and corrupt timestamps.
                    controls_dict['Auto Exposure Priority'].value = 1
                except KeyError:
                    pass

                try:
                    controls_dict['Absolute Exposure Time'].value = 59
                except KeyError:
                    pass


        try:
            controls_dict['Auto Focus'].value = 0
        except KeyError:
            pass
예제 #4
0
class Camera_Capture(object):
    """
    Camera Capture encapsulates the videoInput class
    """
    deviceSettings = None
    captureSettings = None
    device = None
    stream = None

    menu = None
    sidebar = None
    width = 640
    height = 480
    preferred_fps = 30
    fps_mediatype_map = None  # list of tuples in form of: (fps, media_type_index)

    readSetting = None
    _frame = None

    _is_initialized = False
    _failed_inits = 0

    @property
    def settings(self):
        settings = {}
        settings['name'] = self.name
        settings['frame_rate'] = self.frame_rate
        settings['frame_size'] = self.frame_size
        return settings

    @settings.setter
    def settings(self, settings):
        self.frame_size = settings['frame_size']
        self.frame_rate = settings['frame_rate']

    @property
    def name(self):
        if self.uid is not None:
            return str(self.device['name'])
        else:
            return "Fake Capture"

    @property
    def actual_width(self):
        if self.uid is not None:
            return self.stream.listMediaType[
                self.deviceSettings.indexMediaType].width
        else:
            return self.width

    @property
    def actual_height(self):
        if self.uid is not None:
            return self.stream.listMediaType[
                self.deviceSettings.indexMediaType].height
        else:
            return self.height

    @property
    def src_id(self):
        return self.uid

    def __init__(self, uid, size=(640, 480), fps=None, timebase=None):
        self.init_capture(uid, size, fps)

    def re_init_capture(self, uid, size=(640, 480), fps=None):
        if self.sidebar is None:
            self._close_device()
            self.init_capture(uid, size, fps)
        else:
            self.deinit_gui()
            self._close_device()
            self.init_capture(uid, size, fps)
            self.init_gui(self.sidebar)
            self.menu.collapsed = False

    def init_capture(self, uid, size=(640, 480), fps=None, timebase=None):
        self.uid = uid
        if uid is not None:
            # validate parameter UID
            devices = device_list(
            )  # TODO: read list only once (initially) to save runtime
            for device in devices:
                print
                if device['uid'] == uid:
                    break
            if device['uid'] != uid:
                msg = ERR_INIT_FAIL + "UID of camera was not found."
                logger.error(msg)
                self.init_capture(None, size, fps, timebase)
                return

            # validate parameter SIZE
            if not len(size) == 2:
                msg = ERR_INIT_FAIL + "Parameter 'size' must have length 2."
                logger.error(msg)
                self.init_capture(None, size, fps, timebase)
                return

            # setting up device
            self.device = device
            self.deviceSettings = vi.DeviceSettings()
            self.deviceSettings.symbolicLink = self.device['uid']
            self.deviceSettings.indexStream = 0
            self.deviceSettings.indexMediaType = 0
            self.captureSettings = vi.CaptureSettings()
            self.captureSettings.readMode = vi.ReadMode.SYNC
            self.captureSettings.videoFormat = vi.CaptureVideoFormat.RGB32
            self.stream = self.device['handle'].listStream[
                self.deviceSettings.indexStream]

            # set timebase
            if timebase == None:
                logger.debug("Capture will run with default system timebase")
                self.timebase = 0
            else:
                logger.debug(
                    "Capture will run with app wide adjustable timebase")
                self.timebase = timebase

            # set properties
            self.width = size[0]
            self.height = size[1]
            self.preferred_fps = fps
            self._initFrameRates()
            self._initMediaTypeId()

            # robust camera initialization
            self.context = _getVideoInputInstance()
            while True:
                res = self.context.setupDevice(self.deviceSettings,
                                               self.captureSettings)
                if res != vi.ResultCode.OK:
                    self._failed_inits += 1
                    msg = ERR_INIT_FAIL + "Fall back to Fake Capture. Error code: %d" % (
                        res)
                    if self._failed_inits < MAX_RETRY_INIT_CAMERA:
                        logger.warning(
                            "Retry initializing camera: {0}/{1}: ".format(
                                self._failed_inits, MAX_RETRY_INIT_CAMERA) +
                            msg)
                    else:
                        logger.error(msg)
                        self._failed_inits = 0
                        self.init_capture(None, size, fps, timebase)
                        return
                    sleep(0.25)
                else:
                    break

            # creating frame buffer and initializing capture settings
            frame = np.empty((self.actual_height * self.actual_width * 4),
                             dtype=np.uint8)
            self.readSetting = vi.ReadSetting()
            self.readSetting.symbolicLink = self.deviceSettings.symbolicLink
            self.readSetting.setNumpyArray(frame)
            frame.shape = (self.actual_height, self.actual_width, -1)
            self._frame = frame

            logger.debug(
                "Successfully set up device: %s @ %dx%dpx %dfps (mediatype %d)"
                % (self.name, self.actual_height, self.actual_width,
                   self.frame_rate, self.deviceSettings.indexMediaType))
        else:
            self.device = Fake_Capture()
            self.width = size[0]
            self.height = size[1]
            self.preferred_fps = fps
        self._is_initialized = True
        self._failed_inits = 0

    def get_frame(self):
        if self.uid is not None:
            res = self.context.readPixels(self.readSetting)
            if res == vi.ResultCode.READINGPIXELS_REJECTED_TIMEOUT:
                for n in range(MAX_RETRY_GRABBING_FRAMES):
                    logger.warning(
                        "Retry reading frame: {0}/{1}. Error code: {2}".format(
                            n + 1, MAX_RETRY_GRABBING_FRAMES, res))
                    res = self.context.readPixels(self.readSetting)
                    if res == vi.ResultCode.READINGPIXELS_DONE:
                        break
            if res != vi.ResultCode.READINGPIXELS_DONE:
                msg = "Could not read frame. Fall back to Fake Capture. Error code: %d" % (
                    res)
                logger.error(msg)
                self.re_init_capture(None, self.frame_size, self.preferred_fps)
                return self.get_frame()
            frame = Frame(self.get_now() - self.timebase, self._frame)
            return frame
        else:
            return self.device.get_frame_robust()

    @property
    def frame_rate(self):
        if self.uid is not None:
            return self.stream.listMediaType[
                self.deviceSettings.indexMediaType].MF_MT_FRAME_RATE
        else:
            return self.preferred_fps

    @frame_rate.setter
    def frame_rate(self, preferred_fps):
        self.re_init_capture(self.uid, (self.width, self.height),
                             preferred_fps)

    @property
    def available_frame_rates(self):
        fps_list = []
        for fps, _ in self.fps_mediatype_map:
            fps_list.append(fps)
        return fps_list

    @property
    def frame_size(self):
        return (self.actual_width, self.actual_height)

    @frame_size.setter
    def frame_size(self, size):
        self.re_init_capture(self.uid, size, self.preferred_fps)

    @property
    def available_frame_sizes(self):
        size_list = []
        for size in self.size_mediatype_map:
            size_list.append(size)
        return size_list

    @property
    def jpeg_support(self):
        return False

    def get_now(self):
        return time()

    def get_timestamp():
        return self.get_now() - self.timebase.value

    def init_gui(self, sidebar):
        def gui_init_cam(uid):
            logger.debug("selected new device: " + str(uid))
            self.re_init_capture(uid, (self.width, self.height),
                                 self.preferred_fps)

        def gui_get_cam():
            return self.uid

        def gui_get_frame_size():
            return self.frame_size

        def gui_set_frame_size(new_size):
            self.frame_size = new_size

        def gui_get_frame_rate():
            return self.frame_rate

        def gui_set_frame_rate(new_fps):
            self.frame_rate = new_fps

        #create the menu entry
        self.menu = ui.Growing_Menu(label='Camera Settings')

        self.menu.append(ui.Info_Text("Device: " + self.name))
        # TODO: refresh button for capture list. Make properties that refresh on reading...
        cams = device_list()
        cam_names = ['Fake Capture'] + [str(c["name"]) for c in cams]
        cam_devices = [None] + [c["uid"] for c in cams]
        self.menu.append(
            ui.Selector('device',
                        self,
                        selection=cam_devices,
                        labels=cam_names,
                        label='Capture Device',
                        getter=gui_get_cam,
                        setter=gui_init_cam))

        #hardware_ts_switch = ui.Switch('use_hw_ts',self,label='use hardware timestamps')
        #hardware_ts_switch.read_only = True
        #self.menu.append(hardware_ts_switch)

        #self.menu.append(ui.Selector('frame_size', selection=self.available_frame_sizes, label='Frame Size', getter=gui_get_frame_size, setter=gui_set_frame_size))
        if self.uid is not None:
            self.menu.append(
                ui.Info_Text("Resolution: {0} x {1} pixels".format(
                    self.actual_width, self.actual_height)))
            self.menu.append(
                ui.Selector('frame_rate',
                            selection=self.available_frame_rates,
                            label='Frame Rate',
                            getter=gui_get_frame_rate,
                            setter=gui_set_frame_rate))

        # for control in self.controls:
        #     c = None
        #     ctl_name = control['name']

        #     # we use closures as setters and getters for each control element
        #     def make_setter(control):
        #         def fn(val):
        #             self.capture.set_control(control['id'],val)
        #             control['value'] = self.capture.get_control(control['id'])
        #         return fn
        #     def make_getter(control):
        #         def fn():
        #             return control['value']
        #         return fn
        #     set_ctl = make_setter(control)
        #     get_ctl = make_getter(control)

        #     #now we add controls
        #     if control['type']=='bool':
        #         c = ui.Switch(ctl_name,getter=get_ctl,setter=set_ctl)
        #     elif control['type']=='int':
        #         c = ui.Slider(ctl_name,getter=get_ctl,min=control['min'],max=control['max'],
        #                         step=control['step'], setter=set_ctl)

        #     elif control['type']=="menu":
        #         if control['menu'] is None:
        #             selection = range(control['min'],control['max']+1,control['step'])
        #             labels = selection
        #         else:
        #             selection = [value for name,value in control['menu'].iteritems()]
        #             labels = [name for name,value in control['menu'].iteritems()]
        #         c = ui.Selector(ctl_name,getter=get_ctl,selection=selection,labels = labels,setter=set_ctl)
        #     else:
        #         pass
        #     if control['disabled']:
        #         c.read_only = True
        #     if ctl_name == 'Exposure, Auto Priority':
        #         # the controll should always be off. we set it to 0 on init (see above)
        #         c.read_only = True

        #     if c is not None:
        #         self.menu.append(c)

        # self.menu.append(ui.Button("refresh",gui_update_from_device))
        # self.menu.append(ui.Button("load defaults",gui_load_defaults))
        self.menu.collapsed = True
        self.sidebar = sidebar
        #add below geneal settings
        self.sidebar.insert(1, self.menu)

    def deinit_gui(self):
        if self.menu:
            self.sidebar.remove(self.menu)
            self.menu = None

    def close(self):
        self.deinit_gui()
        self._close_device()

    def _close_device(self):
        if self.uid is None:
            return
        if self._is_initialized:
            self._is_initialized = False
            res = self.context.closeDevice(self.deviceSettings)
            if res != vi.ResultCode.OK:
                msg = "Error while closing the capture device. Error code: %s" % res
                logger.error(msg)
                raise CameraCaptureError(msg)

    def _initFrameRates(self):
        """ Reads out possible frame-rates for a given resolution and stores result as internal frame-rate map. """
        self.fps_mediatype_map = []
        tmp_fps_values = []
        self.size_mediatype_map = []
        media_types = self.stream.listMediaType
        for mt, i in zip(media_types, range(len(media_types))):
            size_tuple = (mt.width, mt.height)
            # add distinct resolutions
            if not size_tuple in self.size_mediatype_map:
                self.size_mediatype_map.append(size_tuple)
            if mt.width == self.width and mt.height == self.height:
                # add distinct frame-rate options
                if not mt.MF_MT_FRAME_RATE in tmp_fps_values:
                    tmp_fps_values.append(mt.MF_MT_FRAME_RATE)
                    self.fps_mediatype_map.append((mt.MF_MT_FRAME_RATE, i))

        if not self.fps_mediatype_map:
            msg = ERR_INIT_FAIL + "Capture device does not support resolution: %d x %d" % (
                self.width, self.height)
            logger.error(msg)
            raise CameraCaptureError(msg)

        logger.debug(
            "found %d media types for given resolution: %s" %
            (len(self.fps_mediatype_map), str(self.fps_mediatype_map)))
        self.fps_mediatype_map.sort()

    def _initMediaTypeId(self):
        """ Selects device by setting media-type ID based on previously initialized frame-rate map. """
        match = None
        # choose highest framerate if none is given
        if self.preferred_fps is None:
            match = self.fps_mediatype_map[-1]
        else:
            # choose best match (fps +/- .25 is ok)
            for fps, i in self.fps_mediatype_map:
                if abs(fps - self.preferred_fps) < .25:
                    match = (fps, i)
                    break
            # if none is found, choose highest framerate
            if match is None:
                logger.warn(
                    "Capture device does not support preferred frame-rate %d" %
                    (self.preferred_fps))
                match = self.fps_mediatype_map[-1]
        self.deviceSettings.indexMediaType = match[1]
예제 #5
0
    def init_capture(self, uid, size=(640, 480), fps=None, timebase=None):
        self.uid = uid
        if uid is not None:
            # validate parameter UID
            devices = device_list(
            )  # TODO: read list only once (initially) to save runtime
            for device in devices:
                print
                if device['uid'] == uid:
                    break
            if device['uid'] != uid:
                msg = ERR_INIT_FAIL + "UID of camera was not found."
                logger.error(msg)
                self.init_capture(None, size, fps, timebase)
                return

            # validate parameter SIZE
            if not len(size) == 2:
                msg = ERR_INIT_FAIL + "Parameter 'size' must have length 2."
                logger.error(msg)
                self.init_capture(None, size, fps, timebase)
                return

            # setting up device
            self.device = device
            self.deviceSettings = vi.DeviceSettings()
            self.deviceSettings.symbolicLink = self.device['uid']
            self.deviceSettings.indexStream = 0
            self.deviceSettings.indexMediaType = 0
            self.captureSettings = vi.CaptureSettings()
            self.captureSettings.readMode = vi.ReadMode.SYNC
            self.captureSettings.videoFormat = vi.CaptureVideoFormat.RGB32
            self.stream = self.device['handle'].listStream[
                self.deviceSettings.indexStream]

            # set timebase
            if timebase == None:
                logger.debug("Capture will run with default system timebase")
                self.timebase = 0
            else:
                logger.debug(
                    "Capture will run with app wide adjustable timebase")
                self.timebase = timebase

            # set properties
            self.width = size[0]
            self.height = size[1]
            self.preferred_fps = fps
            self._initFrameRates()
            self._initMediaTypeId()

            # robust camera initialization
            self.context = _getVideoInputInstance()
            while True:
                res = self.context.setupDevice(self.deviceSettings,
                                               self.captureSettings)
                if res != vi.ResultCode.OK:
                    self._failed_inits += 1
                    msg = ERR_INIT_FAIL + "Fall back to Fake Capture. Error code: %d" % (
                        res)
                    if self._failed_inits < MAX_RETRY_INIT_CAMERA:
                        logger.warning(
                            "Retry initializing camera: {0}/{1}: ".format(
                                self._failed_inits, MAX_RETRY_INIT_CAMERA) +
                            msg)
                    else:
                        logger.error(msg)
                        self._failed_inits = 0
                        self.init_capture(None, size, fps, timebase)
                        return
                    sleep(0.25)
                else:
                    break

            # creating frame buffer and initializing capture settings
            frame = np.empty((self.actual_height * self.actual_width * 4),
                             dtype=np.uint8)
            self.readSetting = vi.ReadSetting()
            self.readSetting.symbolicLink = self.deviceSettings.symbolicLink
            self.readSetting.setNumpyArray(frame)
            frame.shape = (self.actual_height, self.actual_width, -1)
            self._frame = frame

            logger.debug(
                "Successfully set up device: %s @ %dx%dpx %dfps (mediatype %d)"
                % (self.name, self.actual_height, self.actual_width,
                   self.frame_rate, self.deviceSettings.indexMediaType))
        else:
            self.device = Fake_Capture()
            self.width = size[0]
            self.height = size[1]
            self.preferred_fps = fps
        self._is_initialized = True
        self._failed_inits = 0
예제 #6
0
class Camera_Capture(object):
    """
    Camera Capture is a class that encapsualtes uvc.Capture:
     - adds UI elements
     - adds timestamping sanitization fns.
    """
    def __init__(self, uid, timebase=None):
        if timebase == None:
            logger.debug("Capture will run with default system timebase")
            self.timebase = c_double(0)
        elif hasattr(timebase, 'value'):
            logger.debug("Capture will run with app wide adjustable timebase")
            self.timebase = timebase
        else:
            logger.error(
                "Invalid timebase variable type. Will use default system timebase"
            )
            self.timebase = c_double(0)

        self.sidebar = None
        self.menu = None
        self.init_capture(uid)

    def re_init_capture(self, uid):
        current_size = self.capture.frame_size
        current_fps = self.capture.frame_rate

        self.capture = None
        #recreate the bar with new values
        menu_conf = self.menu.configuration
        self.deinit_gui()
        self.init_capture(uid)
        self.frame_size = current_size
        self.frame_rate = current_fps
        self.init_gui(self.sidebar)
        self.menu.configuration = menu_conf

    def init_capture(self, uid):
        self.uid = uid

        if uid is not None:
            self.capture = uvc.Capture(uid)
        else:
            self.capture = Fake_Capture()

        if 'C930e' in self.capture.name:
            logger.debug('Timestamp offset for c930 applied: -0.1sec')
            self.ts_offset = -0.1
        else:
            self.ts_offset = 0.0

        #UVC setting quirks:
        controls_dict = dict([(c.display_name, c)
                              for c in self.capture.controls])
        try:
            controls_dict['Auto Focus'].value = 0
        except KeyError:
            pass

        if "Pupil Cam1" in self.capture.name or "USB2.0 Camera" in self.capture.name:
            self.capture.bandwidth_factor = 1.3
            if "ID0" in self.capture.name or "ID1" in self.capture.name:
                try:
                    controls_dict['Auto Exposure Priority'].value = 1
                except KeyError:
                    pass
                try:
                    controls_dict['Absolute Exposure Time'].value = 59
                except KeyError:
                    pass
            try:
                controls_dict['Auto Focus'].value = 0
            except KeyError:
                pass

    def get_frame(self):
        try:
            frame = self.capture.get_frame_robust()
        except:
            raise CameraCaptureError("Could not get frame from %s" % self.uid)

        timestamp = self.get_now() + self.ts_offset
        timestamp -= self.timebase.value
        frame.timestamp = timestamp
        return frame

    def get_now(self):
        return time()

    def get_timestamp(self):
        return self.get_now() - self.timebase.value

    @property
    def frame_rate(self):
        return self.capture.frame_rate

    @frame_rate.setter
    def frame_rate(self, new_rate):
        #closest match for rate
        rates = [abs(r - new_rate) for r in self.capture.frame_rates]
        best_rate_idx = rates.index(min(rates))
        rate = self.capture.frame_rates[best_rate_idx]
        if rate != new_rate:
            logger.warning(
                "%sfps capture mode not available at (%s) on '%s'. Selected %sfps. "
                % (new_rate, self.capture.frame_size, self.capture.name, rate))
        self.capture.frame_rate = rate

    @property
    def settings(self):
        settings = {}
        settings['name'] = self.capture.name
        settings['frame_rate'] = self.frame_rate
        settings['frame_size'] = self.frame_size
        settings['uvc_controls'] = {}
        for c in self.capture.controls:
            settings['uvc_controls'][c.display_name] = c.value
        return settings

    @settings.setter
    def settings(self, settings):
        self.frame_size = settings['frame_size']
        self.frame_rate = settings['frame_rate']
        for c in self.capture.controls:
            try:
                c.value = settings['uvc_controls'][c.display_name]
            except KeyError as e:
                logger.info('No UVC setting "%s" found from settings.' %
                            c.display_name)

    @property
    def frame_size(self):
        return self.capture.frame_size

    @frame_size.setter
    def frame_size(self, new_size):
        #closest match for size
        sizes = [abs(r[0] - new_size[0]) for r in self.capture.frame_sizes]
        best_size_idx = sizes.index(min(sizes))
        size = self.capture.frame_sizes[best_size_idx]
        if size != new_size:
            logger.warning(
                "%s resolution capture mode not available. Selected %s." %
                (new_size, size))
        self.capture.frame_size = size

    @property
    def name(self):
        return self.capture.name

    @property
    def jpeg_support(self):
        if self.capture.__class__ is Fake_Capture:
            return False
        else:
            return True

    def init_gui(self, sidebar):

        #lets define some  helper functions:
        def gui_load_defaults():
            for c in self.capture.controls:
                try:
                    c.value = c.def_val
                except:
                    pass

        def set_size(new_size):
            self.frame_size = new_size
            menu_conf = self.menu.configuration
            self.deinit_gui()
            self.init_gui(self.sidebar)
            self.menu.configuration = menu_conf

        def gui_update_from_device():
            for c in self.capture.controls:
                c.refresh()

        def gui_init_cam_by_uid(requested_id):
            if requested_id is None:
                self.re_init_capture(None)
            else:
                for cam in uvc.device_list():
                    if cam['uid'] == requested_id:
                        if is_accessible(requested_id):
                            self.re_init_capture(requested_id)
                        else:
                            logger.error(
                                "The selected Camera is already in use or blocked."
                            )
                        return
                logger.warning(
                    "could not reinit capture, src_id not valid anymore")
                return

        #create the menu entry
        self.menu = ui.Growing_Menu(label='Camera Settings')
        cameras = uvc.device_list()
        camera_names = ['Fake Capture'] + [c['name'] for c in cameras]
        camera_ids = [None] + [c['uid'] for c in cameras]
        self.menu.append(
            ui.Selector('uid',
                        self,
                        selection=camera_ids,
                        labels=camera_names,
                        label='Capture Device',
                        setter=gui_init_cam_by_uid))

        sensor_control = ui.Growing_Menu(label='Sensor Settings')
        sensor_control.append(
            ui.Info_Text(
                "Do not change these during calibration or recording!"))
        sensor_control.collapsed = False
        image_processing = ui.Growing_Menu(label='Image Post Processing')
        image_processing.collapsed = True

        sensor_control.append(
            ui.Selector('frame_size',
                        self,
                        setter=set_size,
                        selection=self.capture.frame_sizes,
                        label='Resolution'))
        sensor_control.append(
            ui.Selector('frame_rate',
                        self,
                        selection=self.capture.frame_rates,
                        label='Framerate'))

        for control in self.capture.controls:
            c = None
            ctl_name = control.display_name

            #now we add controls
            if control.d_type == bool:
                c = ui.Switch('value',
                              control,
                              label=ctl_name,
                              on_val=control.max_val,
                              off_val=control.min_val)
            elif control.d_type == int:
                c = ui.Slider('value',
                              control,
                              label=ctl_name,
                              min=control.min_val,
                              max=control.max_val,
                              step=control.step)
            elif type(control.d_type) == dict:
                selection = [
                    value for name, value in control.d_type.iteritems()
                ]
                labels = [name for name, value in control.d_type.iteritems()]
                c = ui.Selector('value',
                                control,
                                label=ctl_name,
                                selection=selection,
                                labels=labels)
            else:
                pass
            # if control['disabled']:
            #     c.read_only = True
            # if ctl_name == 'Exposure, Auto Priority':
            #     # the controll should always be off. we set it to 0 on init (see above)
            #     c.read_only = True

            if c is not None:
                if control.unit == 'processing_unit':
                    image_processing.append(c)
                else:
                    sensor_control.append(c)

        self.menu.append(sensor_control)
        if image_processing.elements:
            self.menu.append(image_processing)
        self.menu.append(ui.Button("refresh", gui_update_from_device))
        self.menu.append(ui.Button("load defaults", gui_load_defaults))

        self.sidebar = sidebar
        #add below geneal settings
        self.sidebar.insert(1, self.menu)

    def deinit_gui(self):
        if self.menu:
            self.sidebar.remove(self.menu)
            self.menu = None

    def close(self):
        self.deinit_gui()
        # self.capture.close()
        del self.capture
        logger.info("Capture released")
예제 #7
0
class Camera_Capture(object):
    """
    Camera Capture is a class that encapsualtes uvc.Capture:
     - adds UI elements
     - adds timestamping sanitization fns.
    """
    def __init__(self,uid,timebase=None):
        if timebase == None:
            logger.debug("Capture will run with default system timebase")
            self.timebase = c_double(0)
        elif hasattr(timebase,'value'):
            logger.debug("Capture will run with app wide adjustable timebase")
            self.timebase = timebase
        else:
            logger.error("Invalid timebase variable type. Will use default system timebase")
            self.timebase = c_double(0)

        self.sidebar = None
        self.menu = None
        self.init_capture(uid)


    def re_init_capture(self,uid):
        current_size = self.capture.frame_size
        current_fps = self.capture.frame_rate
        self.capture = None
        if self.menu:
            #recreate the bar with new values
            menu_conf = self.menu.configuration
        else:
            menu_conf = None
        self.deinit_gui()
        self.init_capture(uid)
        self.frame_size = current_size
        self.frame_rate = current_fps
        if menu_conf:
            self.init_gui(self.sidebar)
            self.menu.configuration = menu_conf

    def _re_init_capture_by_name(self,name):
        for x in range(4):
            devices = device_list()
            for d in devices:
                if d['name'] == name:
                    logger.info("Found device.%s."%name)
                    self.re_init_capture(d['uid'])
                    return
            logger.warning('Could not find Camera %s during re initilization.'%name)
            sleep(1.5)
        raise CameraCaptureError('Could not find Camera %s during re initilization.'%name)

    def init_capture(self,uid):
        self.uid = uid

        if uid is None:
            self.capture = Fake_Capture()
        else:
            self.capture = uvc.Capture(uid)

        if 'C930e' in self.capture.name:
                logger.debug('Timestamp offset for c930 applied: -0.1sec')
                self.ts_offset = -0.1
        else:
            self.ts_offset = 0.0


        #UVC setting quirks:
        controls_dict = dict([(c.display_name,c) for c in self.capture.controls])
        try:
            controls_dict['Auto Focus'].value = 0
        except KeyError:
            pass

        if "Pupil Cam1" in self.capture.name or "USB2.0 Camera" in self.capture.name:
            self.capture.bandwidth_factor = 1.8
            if "ID0" in self.capture.name or "ID1" in self.capture.name:
                self.capture.bandwidth_factor = 1.3
                try:
                    controls_dict['Auto Exposure Priority'].value = 0
                except KeyError:
                    pass
                try:
                    # print controls_dict['Auto Exposure Mode'].value
                    controls_dict['Auto Exposure Mode'].value = 1
                except KeyError as e:
                    pass
                try:
                    controls_dict['Saturation'].value = 0
                except KeyError:
                    pass
                try:
                    controls_dict['Absolute Exposure Time'].value = 63
                except KeyError:
                    pass
                try:
                    controls_dict['Backlight Compensation'].value = 2
                except KeyError:
                    pass
                try:
                    controls_dict['Gamma'].value = 100
                except KeyError:
                    pass
            else:
                self.capture.bandwidth_factor = 1.8
                try:
                    controls_dict['Auto Exposure Priority'].value = 1
                except KeyError:
                    pass
        if "C525" in self.capture.name or  "B525" in self.capture.name or "C920" in self.capture.name:
            self.capture.bandwidth_factor = 4.0
            try:
                controls_dict['Auto Focus'].value = 0
            except KeyError:
                pass

    def get_frame(self):
        try:
            frame = self.capture.get_frame_robust()
        except uvc.CaptureError as e:
            try:
                self._re_init_capture_by_name(self.capture.name)
                frame = self.capture.get_frame_robust()
            except uvc.CaptureError as e:
                raise CameraCaptureError("Could not get frame from %s"%self.uid)

        timestamp = self.get_now()+self.ts_offset
        timestamp -= self.timebase.value
        frame.timestamp = timestamp
        return frame

    def get_now(self):
        return uvc.get_time_monotonic()

    def get_timestamp(self):
        return self.get_now()-self.timebase.value

    @property
    def frame_rate(self):
        return self.capture.frame_rate
    @frame_rate.setter
    def frame_rate(self,new_rate):
        #closest match for rate
        rates = [ abs(r-new_rate) for r in self.capture.frame_rates ]
        best_rate_idx = rates.index(min(rates))
        rate = self.capture.frame_rates[best_rate_idx]
        if rate != new_rate:
            logger.warning("%sfps capture mode not available at (%s) on '%s'. Selected %sfps. "%(new_rate,self.capture.frame_size,self.capture.name,rate))
        self.capture.frame_rate = rate


    @property
    def settings(self):
        settings = {}
        settings['name'] = self.capture.name
        settings['frame_rate'] = self.frame_rate
        settings['frame_size'] = self.frame_size
        settings['uvc_controls'] = {}
        for c in self.capture.controls:
            settings['uvc_controls'][c.display_name] = c.value
        return settings
    @settings.setter
    def settings(self,settings):
        self.frame_size = settings['frame_size']
        self.frame_rate = settings['frame_rate']
        for c in self.capture.controls:
            try:
                c.value = settings['uvc_controls'][c.display_name]
            except KeyError as e:
                logger.debug('No UVC setting "%s" found from settings.'%c.display_name)
    @property
    def frame_size(self):
        return self.capture.frame_size
    @frame_size.setter
    def frame_size(self,new_size):
        #closest match for size
        sizes = [ abs(r[0]-new_size[0]) for r in self.capture.frame_sizes ]
        best_size_idx = sizes.index(min(sizes))
        size = self.capture.frame_sizes[best_size_idx]
        if size != new_size:
            logger.warning("%s resolution capture mode not available. Selected %s."%(new_size,size))
        self.capture.frame_size = size

        if hasattr(self,'on_frame_size_change'):
            self.on_frame_size_change(size)

    @property
    def name(self):
        return self.capture.name


    @property
    def jpeg_support(self):
        if self.capture.__class__ is Fake_Capture:
            return False
        else:
            return True

    def init_gui(self,sidebar):

        #lets define some  helper functions:
        def gui_load_defaults():
            for c in self.capture.controls:
                try:
                    c.value = c.def_val
                except:
                    pass
        def set_size(new_size):
            self.frame_size = new_size
            menu_conf = self.menu.configuration
            self.deinit_gui()
            self.init_gui(self.sidebar)
            self.menu.configuration = menu_conf


        def gui_update_from_device():
            for c in self.capture.controls:
                c.refresh()

        def gui_init_cam_by_uid(requested_id):
            if requested_id is None:
                self.re_init_capture(None)
            else:
                for cam in uvc.device_list():
                    if cam['uid'] == requested_id:
                        if is_accessible(requested_id):
                            self.re_init_capture(requested_id)
                        else:
                            logger.error("The selected Camera is already in use or blocked.")
                        return
                logger.warning("could not reinit capture, src_id not valid anymore")
                return

        #create the menu entry
        self.menu = ui.Growing_Menu(label='Camera Settings')
        cameras = uvc.device_list()
        camera_names = ['Fake Capture']+[c['name'] for c in cameras]
        camera_ids = [None]+[c['uid'] for c in cameras]
        self.menu.append(ui.Selector('uid',self,selection=camera_ids,labels=camera_names,label='Capture device', setter=gui_init_cam_by_uid) )

        sensor_control = ui.Growing_Menu(label='Sensor Settings')
        sensor_control.append(ui.Info_Text("Do not change these during calibration or recording!"))
        sensor_control.collapsed=False
        image_processing = ui.Growing_Menu(label='Image Post Processing')
        image_processing.collapsed=True

        sensor_control.append(ui.Selector('frame_size',self,setter=set_size, selection=self.capture.frame_sizes,label='Resolution' ) )
        sensor_control.append(ui.Selector('frame_rate',self, selection=self.capture.frame_rates,label='Frame rate' ) )


        for control in self.capture.controls:
            c = None
            ctl_name = control.display_name

            #now we add controls
            if control.d_type == bool :
                c = ui.Switch('value',control,label=ctl_name, on_val=control.max_val, off_val=control.min_val)
            elif control.d_type == int:
                c = ui.Slider('value',control,label=ctl_name,min=control.min_val,max=control.max_val,step=control.step)
            elif type(control.d_type) == dict:
                selection = [value for name,value in control.d_type.iteritems()]
                labels = [name for name,value in control.d_type.iteritems()]
                c = ui.Selector('value',control, label = ctl_name, selection=selection,labels = labels)
            else:
                pass
            # if control['disabled']:
            #     c.read_only = True
            # if ctl_name == 'Exposure, Auto Priority':
            #     # the controll should always be off. we set it to 0 on init (see above)
            #     c.read_only = True

            if c is not None:
                if control.unit == 'processing_unit':
                    image_processing.append(c)
                else:
                    sensor_control.append(c)

        self.menu.append(sensor_control)
        if image_processing.elements:
            self.menu.append(image_processing)
        self.menu.append(ui.Button("refresh",gui_update_from_device))
        self.menu.append(ui.Button("load defaults",gui_load_defaults))

        self.sidebar = sidebar
        #add below geneal settings
        self.sidebar.insert(1,self.menu)


    def deinit_gui(self):
        if self.menu:
            self.sidebar.remove(self.menu)
            self.menu = None


    def close(self):
        self.deinit_gui()
        # self.capture.close()
        del self.capture
예제 #8
0
class Camera_Capture(object):
    """
    Camera Capture encapsulates the videoInput class
    """
    deviceSettings = None
    captureSettings = None
    device = None
    stream = None

    menu = None
    sidebar = None
    width = 640
    height = 480
    preferred_fps = 30
    fps_mediatype_map = None # list of tuples in form of: (fps, media_type_index)

    readSetting = None
    _frame = None

    _is_initialized = False
    _failed_inits = 0
    
    @property
    def settings(self):
        settings = {}
        settings['name'] = self.name
        settings['frame_rate'] = self.frame_rate
        settings['frame_size'] = self.frame_size
        return settings
    @settings.setter
    def settings(self,settings):
        self.frame_size = settings['frame_size']
        self.frame_rate = settings['frame_rate']


    @property
    def name(self):
        if self.uid is not None:
            return str(self.device['name'])
        else:
            return "Fake Capture"

    @property
    def actual_width(self):
        if self.uid is not None:
            return self.stream.listMediaType[self.deviceSettings.indexMediaType].width
        else:
            return self.width
            
    @property
    def actual_height(self):
        if self.uid is not None:
            return self.stream.listMediaType[self.deviceSettings.indexMediaType].height
        else:
            return self.height

    @property
    def src_id(self):
        return self.uid

    def __init__(self, uid, size=(640,480), fps=None, timebase=None):
        self.init_capture(uid, size, fps)
        
    def re_init_capture(self, uid, size=(640,480), fps=None):
        if self.sidebar is None:
            self._close_device()
            self.init_capture(uid, size, fps)
        else:
            self.deinit_gui()
            self._close_device()
            self.init_capture(uid, size, fps)
            self.init_gui(self.sidebar)
            self.menu.collapsed = False

    def init_capture(self, uid, size=(640,480), fps=None, timebase=None):
        self.uid = uid
        if uid is not None:
            # validate parameter UID
            devices = device_list() # TODO: read list only once (initially) to save runtime
            for device in devices:
                print 
                if device['uid'] == uid:
                    break
            if device['uid'] != uid:
                msg = ERR_INIT_FAIL + "UID of camera was not found."
                logger.error(msg)
                self.init_capture(None, size, fps, timebase)
                return
                
            # validate parameter SIZE
            if not len(size) == 2:
                msg = ERR_INIT_FAIL + "Parameter 'size' must have length 2."
                logger.error(msg)
                self.init_capture(None, size, fps, timebase)
                return

            # setting up device
            self.device = device
            self.deviceSettings = vi.DeviceSettings()
            self.deviceSettings.symbolicLink = self.device['uid']
            self.deviceSettings.indexStream = 0
            self.deviceSettings.indexMediaType = 0
            self.captureSettings = vi.CaptureSettings()
            self.captureSettings.readMode = vi.ReadMode.SYNC
            self.captureSettings.videoFormat = vi.CaptureVideoFormat.RGB32
            self.stream = self.device['handle'].listStream[self.deviceSettings.indexStream]

            # set timebase
            if timebase == None:
                logger.debug("Capture will run with default system timebase")
                self.timebase = 0
            else:
                logger.debug("Capture will run with app wide adjustable timebase")
                self.timebase = timebase

            # set properties
            self.width = size[0]
            self.height = size[1]
            self.preferred_fps = fps
            self._initFrameRates()
            self._initMediaTypeId()

            # robust camera initialization
            self.context = _getVideoInputInstance()
            while True:
                res = self.context.setupDevice(self.deviceSettings, self.captureSettings)
                if res != vi.ResultCode.OK:
                    self._failed_inits += 1
                    msg = ERR_INIT_FAIL + "Fall back to Fake Capture. Error code: %d" %(res)
                    if self._failed_inits < MAX_RETRY_INIT_CAMERA:
                        logger.warning("Retry initializing camera: {0}/{1}: ".format(self._failed_inits, MAX_RETRY_INIT_CAMERA) + msg)
                    else:
                        logger.error(msg)
                        self._failed_inits = 0
                        self.init_capture(None, size, fps, timebase)
                        return
                    sleep(0.25)
                else:
                    break

            # creating frame buffer and initializing capture settings
            frame = np.empty((self.actual_height * self.actual_width * 4), dtype=np.uint8)
            self.readSetting = vi.ReadSetting()
            self.readSetting.symbolicLink = self.deviceSettings.symbolicLink
            self.readSetting.setNumpyArray(frame)
            frame.shape = (self.actual_height, self.actual_width, -1)
            self._frame = frame

            logger.debug("Successfully set up device: %s @ %dx%dpx %dfps (mediatype %d)" %(self.name, self.actual_height, self.actual_width, self.frame_rate, self.deviceSettings.indexMediaType))
        else:
            self.device = Fake_Capture()
            self.width = size[0]
            self.height = size[1]
            self.preferred_fps = fps
        self._is_initialized = True
        self._failed_inits = 0

    def get_frame(self):
        if self.uid is not None:
            res = self.context.readPixels(self.readSetting)
            if res == vi.ResultCode.READINGPIXELS_REJECTED_TIMEOUT:
                for n in range(MAX_RETRY_GRABBING_FRAMES):
                    logger.warning("Retry reading frame: {0}/{1}. Error code: {2}".format(n+1, MAX_RETRY_GRABBING_FRAMES, res))
                    res = self.context.readPixels(self.readSetting)
                    if res == vi.ResultCode.READINGPIXELS_DONE:
                        break
            if res != vi.ResultCode.READINGPIXELS_DONE:
                msg = "Could not read frame. Fall back to Fake Capture. Error code: %d" %(res)
                logger.error(msg)
                self.re_init_capture(None, self.frame_size, self.preferred_fps)
                return self.get_frame()
            frame = Frame(self.get_now() - self.timebase, self._frame)
            return frame
        else:
            return self.device.get_frame_robust()

    @property
    def frame_rate(self):
        if self.uid is not None:
            return self.stream.listMediaType[self.deviceSettings.indexMediaType].MF_MT_FRAME_RATE
        else:
            return self.preferred_fps
    @frame_rate.setter
    def frame_rate(self, preferred_fps):
        self.re_init_capture(self.uid, (self.width, self.height), preferred_fps)

    @property
    def available_frame_rates(self):
        fps_list = []
        for fps, _ in self.fps_mediatype_map:
            fps_list.append(fps)
        return fps_list

    @property
    def frame_size(self):
        return (self.actual_width, self.actual_height)
    @frame_size.setter
    def frame_size(self, size):
        self.re_init_capture( self.uid, size, self.preferred_fps)

    @property
    def available_frame_sizes(self):
        size_list = []
        for size in self.size_mediatype_map:
            size_list.append(size)
        return size_list

    @property
    def jpeg_support(self):
        return False
        
    def get_now(self):
        return time()

    def get_timestamp():
        return self.get_now()-self.timebase.value

    def init_gui(self,sidebar):

        def gui_init_cam(uid):
            logger.debug("selected new device: " + str(uid))
            self.re_init_capture(uid, (self.width, self.height), self.preferred_fps)

        def gui_get_cam():
            return self.uid

        def gui_get_frame_size():
            return self.frame_size

        def gui_set_frame_size(new_size):
            self.frame_size = new_size

        def gui_get_frame_rate():
            return self.frame_rate

        def gui_set_frame_rate(new_fps):
            self.frame_rate = new_fps

        #create the menu entry
        self.menu = ui.Growing_Menu(label='Camera Settings')

        self.menu.append(ui.Info_Text("Device: " + self.name))
        # TODO: refresh button for capture list. Make properties that refresh on reading...
        cams = device_list()
        cam_names = ['Fake Capture'] + [str(c["name"]) for c in cams]
        cam_devices = [None] + [c["uid"] for c in cams]
        self.menu.append(ui.Selector('device',self,selection=cam_devices,labels=cam_names,label='Capture Device', getter=gui_get_cam, setter=gui_init_cam))

        #hardware_ts_switch = ui.Switch('use_hw_ts',self,label='use hardware timestamps')
        #hardware_ts_switch.read_only = True
        #self.menu.append(hardware_ts_switch)

        #self.menu.append(ui.Selector('frame_size', selection=self.available_frame_sizes, label='Frame Size', getter=gui_get_frame_size, setter=gui_set_frame_size))
        if self.uid is not None:
            self.menu.append(ui.Info_Text("Resolution: {0} x {1} pixels".format(self.actual_width, self.actual_height)))
            self.menu.append(ui.Selector('frame_rate', selection=self.available_frame_rates, label='Frame Rate', getter=gui_get_frame_rate, setter=gui_set_frame_rate))

        # for control in self.controls:
        #     c = None
        #     ctl_name = control['name']

        #     # we use closures as setters and getters for each control element
        #     def make_setter(control):
        #         def fn(val):
        #             self.capture.set_control(control['id'],val)
        #             control['value'] = self.capture.get_control(control['id'])
        #         return fn
        #     def make_getter(control):
        #         def fn():
        #             return control['value']
        #         return fn
        #     set_ctl = make_setter(control)
        #     get_ctl = make_getter(control)

        #     #now we add controls
        #     if control['type']=='bool':
        #         c = ui.Switch(ctl_name,getter=get_ctl,setter=set_ctl)
        #     elif control['type']=='int':
        #         c = ui.Slider(ctl_name,getter=get_ctl,min=control['min'],max=control['max'],
        #                         step=control['step'], setter=set_ctl)

        #     elif control['type']=="menu":
        #         if control['menu'] is None:
        #             selection = range(control['min'],control['max']+1,control['step'])
        #             labels = selection
        #         else:
        #             selection = [value for name,value in control['menu'].iteritems()]
        #             labels = [name for name,value in control['menu'].iteritems()]
        #         c = ui.Selector(ctl_name,getter=get_ctl,selection=selection,labels = labels,setter=set_ctl)
        #     else:
        #         pass
        #     if control['disabled']:
        #         c.read_only = True
        #     if ctl_name == 'Exposure, Auto Priority':
        #         # the controll should always be off. we set it to 0 on init (see above)
        #         c.read_only = True

        #     if c is not None:
        #         self.menu.append(c)

        # self.menu.append(ui.Button("refresh",gui_update_from_device))
        # self.menu.append(ui.Button("load defaults",gui_load_defaults))
        self.menu.collapsed = True
        self.sidebar = sidebar
        #add below geneal settings
        self.sidebar.insert(1,self.menu)

    def deinit_gui(self):
        if self.menu:
            self.sidebar.remove(self.menu)
            self.menu = None

    def close(self):
        self.deinit_gui()
        self._close_device()

    def _close_device(self):
        if self.uid is None:
            return
        if self._is_initialized:
            self._is_initialized = False
            res = self.context.closeDevice(self.deviceSettings)
            if res != vi.ResultCode.OK:
                msg = "Error while closing the capture device. Error code: %s" %res
                logger.error(msg)
                raise CameraCaptureError(msg)

    def _initFrameRates(self):
        """ Reads out possible frame-rates for a given resolution and stores result as internal frame-rate map. """
        self.fps_mediatype_map = []
        tmp_fps_values = []
        self.size_mediatype_map = []
        media_types = self.stream.listMediaType
        for mt, i in zip(media_types, range(len(media_types))):
            size_tuple = (mt.width, mt.height)
            # add distinct resolutions
            if not size_tuple in self.size_mediatype_map:
                self.size_mediatype_map.append(size_tuple)
            if mt.width == self.width and mt.height == self.height:
                # add distinct frame-rate options
                if not mt.MF_MT_FRAME_RATE in tmp_fps_values:
                    tmp_fps_values.append(mt.MF_MT_FRAME_RATE)
                    self.fps_mediatype_map.append((mt.MF_MT_FRAME_RATE, i))

        if not self.fps_mediatype_map:
            msg = ERR_INIT_FAIL + "Capture device does not support resolution: %d x %d"% (self.width, self.height)
            logger.error(msg)
            raise CameraCaptureError(msg)

        logger.debug("found %d media types for given resolution: %s" %(len(self.fps_mediatype_map), str(self.fps_mediatype_map)))
        self.fps_mediatype_map.sort()

    def _initMediaTypeId(self):
        """ Selects device by setting media-type ID based on previously initialized frame-rate map. """
        match = None
        # choose highest framerate if none is given
        if self.preferred_fps is None:
            match = self.fps_mediatype_map[-1]
        else:
            # choose best match (fps +/- .25 is ok)
            for fps, i in self.fps_mediatype_map:
                if abs(fps-self.preferred_fps) < .25:
                    match = (fps, i)
                    break
            # if none is found, choose highest framerate
            if match is None:
                logger.warn("Capture device does not support preferred frame-rate %d"% (self.preferred_fps))
                match = self.fps_mediatype_map[-1]
        self.deviceSettings.indexMediaType = match[1]
예제 #9
0
    def init_capture(self, uid, size=(640,480), fps=None, timebase=None):
        self.uid = uid
        if uid is not None:
            # validate parameter UID
            devices = device_list() # TODO: read list only once (initially) to save runtime
            for device in devices:
                print 
                if device['uid'] == uid:
                    break
            if device['uid'] != uid:
                msg = ERR_INIT_FAIL + "UID of camera was not found."
                logger.error(msg)
                self.init_capture(None, size, fps, timebase)
                return
                
            # validate parameter SIZE
            if not len(size) == 2:
                msg = ERR_INIT_FAIL + "Parameter 'size' must have length 2."
                logger.error(msg)
                self.init_capture(None, size, fps, timebase)
                return

            # setting up device
            self.device = device
            self.deviceSettings = vi.DeviceSettings()
            self.deviceSettings.symbolicLink = self.device['uid']
            self.deviceSettings.indexStream = 0
            self.deviceSettings.indexMediaType = 0
            self.captureSettings = vi.CaptureSettings()
            self.captureSettings.readMode = vi.ReadMode.SYNC
            self.captureSettings.videoFormat = vi.CaptureVideoFormat.RGB32
            self.stream = self.device['handle'].listStream[self.deviceSettings.indexStream]

            # set timebase
            if timebase == None:
                logger.debug("Capture will run with default system timebase")
                self.timebase = 0
            else:
                logger.debug("Capture will run with app wide adjustable timebase")
                self.timebase = timebase

            # set properties
            self.width = size[0]
            self.height = size[1]
            self.preferred_fps = fps
            self._initFrameRates()
            self._initMediaTypeId()

            # robust camera initialization
            self.context = _getVideoInputInstance()
            while True:
                res = self.context.setupDevice(self.deviceSettings, self.captureSettings)
                if res != vi.ResultCode.OK:
                    self._failed_inits += 1
                    msg = ERR_INIT_FAIL + "Fall back to Fake Capture. Error code: %d" %(res)
                    if self._failed_inits < MAX_RETRY_INIT_CAMERA:
                        logger.warning("Retry initializing camera: {0}/{1}: ".format(self._failed_inits, MAX_RETRY_INIT_CAMERA) + msg)
                    else:
                        logger.error(msg)
                        self._failed_inits = 0
                        self.init_capture(None, size, fps, timebase)
                        return
                    sleep(0.25)
                else:
                    break

            # creating frame buffer and initializing capture settings
            frame = np.empty((self.actual_height * self.actual_width * 4), dtype=np.uint8)
            self.readSetting = vi.ReadSetting()
            self.readSetting.symbolicLink = self.deviceSettings.symbolicLink
            self.readSetting.setNumpyArray(frame)
            frame.shape = (self.actual_height, self.actual_width, -1)
            self._frame = frame

            logger.debug("Successfully set up device: %s @ %dx%dpx %dfps (mediatype %d)" %(self.name, self.actual_height, self.actual_width, self.frame_rate, self.deviceSettings.indexMediaType))
        else:
            self.device = Fake_Capture()
            self.width = size[0]
            self.height = size[1]
            self.preferred_fps = fps
        self._is_initialized = True
        self._failed_inits = 0
예제 #10
0
class Camera_Capture(object):
    """
    Camera Capture is a class that encapsualtes uvc.Capture:
     - adds UI elements
     - adds timestamping sanitization fns.
    """

    def __init__(self, uid, timebase=None):
        if timebase == None:
            logger.debug("Capture will run with default system timebase")
            self.timebase = c_double(0)
        elif hasattr(timebase, "value"):
            logger.debug("Capture will run with app wide adjustable timebase")
            self.timebase = timebase
        else:
            logger.error("Invalid timebase variable type. Will use default system timebase")
            self.timebase = c_double(0)

        self.sidebar = None
        self.menu = None

        self.init_capture(uid, size=(1280, 720), fps=30)

    def re_init_capture(self, uid):
        current_size = self.capture.frame_size
        current_fps = self.capture.frame_rate

        self.capture = None
        # recreate the bar with new values
        menu_conf = self.menu.configuration
        self.deinit_gui()
        self.init_capture(uid, current_size, current_fps)

        self.init_gui(self.sidebar)
        self.menu.configuration = menu_conf

    def init_capture(self, uid, size, fps):

        if uid is not None:
            self.capture = uvc.Capture(uid)
        else:
            self.capture = Fake_Capture()
        self.uid = uid

        self.frame_size = size
        self.frame_rate = fps

        if "C930e" in self.capture.name:
            logger.debug("Timestamp offset for c930 applied: -0.1sec")
            self.ts_offset = -0.1
        else:
            self.ts_offset = 0.0

        # UVC setting quirks:
        controls_dict = dict([(c.display_name, c) for c in self.capture.controls])
        try:
            controls_dict["Auto Focus"].value = 0
        except KeyError:
            pass

        if "Pupil Cam1" in self.capture.name or "USB2.0 Camera" in self.capture.name:
            self.capture.bandwidth_factor = 1.3

            if "ID0" in self.capture.name or "ID1" in self.capture.name:
                try:
                    # Auto Exposure Priority = 1 leads to reduced framerates under low light and corrupt timestamps.
                    controls_dict["Auto Exposure Priority"].value = 1
                except KeyError:
                    pass

                try:
                    controls_dict["Absolute Exposure Time"].value = 59
                except KeyError:
                    pass

        try:
            controls_dict["Auto Focus"].value = 0
        except KeyError:
            pass

    def get_frame(self):
        try:
            frame = self.capture.get_frame_robust()
        except:
            raise CameraCaptureError("Could not get frame from %s" % self.uid)

        timestamp = self.get_now() + self.ts_offset
        timestamp -= self.timebase.value
        frame.timestamp = timestamp
        return frame

    def get_now(self):
        return time()

    def get_timestamp():
        return self.get_now() - self.timebase.value

    @property
    def frame_rate(self):
        return self.capture.frame_rate

    @frame_rate.setter
    def frame_rate(self, new_rate):
        # closest match for rate
        rates = [abs(r - new_rate) for r in self.capture.frame_rates]
        best_rate_idx = rates.index(min(rates))
        rate = self.capture.frame_rates[best_rate_idx]
        if rate != new_rate:
            logger.warning(
                "%sfps capture mode not available at (%s) on '%s'. Selected %sfps. "
                % (new_rate, self.capture.frame_size, self.capture.name, rate)
            )
        self.capture.frame_rate = rate

    @property
    def settings(self):
        settings = {}
        settings["name"] = self.capture.name
        settings["frame_rate"] = self.frame_rate
        settings["uvc_controls"] = {}
        for c in self.capture.controls:
            settings["uvc_controls"][c.display_name] = c.value
        return settings

    @settings.setter
    def settings(self, settings):
        try:
            self.frame_rate = settings["frame_rate"]
        except KeyError:
            pass

        if settings.get("name", "") == self.capture.name:
            for c in self.capture.controls:
                try:
                    c.value = settings["uvc_controls"][c.display_name]
                except KeyError as e:
                    logger.warning('Could not set UVC setting "%s" from last session.' % c.display_name)

    @property
    def frame_size(self):
        return self.capture.frame_size

    @frame_size.setter
    def frame_size(self, new_size):
        self.capture.frame_size = filter_sizes(self.name, new_size)

    @property
    def name(self):
        return self.capture.name

    def init_gui(self, sidebar):

        # lets define some  helper functions:
        def gui_load_defaults():
            for c in self.capture.controls:
                try:
                    c.value = c.def_val
                except:
                    pass

        def gui_update_from_device():
            for c in self.capture.controls:
                c.refresh()

        def gui_init_cam_by_uid(requested_id):
            if requested_id is None:
                self.re_init_capture(None)
            else:
                for cam in uvc.device_list():
                    if cam["uid"] == requested_id:
                        if is_accessible(requested_id):
                            self.re_init_capture(requested_id)
                        else:
                            logger.error("The selected Camera is already in use or blocked.")
                        return
                logger.warning("could not reinit capture, src_id not valid anymore")
                return

        # create the menu entry
        self.menu = ui.Growing_Menu(label="Camera Settings")
        cameras = uvc.device_list()
        camera_names = ["Fake Capture"] + [c["name"] for c in cameras]
        camera_ids = [None] + [c["uid"] for c in cameras]
        self.menu.append(
            ui.Selector(
                "uid",
                self,
                selection=camera_ids,
                labels=camera_names,
                label="Capture Device",
                setter=gui_init_cam_by_uid,
            )
        )

        sensor_control = ui.Growing_Menu(label="Sensor Settings")
        sensor_control.collapsed = False
        image_processing = ui.Growing_Menu(label="Image Post Processing")
        image_processing.collapsed = True

        sensor_control.append(
            ui.Selector("frame_rate", self, selection=self.capture.frame_rates, label="Frames per second")
        )

        for control in self.capture.controls:
            c = None
            ctl_name = control.display_name

            # now we add controls
            if control.d_type == bool:
                c = ui.Switch("value", control, label=ctl_name, on_val=control.max_val, off_val=control.min_val)
            elif control.d_type == int:
                c = ui.Slider(
                    "value", control, label=ctl_name, min=control.min_val, max=control.max_val, step=control.step
                )
            elif type(control.d_type) == dict:
                selection = [value for name, value in control.d_type.iteritems()]
                labels = [name for name, value in control.d_type.iteritems()]
                c = ui.Selector("value", control, label=ctl_name, selection=selection, labels=labels)
            else:
                pass
            # if control['disabled']:
            #     c.read_only = True
            # if ctl_name == 'Exposure, Auto Priority':
            #     # the controll should always be off. we set it to 0 on init (see above)
            #     c.read_only = True

            if c is not None:
                if control.unit == "processing_unit":
                    image_processing.append(c)
                else:
                    sensor_control.append(c)

        self.menu.append(sensor_control)
        if image_processing.elements:
            self.menu.append(image_processing)
        self.menu.append(ui.Button("refresh", gui_update_from_device))
        self.menu.append(ui.Button("load defaults", gui_load_defaults))

        self.sidebar = sidebar
        # add below geneal settings
        self.sidebar.insert(1, self.menu)

    def deinit_gui(self):
        if self.menu:
            self.sidebar.remove(self.menu)
            self.menu = None

    def close(self):
        self.deinit_gui()
        # self.capture.close()
        del self.capture
        logger.info("Capture released")