Esempio n. 1
0
    def __init__(self):
        self.timer = CvTimer()
        self.work_timer = CountdownTimer()
        #TODO:this should be configurable from gui
        self.frame_counter = FPSCounter(every=5)

        self.capturer = Capturer()
        self.frame_size = frame_width, frame_heigth = self.capturer.get_camera_width_heigth()
        #TODO: check the way to reduce the capture.
        print('capturing %sx%s' % (frame_width, frame_heigth)) 

        self.face_enforcer = enforcers.EnforceFaceLimits(say_warning)
        self.face_classifier = classifiers.CascadeClassifier(find_data_file('cascades/haarcascade_frontalface_alt.xml'))

        #Initialize GUI:
        self.gui = CX_Gui(window_name='behave', frame_size=self.frame_size, callback_obj=self)
        self.gui.initialize_gui()

        #Event hooks, they control the flow of the main loop:
        self._event_debug = False
        self._event_enforcing = True
        self._event_quit = False
        self._event_auto_limit = False
        self._event_image_show = True
        #_msg is used to get output from events
        self._event_msg = None

        #Auto-adjust protocol needs:
        self._auto_faces = []
        self._auto_num_faces = 5 #TODO: gui configurable
        self._auto_tilt = 10
Esempio n. 2
0
class Behave(object):
    def __init__(self):
        self.timer = CvTimer()
        self.work_timer = CountdownTimer()
        #TODO:this should be configurable from gui
        self.frame_counter = FPSCounter(every=5)

        self.capturer = Capturer()
        self.frame_size = frame_width, frame_heigth = self.capturer.get_camera_width_heigth()
        #TODO: check the way to reduce the capture.
        print('capturing %sx%s' % (frame_width, frame_heigth)) 

        self.face_enforcer = enforcers.EnforceFaceLimits(say_warning)
        self.face_classifier = classifiers.CascadeClassifier(find_data_file('cascades/haarcascade_frontalface_alt.xml'))

        #Initialize GUI:
        self.gui = CX_Gui(window_name='behave', frame_size=self.frame_size, callback_obj=self)
        self.gui.initialize_gui()

        #Event hooks, they control the flow of the main loop:
        self._event_debug = False
        self._event_enforcing = True
        self._event_quit = False
        self._event_auto_limit = False
        self._event_image_show = True
        #_msg is used to get output from events
        self._event_msg = None

        #Auto-adjust protocol needs:
        self._auto_faces = []
        self._auto_num_faces = 5 #TODO: gui configurable
        self._auto_tilt = 10

    def dispatch_keyb_events(self):
        keyb_event = self.gui.keyb_event_generator()
        if keyb_event == 'quit':
            self._event_quit = True

        elif keyb_event == 'debug':
            self._event_debug = not self._event_debug

        elif keyb_event == 'toggle_work_timer':
            if self.work_timer.is_started:
                self.work_timer.stop()
            else: 
                self.work_timer.start()

        elif keyb_event == 'toggle_show_image':
            self._event_image_show = not self._event_image_show

        elif keyb_event == 'set_limit_auto':
            self._event_auto_limit = True

    def handle_left_click_in_img(self, y_coord):
        self.face_enforcer.set_y_limit_low(y_limit_low=y_coord)

    def handle_auto_limit(self, face):
        """Fancy protocol, saves N faces, takes average and sets the y limit with a tilt"""
        #We disable enforcing
        self._event_enforcing = False

        self._auto_faces.append(face)

        len_faces = len(self._auto_faces)
        msg = ("AUTO-adjusting in process... sit correctly! %s of %s" % (len_faces, self._auto_num_faces))
        
        if len_faces == self._auto_num_faces:
            y_s = [y + h / 2. for x, y, w, h in self._auto_faces]
            h_s = [h for x, y, w, h in self._auto_faces]
            #Very ugly, but needed, float to get the real avg, then truncate to get pixels
            avg_y_s = int(sum(y_s) / len_faces)
            avg_size = int(float(sum(h_s)) / len_faces)

            surplus = int(float(avg_size) / self._auto_tilt)
            y_limit_low = avg_y_s + surplus
            self.face_enforcer.set_y_limit_low(y_limit_low)

            #leaving the auto adjustment, cleaning up:
            self.face_enforcer.reset_wrongs()
            self.face_enforcer.reset_oks()
            self._auto_faces = list() 
            self._event_auto_limit = False
            self._event_enforcing = True

        return msg

    def detect_face_in_frame(self, a_frame): 
        a_frame = convert_to_gray(a_frame)
        a_frame = equalize(a_frame)
        faces_list = self.face_classifier.detect_multiscale(a_frame)

        return faces_list[0] if len(faces_list) == 1 else None

    def handle_enforce(self, face): 
        action_needed, msg = self.face_enforcer.check_face(face)
        if action_needed:
            action_needed()
            #slight relax in the limit, trying to adjust.TODO:only reduces.
            self.face_enforcer.adjust_y_limit_low_after_scold()
        if msg:
            return msg
    
    @property
    def should_process_this_frame(self):
        return self.frame_counter.check_if_capture

    def main(self):
                
        while(not self._event_quit):
            self.timer.mark_new_frame()

            #Capture frame-by-frame
            a_frame = self.capturer.get_frame()
            a_frame = flip_frame(a_frame)
            self.gui.feed_frame(a_frame)

            #detect face part:
            if self.should_process_this_frame:
                #face>>(x,y,w,h)
                face = self.detect_face_in_frame(a_frame)

                if face is not None:
                    self.gui.show_face_position(face)
                    if self._event_debug:
                        self.gui.show_face(face)
                    if self._event_auto_limit:
                        self._event_msg = self.handle_auto_limit(face)
                    elif self._event_enforcing:
                        self._event_msg = self.handle_enforce(face)

            #this if is out of the process one to leave the msg in between frames
            if self._event_msg:
                self.gui.show_msg(self._event_msg)

            #Check user input, this part needs to be after the frame has been created and fed to gui:
            self.dispatch_keyb_events()
            if self._event_debug:
                self.gui.show_debug(self.timer)
            #TODO: if face detected, work counter counts:
            if self.work_timer.is_started:
                self.gui.show_contdown(self.work_timer.get_time_left())
                
            #Add on-screen controls and limits visual guide:
            self.gui.show_controls()
            self.gui.show_limits(self.face_enforcer)

            #Display the resulting frame
            if self._event_image_show:
                self.gui.show_image()

        #if we are out of the while:
        self.clean_up()

    def clean_up(self):
        self.capturer.release()
        self.gui.close_window()