Beispiel #1
1
 def initialize(self, options, camera_widget):
     
     self.do_stop = False
     self.do_refresh = False
     
     self.use_webcam = options.webcam
     self.camera_ip = options.camera_ip
     self.camera_widget = camera_widget
     
     self.img_logger = None
     
     if options.ask:
         options.static_images = util.get_directory(os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'logs')))
         if options.static_images is None:
             raise RuntimeError()
     
     if options.log_images:
         self.img_logger = ImageLogger(options.log_dir)
     
     # detect live or static processing
     if options.static_images is not None:
         self._initialize_static(options)
         thread_fn = self._static_processing
     else:
         self.using_live_feed = True
         thread_fn = self._live_processing
         
     self.thread = threading.Thread(target=thread_fn)
     self.thread.setDaemon(True)
Beispiel #2
0
    def initialize(self, options):

        # initialize this here instead of globally because we can't
        # get the logger until it has been configured, and we need
        # to interact with the options parser

        import logging
        self.logger = logging.getLogger(__name__)

        from ui.util import get_directory

        def _get_option(name):
            return getattr(options, '%s%s' % (self.prefix, name))

        def _set_option(name, val):
            setattr(options, '%s%s' % (self.prefix, name), val)

        self.do_stop = False
        self.do_refresh = False

        self.use_webcam = _get_option('webcam')
        self.camera_ip = _get_option('camera_ip')

        self.img_logger = None

        if _get_option('ask'):
            static_images = get_directory(
                os.path.abspath(
                    os.path.join(os.path.dirname(__file__), '..', 'logs')))
            if static_images is None:
                raise RuntimeError()

            _set_option('static_images', static_images)
            self.logger.info("%s ask: user selected %s", self.prefix,
                             static_images)

        if _get_option('log'):
            self.img_logger = ImageLogger(self.prefix, options.log_dir)

        # detect live or static processing
        if _get_option('static_images') is not None:
            self._initialize_static(_get_option('static_images'))
            thread_fn = self._static_processing
        elif self.use_webcam is not None or self.camera_ip is not None:
            self.using_live_feed = True
            thread_fn = self._live_processing
        else:
            thread_fn = self._no_processing

        self.thread = threading.Thread(target=thread_fn)
        self.thread.setDaemon(True)
Beispiel #3
0
 def initialize(self, options):
     
     # initialize this here instead of globally because we can't
     # get the logger until it has been configured, and we need
     # to interact with the options parser
  
     import logging
     self.logger = logging.getLogger(__name__)
     
     from ui.util import get_directory
     
     def _get_option(name):
         return getattr(options, '%s%s' % (self.prefix, name))
     
     def _set_option(name, val):
         setattr(options, '%s%s' % (self.prefix, name), val)
     
     self.do_stop = False
     self.do_refresh = False
     
     self.use_webcam = _get_option('webcam')
     self.camera_ip = _get_option('camera_ip')
     
     self.img_logger = None
     
     
     if _get_option('ask'):
         static_images = get_directory(os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'logs')))
         if static_images is None:
             raise RuntimeError()
         
         _set_option('static_images', static_images)
         self.logger.info("%s ask: user selected %s", self.prefix, static_images)
     
     if _get_option('log'):
         self.img_logger = ImageLogger(self.prefix, options.log_dir)
     
     # detect live or static processing
     if _get_option('static_images') is not None:
         self._initialize_static(_get_option('static_images'))
         thread_fn = self._static_processing
     elif self.use_webcam is not None or self.camera_ip is not None:
         self.using_live_feed = True
         thread_fn = self._live_processing
     else:
         thread_fn = self._no_processing
         
     self.thread = threading.Thread(target=thread_fn)
     self.thread.setDaemon(True)
Beispiel #4
0
class ImageCapture(object):
    '''
        This class manages the image processing stuff. It determines what
        actions to take, and then performs them on another thread.
        
        The actual image processing takes place in a different class. That 
        class processes the image, and then returns a dictionary that has
        targeting information in it.
    '''
    
    def __init__(self, detector=None, name=''):    
        
        if detector is None:
            self.detector = _FakeDetector()
        else:
            self.detector = detector
        
        self.prefix = name if name == '' else '%s_' % name
        self.lock = threading.Lock()
        self.condition = threading.Condition(self.lock)
        self.image_log_enabled = False
        self.using_live_feed = False
        self.camera_widget = None
        
        self.started = False
    
    def configure_options(self, parser):
        '''
            :param parser: an OptionParser instance
        '''
        
        name = self.prefix.replace('_', '-')
        
        parser.add_option('--%scamera-ip' % name, dest='%scamera_ip' % self.prefix,
                          help='IP address of %s camera' % self.prefix)
        parser.add_option('--%swebcam' % name, dest='%swebcam' % self.prefix,
                          help="Use webcam for %s camera" % self.prefix)
        parser.add_option('--%sask' % name, dest='%sask' % self.prefix,
                          help="Ask for static images for %s camera" % self.prefix)
        parser.add_option('--%sstatic' % name, dest='%sstatic_images' % self.prefix,
                          help="Load static images for %s camera" % self.prefix)
        parser.add_option('--%slog' % name, dest='%slog' % self.prefix, action='store_true',
                          help="Log images for %s camera" % self.prefix)
        
    
    def initialize(self, options):
        
        # initialize this here instead of globally because we can't
        # get the logger until it has been configured, and we need
        # to interact with the options parser
     
        import logging
        self.logger = logging.getLogger(__name__)
        
        from ui.util import get_directory
        
        def _get_option(name):
            return getattr(options, '%s%s' % (self.prefix, name))
        
        def _set_option(name, val):
            setattr(options, '%s%s' % (self.prefix, name), val)
        
        self.do_stop = False
        self.do_refresh = False
        
        self.use_webcam = _get_option('webcam')
        self.camera_ip = _get_option('camera_ip')
        
        self.img_logger = None
        
        
        if _get_option('ask'):
            static_images = get_directory(os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'logs')))
            if static_images is None:
                raise RuntimeError()
            
            _set_option('static_images', static_images)
            self.logger.info("%s ask: user selected %s", self.prefix, static_images)
        
        if _get_option('log'):
            self.img_logger = ImageLogger(self.prefix, options.log_dir)
        
        # detect live or static processing
        if _get_option('static_images') is not None:
            self._initialize_static(_get_option('static_images'))
            thread_fn = self._static_processing
        elif self.use_webcam is not None or self.camera_ip is not None:
            self.using_live_feed = True
            thread_fn = self._live_processing
        else:
            thread_fn = self._no_processing
            
        self.thread = threading.Thread(target=thread_fn)
        self.thread.setDaemon(True)
        
    def is_live_feed(self):
        return self.using_live_feed
    
    def set_camera_widget(self, camera_widget):
        self.camera_widget = camera_widget
        
    def set_detector(self, detector):
        self.detector = detector
        
    def start(self):
        
        if self.started:
            return
        
        if self.img_logger is not None:
            self.img_logger.start()
        
        if not self.thread.is_alive():
            self.thread.start()
            
        self.started = True
        
    def stop(self):
        self.do_stop = True
        with self.condition:
            self.condition.notify()
            
        if self.thread.is_alive():
            self.thread.join()
        
        if self.img_logger is not None:
            self.img_logger.stop()
            
        self.started = False
            
    def enable_image_logging(self):
        with self.lock:
            self.image_log_enabled = True
            
    def disable_image_logging(self):
        with self.lock:
            self.image_log_enabled = False
        
    def refresh(self):
        with self.condition:
            self.do_refresh = True
            self.condition.notify()
    
    def _no_processing(self):
        # called when no processing is being done
        if self.camera_widget is not None:
            self.camera_widget.set_error()
    
    def _initialize_static(self, static_images):
        
        # TODO: should this stuff be here? or move it to the UI?
        import gtk
        
        path = static_images
        self.idx = 0
        self.idx_increment = 1
        
        if not os.path.exists(path):
            self.logger.error("'%s' does not exist!" % path)
            raise RuntimeError()
        
        self.logger.info("Loading static images from %s", path)
        
        if not os.path.isdir(path):
            self.images = [path]
        else:
            self.images = []
            for path, dirs, files in os.walk(path):
                self.images += [os.path.join(path, f) for f in files] 
            
            self.images.sort()
        
        # setup the key handler
        def _on_key_press(widget, event):
            if event.keyval == gtk.keysyms.Left:
                if self.idx > 0:
                    with self.condition:
                        self.idx -= 1
                        self.idx_increment = -1
                        self.condition.notify()
            elif event.keyval == gtk.keysyms.Right:
                if self.idx < len(self.images):
                    with self.condition:
                        self.idx += 1
                        self.idx_increment = 1
                        self.condition.notify()
            elif event.keyval == gtk.keysyms.Escape:
                gtk.main_quit()
            
            # return True otherwise we might lose focus
            return True
        
        def _on_button_pressed(widget, event):
            widget.grab_focus()
        
        # must be able to get focus to receive keyboard events
        self.camera_widget.set_can_focus(True)
        self.camera_widget.add_events(gtk.gdk.BUTTON_PRESS_MASK)
        
        self.camera_widget.grab_focus()
        self.camera_widget.connect('key-press-event', _on_key_press)
        self.camera_widget.connect('button-press-event', _on_button_pressed)
        

    @logutil.exception_decorator(logger=None)
    def _static_processing(self):
        
        self.logger.info("Static processing thread starting")
        idx = -1
        
        # resume processing with the last image the user looked at
        last_img = settings.get('processing/last_img', None)
        for i, image_name in enumerate(self.images):
            if image_name == last_img:
                self.idx = i
                break 
        
        while True:
        
            with self.condition:
                
                # wait until the user hits a key
                while idx == self.idx and not self.do_stop and not self.do_refresh:
                    self.condition.wait()
                
                if self.do_stop:
                    break
                
                idx = self.idx
                self.do_refresh = False
                    
            # if the index is valid, then process an image
            if idx < len(self.images) and idx >= 0:
                
                image_name = self.images[idx]
                
                self.logger.info("Opening %s" % image_name)
                
                img = cv2.imread(image_name)
                if img is None:
                    self.logger.error("Error opening %s: could not read file" % (image_name))
                    self.camera_widget.set_error()
                    self.idx += self.idx_increment
                    continue
                
                try:
                    target_data = self.detector.process_image(img)
                except:
                    logutil.log_exception(self.logger, 'error processing image')
                    self.camera_widget.set_error(img)
                else:
                    settings.set('processing/last_img', image_name)
                    settings.save()
                    
                    self.logger.info('Finished processing')
                
                    # note that you cannot typically interact with the UI
                    # from another thread -- but this function is special
                    self.camera_widget.set_target_data(target_data)
            
        self.logger.info("Static processing thread exiting")

        
    def _initialize_live(self):
        vc = cv2.VideoCapture()
        
        vc.set(cv2.cv.CV_CAP_PROP_FPS, 1)
        
        if self.use_webcam is None:
            self.logger.info('Connecting to %s' % self.camera_ip)
            if not vc.open('http://%s/mjpg/video.mjpg' % self.camera_ip):
                self.logger.error("Could not connect")
                return
        else:
            self.logger.info('Connecting to webcam %s' % self.use_webcam)
            if not vc.open(self.use_webcam):
                self.logger.error("Could not connect")
                return
        
        self.logger.info('Connected!')
        return vc
            

    @logutil.exception_decorator(logger=None)
    def _live_processing(self):
        
        self.logger.info("Live processing thread starting")
        
        while True:
            
            # check for exit condition
            with self.lock:
                if self.do_stop:
                    break
            
            # open the video capture device
            vc = self._initialize_live()
            
            if vc is None:
                continue
        
            last_log = 0
            exception_occurred = False
            
            # allocate a buffer for reading
            h = vc.get(cv2.cv.CV_CAP_PROP_FRAME_WIDTH)
            w = vc.get(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT)
            
            capture_buffer = np.empty(shape=(h, w, 3), dtype=np.uint8)
            
            while True:
            
                # check for exit condition
                with self.lock:
                    if self.do_stop:
                        break
                    
                    image_log_enabled = self.image_log_enabled
                
                #
                # Read the video frame
                #
                
                retval, img = vc.read(capture_buffer)
                
                if retval:
                    
                    # log images to directory
                    if self.img_logger is not None:
                        tm = time.time()
                        diff = tm - last_log
                        if diff >= 1:
                            if image_log_enabled:
                                self.img_logger.log_image(img)
                            
                            # adjust for possible drift
                            if diff > 1.5:
                                last_log = tm
                            else:
                                last_log += 1
                
                    #
                    # Process the image
                    #
                    
                    try:
                        target_data = self.detector.process_image(img)
                    except:
                        # if it happened once, it'll probably happen again. Don't flood
                        # the logfiles... 
                        if not exception_occurred:
                            logutil.log_exception(self.logger, 'error processing image')
                            exception_occurred = True
                        self.camera_widget.set_error(img)
                        
                    else:
                        if exception_occurred:
                            self.logger.info("Processing resumed, no more errors.")
                            exception_occurred = False
                        
                        # note that you cannot typically interact with the UI
                        # from another thread -- but this function is special
                        self.camera_widget.set_target_data(target_data)
                                        
                else:
                    if last_log == 0: 
                        self.logger.error("Not able to connect to camera, retrying")
                    else:
                        self.logger.error("Camera disconnected, retrying")
                        
                    self.camera_widget.set_error()
                    break
            
        self.logger.info("Static processing thread exiting")
Beispiel #5
0
class ImageProcessor(object):
    '''
        This class manages the image processing stuff. It determines what
        actions to take, and then performs them on another thread.
        
        The actual image processing takes place in a different class. That 
        class processes the image, and then returns a dictionary that has
        targeting information in it.
    '''
    
    def __init__(self):        
        self.detector = kwarqs2013cv.TargetDetector()
        self.lock = threading.Lock()
        self.condition = threading.Condition(self.lock)
        self.image_log_enabled = False
        self.using_live_feed = False
    
    def initialize(self, options, camera_widget):
        
        self.do_stop = False
        self.do_refresh = False
        
        self.use_webcam = options.webcam
        self.camera_ip = options.camera_ip
        self.camera_widget = camera_widget
        
        self.img_logger = None
        
        if options.ask:
            options.static_images = util.get_directory(os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'logs')))
            if options.static_images is None:
                raise RuntimeError()
        
        if options.log_images:
            self.img_logger = ImageLogger(options.log_dir)
        
        # detect live or static processing
        if options.static_images is not None:
            self._initialize_static(options)
            thread_fn = self._static_processing
        else:
            self.using_live_feed = True
            thread_fn = self._live_processing
            
        self.thread = threading.Thread(target=thread_fn)
        self.thread.setDaemon(True)
        
    def is_live_feed(self):
        return self.using_live_feed
        
    def start(self):
        if self.img_logger is not None:
            self.img_logger.start()
        
        if not self.thread.is_alive():
            self.thread.start()
        
    def stop(self):
        self.do_stop = True
        with self.condition:
            self.condition.notify()
            
        if self.thread.is_alive():
            self.thread.join()
        
        if self.img_logger is not None:
            self.img_logger.stop()
            
    def enable_image_logging(self):
        with self.lock:
            self.image_log_enabled = True
            
    def disable_image_logging(self):
        with self.lock:
            self.image_log_enabled = False
        
    def refresh(self):
        with self.condition:
            self.do_refresh = True
            self.condition.notify()
        
    def _initialize_static(self, options):
        
        path = options.static_images
        self.idx = 0
        self.idx_increment = 1
        
        if not os.path.exists(path):
            logger.error("'%s' does not exist!" % path)
            raise RuntimeError()
        
        if not os.path.isdir(path):
            self.images = [path]
        else:
            self.images = []
            for path, dirs, files in os.walk(path):
                self.images += [os.path.join(path, f) for f in files] 
            
            self.images.sort()
        
        # setup the key handler
        def _on_key_press(widget, event):
            if event.keyval == gtk.keysyms.Left:
                if self.idx > 0:
                    with self.condition:
                        self.idx -= 1
                        self.idx_increment = -1
                        self.condition.notify()
            elif event.keyval == gtk.keysyms.Right:
                if self.idx < len(self.images):
                    with self.condition:
                        self.idx += 1
                        self.idx_increment = 1
                        self.condition.notify()
            elif event.keyval == gtk.keysyms.Escape:
                gtk.main_quit()
            
            # return True otherwise we might lose focus
            return True
        
        def _on_button_pressed(widget, event):
            widget.grab_focus()
        
        # must be able to get focus to receive keyboard events
        self.camera_widget.set_can_focus(True)
        self.camera_widget.add_events(gtk.gdk.BUTTON_PRESS_MASK)
        
        self.camera_widget.grab_focus()
        self.camera_widget.connect('key-press-event', _on_key_press)
        self.camera_widget.connect('button-press-event', _on_button_pressed)
        

    @logutil.exception_decorator(logger)
    def _static_processing(self):
        
        logger.info("Static processing thread starting")
        idx = -1
        
        # resume processing with the last image the user looked at
        last_img = settings.get('processing/last_img', None)
        for i, image_name in enumerate(self.images):
            if image_name == last_img:
                self.idx = i
                break 
        
        while True:
        
            with self.condition:
                
                # wait until the user hits a key
                while idx == self.idx and not self.do_stop and not self.do_refresh:
                    self.condition.wait()
                
                if self.do_stop:
                    break
                
                idx = self.idx
                self.do_refresh = False
                    
            # if the index is valid, then process an image
            if idx < len(self.images) and idx >= 0:
                
                image_name = self.images[idx]
                
                logger.info("Opening %s" % image_name)
                
                img = cv2.imread(image_name)
                if img is None:
                    logger.error("Error opening %s: could not read file" % (image_name))
                    self.idx += self.idx_increment
                    continue
                
                try:
                    target_data = self.detector.processImage(img)
                except:
                    logutil.log_exception(logger, 'error processing image')
                else:
                    settings.set('processing/last_img', image_name)
                    settings.save()
                    
                    logger.info('Finished processing')
                
                    # note that you cannot typically interact with the UI
                    # from another thread -- but this function is special
                    self.camera_widget.set_target_data(target_data)
            
        logger.info("Static processing thread exiting")

        
    def _initialize_live(self):
        vc = cv2.VideoCapture()
        
        vc.set(cv2.cv.CV_CAP_PROP_FPS, 1)
        
        if self.use_webcam is None:
            logger.info('Connecting to %s' % self.camera_ip)
            if not vc.open('http://%s/mjpg/video.mjpg' % self.camera_ip):
                logger.error("Could not connect")
                return
        else:
            logger.info('Connecting to webcam %s' % self.use_webcam)
            if not vc.open(self.use_webcam):
                logger.error("Could not connect")
                return
        
        logger.info('Connected!')
        return vc
            

    @logutil.exception_decorator(logger)
    def _live_processing(self):
        
        logger.info("Live processing thread starting")
        
        while True:
            
            # check for exit condition
            with self.lock:
                if self.do_stop:
                    break
            
            # open the video capture device
            vc = self._initialize_live()
            
            if vc is None:
                continue
        
            last_log = 0
            exception_occurred = False
            
            # allocate a buffer for reading
            h = vc.get(cv2.cv.CV_CAP_PROP_FRAME_WIDTH)
            w = vc.get(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT)
            
            capture_buffer = np.empty(shape=(h, w, 3), dtype=np.uint8)
            
            while True:
            
                # check for exit condition
                with self.lock:
                    if self.do_stop:
                        break
                    
                    image_log_enabled = self.image_log_enabled
                
                #
                # Read the video frame
                #
                
                retval, img = vc.read(capture_buffer)
                
                if retval:
                    
                    # log images to directory
                    if self.img_logger is not None:
                        tm = time.time()
                        diff = tm - last_log
                        if diff >= 1:
                            if image_log_enabled:
                                self.img_logger.log_image(img)
                            
                            # adjust for possible drift
                            if diff > 1.5:
                                last_log = tm
                            else:
                                last_log += 1
                
                    #
                    # Process the image
                    #
                    
                    try:
                        target_data = self.detector.processImage(img)
                    except:
                        # if it happened once, it'll probably happen again. Don't flood
                        # the logfiles... 
                        if not exception_occurred:
                            logutil.log_exception(logger, 'error processing image')
                            exception_occurred = True
                        self.camera_widget.set_error(img)
                        
                    else:
                        if exception_occurred:
                            logger.info("Processing resumed, no more errors.")
                            exception_occurred = False
                        
                        # note that you cannot typically interact with the UI
                        # from another thread -- but this function is special
                        self.camera_widget.set_target_data(target_data)
                                        
                else:
                    if last_log == 0: 
                        logger.error("Not able to connect to camera, retrying")
                    else:
                        logger.error("Camera disconnected, retrying")
                        
                    self.camera_widget.set_error()
                    break
            
        logger.info("Static processing thread exiting")
Beispiel #6
0
class ImageCapture(object):
    '''
        This class manages the image processing stuff. It determines what
        actions to take, and then performs them on another thread.
        
        The actual image processing takes place in a different class. That 
        class processes the image, and then returns a dictionary that has
        targeting information in it.
    '''
    def __init__(self, detector=None, name=''):

        if detector is None:
            self.detector = _FakeDetector()
        else:
            self.detector = detector

        self.prefix = name if name == '' else '%s_' % name
        self.lock = threading.Lock()
        self.condition = threading.Condition(self.lock)
        self.image_log_enabled = False
        self.using_live_feed = False
        self.camera_widget = None

        self.started = False

    def configure_options(self, parser):
        '''
            :param parser: an OptionParser instance
        '''

        name = self.prefix.replace('_', '-')

        parser.add_option('--%scamera-ip' % name,
                          dest='%scamera_ip' % self.prefix,
                          help='IP address of %s camera' % self.prefix)
        parser.add_option('--%swebcam' % name,
                          dest='%swebcam' % self.prefix,
                          help="Use webcam for %s camera" % self.prefix)
        parser.add_option('--%sask' % name,
                          dest='%sask' % self.prefix,
                          help="Ask for static images for %s camera" %
                          self.prefix)
        parser.add_option('--%sstatic' % name,
                          dest='%sstatic_images' % self.prefix,
                          help="Load static images for %s camera" %
                          self.prefix)
        parser.add_option('--%slog' % name,
                          dest='%slog' % self.prefix,
                          action='store_true',
                          help="Log images for %s camera" % self.prefix)

    def initialize(self, options):

        # initialize this here instead of globally because we can't
        # get the logger until it has been configured, and we need
        # to interact with the options parser

        import logging
        self.logger = logging.getLogger(__name__)

        from ui.util import get_directory

        def _get_option(name):
            return getattr(options, '%s%s' % (self.prefix, name))

        def _set_option(name, val):
            setattr(options, '%s%s' % (self.prefix, name), val)

        self.do_stop = False
        self.do_refresh = False

        self.use_webcam = _get_option('webcam')
        self.camera_ip = _get_option('camera_ip')

        self.img_logger = None

        if _get_option('ask'):
            static_images = get_directory(
                os.path.abspath(
                    os.path.join(os.path.dirname(__file__), '..', 'logs')))
            if static_images is None:
                raise RuntimeError()

            _set_option('static_images', static_images)
            self.logger.info("%s ask: user selected %s", self.prefix,
                             static_images)

        if _get_option('log'):
            self.img_logger = ImageLogger(self.prefix, options.log_dir)

        # detect live or static processing
        if _get_option('static_images') is not None:
            self._initialize_static(_get_option('static_images'))
            thread_fn = self._static_processing
        elif self.use_webcam is not None or self.camera_ip is not None:
            self.using_live_feed = True
            thread_fn = self._live_processing
        else:
            thread_fn = self._no_processing

        self.thread = threading.Thread(target=thread_fn)
        self.thread.setDaemon(True)

    def is_live_feed(self):
        return self.using_live_feed

    def set_camera_widget(self, camera_widget):
        self.camera_widget = camera_widget

    def set_detector(self, detector):
        self.detector = detector

    def start(self):

        if self.started:
            return

        if self.img_logger is not None:
            self.img_logger.start()

        if not self.thread.is_alive():
            self.thread.start()

        self.started = True

    def stop(self):
        self.do_stop = True
        with self.condition:
            self.condition.notify()

        if self.thread.is_alive():
            self.thread.join()

        if self.img_logger is not None:
            self.img_logger.stop()

        self.started = False

    def enable_image_logging(self):
        with self.lock:
            self.image_log_enabled = True

    def disable_image_logging(self):
        with self.lock:
            self.image_log_enabled = False

    def refresh(self):
        with self.condition:
            self.do_refresh = True
            self.condition.notify()

    def _no_processing(self):
        # called when no processing is being done
        if self.camera_widget is not None:
            self.camera_widget.set_error()

    def _initialize_static(self, static_images):

        # TODO: should this stuff be here? or move it to the UI?
        import gtk

        path = static_images
        self.idx = 0
        self.idx_increment = 1

        if not os.path.exists(path):
            self.logger.error("'%s' does not exist!" % path)
            raise RuntimeError()

        self.logger.info("Loading static images from %s", path)

        if not os.path.isdir(path):
            self.images = [path]
        else:
            self.images = []
            for path, dirs, files in os.walk(path):
                self.images += [os.path.join(path, f) for f in files]

            self.images.sort()

        # setup the key handler
        def _on_key_press(widget, event):
            if event.keyval == gtk.keysyms.Left:
                if self.idx > 0:
                    with self.condition:
                        self.idx -= 1
                        self.idx_increment = -1
                        self.condition.notify()
            elif event.keyval == gtk.keysyms.Right:
                if self.idx < len(self.images):
                    with self.condition:
                        self.idx += 1
                        self.idx_increment = 1
                        self.condition.notify()
            elif event.keyval == gtk.keysyms.Escape:
                gtk.main_quit()

            # return True otherwise we might lose focus
            return True

        def _on_button_pressed(widget, event):
            widget.grab_focus()

        # must be able to get focus to receive keyboard events
        self.camera_widget.set_can_focus(True)
        self.camera_widget.add_events(gtk.gdk.BUTTON_PRESS_MASK)

        self.camera_widget.grab_focus()
        self.camera_widget.connect('key-press-event', _on_key_press)
        self.camera_widget.connect('button-press-event', _on_button_pressed)

    @logutil.exception_decorator(logger=None)
    def _static_processing(self):

        self.logger.info("Static processing thread starting")
        idx = -1

        # resume processing with the last image the user looked at
        last_img = settings.get('processing/last_img', None)
        for i, image_name in enumerate(self.images):
            if image_name == last_img:
                self.idx = i
                break

        while True:

            with self.condition:

                # wait until the user hits a key
                while idx == self.idx and not self.do_stop and not self.do_refresh:
                    self.condition.wait()

                if self.do_stop:
                    break

                idx = self.idx
                self.do_refresh = False

            # if the index is valid, then process an image
            if idx < len(self.images) and idx >= 0:

                image_name = self.images[idx]

                self.logger.info("Opening %s" % image_name)

                img = cv2.imread(image_name)
                if img is None:
                    self.logger.error("Error opening %s: could not read file" %
                                      (image_name))
                    self.camera_widget.set_error()
                    self.idx += self.idx_increment
                    continue

                try:
                    target_data = self.detector.process_image(img)
                except:
                    logutil.log_exception(self.logger,
                                          'error processing image')
                    self.camera_widget.set_error(img)
                else:
                    settings.set('processing/last_img', image_name)
                    settings.save()

                    self.logger.info('Finished processing')

                    # note that you cannot typically interact with the UI
                    # from another thread -- but this function is special
                    self.camera_widget.set_target_data(target_data)

        self.logger.info("Static processing thread exiting")

    def _initialize_live(self):
        vc = cv2.VideoCapture()

        vc.set(cv2.cv.CV_CAP_PROP_FPS, 1)

        if self.use_webcam is None:
            self.logger.info('Connecting to %s' % self.camera_ip)
            if not vc.open('http://%s/mjpg/video.mjpg' % self.camera_ip):
                self.logger.error("Could not connect")
                return
        else:
            self.logger.info('Connecting to webcam %s' % self.use_webcam)
            if not vc.open(self.use_webcam):
                self.logger.error("Could not connect")
                return

        self.logger.info('Connected!')
        return vc

    @logutil.exception_decorator(logger=None)
    def _live_processing(self):

        self.logger.info("Live processing thread starting")

        while True:

            # check for exit condition
            with self.lock:
                if self.do_stop:
                    break

            # open the video capture device
            vc = self._initialize_live()

            if vc is None:
                continue

            last_log = 0
            exception_occurred = False

            # allocate a buffer for reading
            h = vc.get(cv2.cv.CV_CAP_PROP_FRAME_WIDTH)
            w = vc.get(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT)

            capture_buffer = np.empty(shape=(h, w, 3), dtype=np.uint8)

            while True:

                # check for exit condition
                with self.lock:
                    if self.do_stop:
                        break

                    image_log_enabled = self.image_log_enabled

                #
                # Read the video frame
                #

                retval, img = vc.read(capture_buffer)

                if retval:

                    # log images to directory
                    if self.img_logger is not None:
                        tm = time.time()
                        diff = tm - last_log
                        if diff >= 1:
                            if image_log_enabled:
                                self.img_logger.log_image(img)

                            # adjust for possible drift
                            if diff > 1.5:
                                last_log = tm
                            else:
                                last_log += 1

                    #
                    # Process the image
                    #

                    try:
                        target_data = self.detector.process_image(img)
                    except:
                        # if it happened once, it'll probably happen again. Don't flood
                        # the logfiles...
                        if not exception_occurred:
                            logutil.log_exception(self.logger,
                                                  'error processing image')
                            exception_occurred = True
                        self.camera_widget.set_error(img)

                    else:
                        if exception_occurred:
                            self.logger.info(
                                "Processing resumed, no more errors.")
                            exception_occurred = False

                        # note that you cannot typically interact with the UI
                        # from another thread -- but this function is special
                        self.camera_widget.set_target_data(target_data)

                else:
                    if last_log == 0:
                        self.logger.error(
                            "Not able to connect to camera, retrying")
                    else:
                        self.logger.error("Camera disconnected, retrying")

                    self.camera_widget.set_error()
                    break

        self.logger.info("Static processing thread exiting")