Ejemplo n.º 1
0
    def __init__(self):
        rospy.init_node("fasel")
        self.enrollService = rospy.Service("enroll", Enroll, self.handleEnrollFace)
        self.trainService = rospy.Service("train", Train, self.handleTrain)
        self.resetService = rospy.Service("reset", Reset, self.handleReset)
        self.namesPub = rospy.Publisher("names", String)
        self.personEventPub = rospy.Publisher("person_event", PersonEvent)
        self.imagePub = rospy.Publisher("images", Image)
        self.imageSub = rospy.Subscriber("image", Image, self.handleImage)

        self.bridge = CvBridge()

        self.face_detector = CascadeDetector(cascade_name=CASCADE_NAME, image_scale=0.5)
        self.fel = loadFilterEyeLocator(FEL_NAME)
        self.face_rec = SVMFaceRec()

        self.arialblack24 = PIL.ImageFont.truetype(ARIAL_BLACK_NAME, 24)

        self.svm_mode = SVM_AUTOMATIC
        self.svm_C = 4.000e00
        self.svm_Gamma = 9.766e-04

        self.current_faces = []
        self.enrolling = None
        self.enroll_count = 0
        self.enroll_max = 64
        self.enroll_list = []
        self.enrollCondition = Condition()

        self.isTrained = False

        self.nameList = []
        self.faceNames = []
        self.faceCount = 0
        self.faceTrack = dict()

        self.face_processing = True
        self.eye_processing = True
        self.image_flip = True

        self.reqQueueLock = Lock()
        self.faceTrackLock = Lock()

        self.is_running = True
        self.eventUpdateDelay = 2.0  # seconds
        self.eventUpdateTimer = Thread(target=self.eventUpdate)
        self.eventUpdateTimer.start()
Ejemplo n.º 2
0
class Facel:
    def __init__(self):
        rospy.init_node("fasel")
        self.enrollService = rospy.Service("enroll", Enroll, self.handleEnrollFace)
        self.trainService = rospy.Service("train", Train, self.handleTrain)
        self.resetService = rospy.Service("reset", Reset, self.handleReset)
        self.namesPub = rospy.Publisher("names", String)
        self.personEventPub = rospy.Publisher("person_event", PersonEvent)
        self.imagePub = rospy.Publisher("images", Image)
        self.imageSub = rospy.Subscriber("image", Image, self.handleImage)

        self.bridge = CvBridge()

        self.face_detector = CascadeDetector(cascade_name=CASCADE_NAME, image_scale=0.5)
        self.fel = loadFilterEyeLocator(FEL_NAME)
        self.face_rec = SVMFaceRec()

        self.arialblack24 = PIL.ImageFont.truetype(ARIAL_BLACK_NAME, 24)

        self.svm_mode = SVM_AUTOMATIC
        self.svm_C = 4.000e00
        self.svm_Gamma = 9.766e-04

        self.current_faces = []
        self.enrolling = None
        self.enroll_count = 0
        self.enroll_max = 64
        self.enroll_list = []
        self.enrollCondition = Condition()

        self.isTrained = False

        self.nameList = []
        self.faceNames = []
        self.faceCount = 0
        self.faceTrack = dict()

        self.face_processing = True
        self.eye_processing = True
        self.image_flip = True

        self.reqQueueLock = Lock()
        self.faceTrackLock = Lock()

        self.is_running = True
        self.eventUpdateDelay = 2.0  # seconds
        self.eventUpdateTimer = Thread(target=self.eventUpdate)
        self.eventUpdateTimer.start()

    # Convert opencv2 image to pyvision image
    def opencv_to_pyvision(self, cv_image):
        pil_img = PIL.Image.fromstring("RGB", (cv_image.width, cv_image.height), cv_image.tostring())
        pyimg = pv.Image(pil_img)
        return pyimg

    # Convert pyvision image to opencv2 image
    def pyvision_to_opencv(self, pyimg):
        pil_img = pyimg.asPIL()
        cv_img = cv.CreateImageHeader(pil_img.size, cv.IPL_DEPTH_8U, 3)  # RGB image
        cv.SetData(cv_img, pil_img.tostring(), pil_img.size[0] * 3)
        return cv_img

    def PIL_to_opencv(self, pil_img):
        cv_img = cv.CreateImageHeader(pil_img.size, cv.IPL_DEPTH_8U, 3)  # RGB image
        cv.SetData(cv_img, pil_img.tostring(), pil_img.size[0] * 3)
        return cv_img

    def onFrame(self, img):
        """
        Process a video frame.
        """
        self.eye_time = 0.0

        names = []
        nFaces = 0

        if self.face_processing:

            faces = self.findFaces(img)
            nFaces = len(faces)

            if self.enrolling != None:
                success = None
                for rect, leye, reye in faces:
                    img.annotateRect(self.enrolling, color="yellow")

                    if (success == None) and is_success(self.enrolling, rect):
                        success = rect
                        img.annotateRect(rect, color="blue")
                        if self.eye_processing:
                            img.annotatePoint(leye, color="blue")
                            img.annotatePoint(reye, color="blue")
                        self.enroll_list.append([img, rect, leye, reye])

                    else:
                        img.annotateRect(rect, color="red")
                        if self.eye_processing:
                            img.annotatePoint(leye, color="red")
                            img.annotatePoint(reye, color="red")
                        img.annotateLine(
                            pv.Point(rect.x, rect.y), pv.Point(rect.x + rect.w, rect.y + rect.h), color="red"
                        )
                        img.annotateLine(
                            pv.Point(rect.x + rect.w, rect.y), pv.Point(rect.x, rect.y + rect.h), color="red"
                        )

                if success == None:
                    rect = self.enrolling
                    img.annotateLine(
                        pv.Point(rect.x, rect.y), pv.Point(rect.x + rect.w, rect.y + rect.h), color="yellow"
                    )
                    img.annotateLine(
                        pv.Point(rect.x + rect.w, rect.y), pv.Point(rect.x, rect.y + rect.h), color="yellow"
                    )
                else:
                    # enroll in the identification algorithm
                    pass
            else:
                for rect, leye, reye in faces:
                    img.annotateRect(rect, color="blue")
                    if self.eye_processing:
                        img.annotatePoint(leye, color="blue")
                        img.annotatePoint(reye, color="blue")

                for rect, leye, reye in faces:
                    img.annotateRect(rect, color="blue")
                    img.annotatePoint(leye, color="blue")
                    img.annotatePoint(reye, color="blue")

            if self.isTrained:
                self.label_time = time.time()
                for rect, leye, reye in faces:
                    if self.face_rec.isTrained():
                        label = self.face_rec.predict(img, leye, reye)
                        names.append([0.5 * (leye + reye), label])

                self.label_time = time.time() - self.label_time

        im = img.asAnnotated()

        # Flip to mirror image
        if self.image_flip:
            im = im.transpose(FLIP_LEFT_RIGHT)

        if self.enrolling != None:
            self.enrollCondition.acquire()
            self.enroll_count += 1
            self.enrollCondition.notify()
            self.enrollCondition.release()

            # Draw on the image
            draw = PIL.ImageDraw.Draw(im)
            x, y = self.enrolling.x, self.enrolling.y
            if self.image_flip:
                xsize, ysize = im.size
                x = xsize - (x + self.enrolling.w)
            draw.text(
                (x + 10, y + 10),
                "Enrolling: %2d of %2d" % (self.enroll_count, self.enroll_max),
                fill="yellow",
                font=self.arialblack24,
            )
            del draw

        facesEntered = []

        if len(names) > 0:

            draw = PIL.ImageDraw.Draw(im)

            for pt, name in names:
                x, y = pt.X(), pt.Y()

                # Draw on the image
                x, y = pt.X(), pt.Y()
                w, h = draw.textsize(name, font=self.arialblack24)

                if self.image_flip:
                    xsize, ysize = im.size
                    x = xsize - x - 0.5 * w
                else:
                    x = x - 0.5 * w

                draw.text((x, y - 20 - h), name, fill="green", font=self.arialblack24)

                facesEntered.append(name)

                # Publish only new names
                if name not in self.faceNames:
                    str = "seeing %s" % name
                    rospy.loginfo(str)
                    self.namesPub.publish(String(name))
                    self.publishPersonEvent(name, "entered")

            del draw

        # Find all of the faces that are no longer detected
        for name in self.faceNames:
            if name not in facesEntered:
                self.publishPersonEvent(name, "exited")

        #  print "{0} {1} {2}".format(nFaces, self.faceCount, len(facesEntered))
        nFaces = nFaces - len(facesEntered)

        # For unidentified faces
        # figure out how many entered/exited
        if (nFaces - self.faceCount) > 0:
            self.publishPersonEvent("unknown", "entered")

        if (nFaces - self.faceCount) < 0:
            self.publishPersonEvent("unknown", "exited")

        # Update all for the next round
        self.faceNames = facesEntered
        self.faceCount = nFaces

        # Publish the image
        cv_img = self.PIL_to_opencv(im)
        # cv_img = self.pyvision_to_opencv(img)
        msg = self.bridge.cv_to_imgmsg(cv_img, encoding="rgb8")

        self.imagePub.publish(msg)

    def publishPersonEvent(self, name, event):
        """
        Updates the dictionary
        """
        now = time.time()

        # In case of non-existing records, force the update
        if name in self.faceTrack:
            self.faceTrackLock.acquire()
            pastEvent, lastEvent, recTime = self.faceTrack[name]
            self.faceTrackLock.release()
        else:
            recTime = now - self.eventUpdateDelay
            lastEvent = "undefined"
            pastEvent = lastEvent

        self.faceTrackLock.acquire()
        self.faceTrack[name] = (pastEvent, event, now)
        self.faceTrackLock.release()
        # print "publishPersonEvent for {0} {1} {2} {3} ".format(name,pastEvent,event,now)

    def eventUpdate(self):
        """
        Publishes events and updates the dictionary
        """
        while self.is_running:
            now = time.time()
            # Publish evey n seconds to avoid hysterisis,
            # where n = self.eventUpdateDelay
            self.faceTrackLock.acquire()
            for name in self.faceTrack:
                lastEvent, event, eventTime = self.faceTrack[name]
                if ((now - eventTime) >= self.eventUpdateDelay) and (event <> lastEvent):
                    # print "eventUpdate for {0} {1} {2} {3} ".format(name,lastEvent,event,now)
                    self.personEventPub.publish(event, name)
                    self.faceTrack[name] = (event, event, now)
                    # print "eventUpdate to {0} ".format(event)
            self.faceTrackLock.release()

            time.sleep(self.eventUpdateDelay)

    def enrollFace(self, name):
        with self.reqQueueLock:
            """
            Starts the enrollment process.
            """
            faces = self.current_faces

            if len(faces) > 1:
                return "too many faces to enroll"

            for rect, leye, reye in faces:
                print "Start Enrolling %s" % (name)
                self.enrolling = rect
                self.enroll_count = 0
                self.nameList.append(name)

                self.enrollCondition.acquire()
                while self.enroll_count < self.enroll_max:
                    self.enrollCondition.wait()
                self.enrollCondition.release()

                self.enrolling = None

                for data, rect, leye, reye in self.enroll_list:
                    self.face_rec.addTraining(data, leye, reye, name)

                self.enroll_count = 0
                self.enroll_list = []

        return "ok"

    def trainFaces(self):
        with self.reqQueueLock:
            """
            Start the SVM training process.
            """
            result = "ok"

            # Prevent face prediction while training
            self.isTrained = False

            if self.svm_mode == SVM_AUTOMATIC:
                # Train with automatic tuning.
                print "Training mode: auto tuning"
                self.face_rec.train()  # callback=progress.Update)
                self.svm_C = self.face_rec.svm.C
                self.svm_Gamma = self.face_rec.svm.gamma
            else:
                # Train with manual tuning.
                print "Training mode: manual tuning"
                self.face_rec.train(C=[self.svm_C], Gamma=[self.svm_Gamma])  # ,callback=progress.Update)

            if self.face_rec.isTrained():
                result = "ok"
                self.isTrained = True
            else:
                result = "Error"

        return result

    def resetFaces(self):
        with self.reqQueueLock:
            """
            Clear the enrollment data.
            """
            result = "ok"

            self.isTrained = False

            nameList = []

            # Clear the enrollment data for the SVM
            self.face_rec.reset()

        return result

    def findFaces(self, img):
        faces = []

        self.detect_time = time.time()
        rects = self.face_detector.detect(img)
        self.detect_time = time.time() - self.detect_time

        cvtile = opencv.cvCreateMat(128, 128, opencv.CV_8UC3)
        bwtile = opencv.cvCreateMat(128, 128, opencv.CV_8U)

        cvimg = img.asOpenCV()

        self.eye_time = time.time()

        for rect in rects:
            faceim = opencv.cvGetSubRect(cvimg, rect.asOpenCV())
            opencv.cvResize(faceim, cvtile)

            affine = pv.AffineFromRect(rect, (128, 128))

            opencv.cvCvtColor(cvtile, bwtile, cv.CV_BGR2GRAY)

            leye, reye, lcp, rcp = self.fel.locateEyes(bwtile)
            leye = pv.Point(leye)
            reye = pv.Point(reye)

            leye = affine.invertPoint(leye)
            reye = affine.invertPoint(reye)

            faces.append([rect, leye, reye])

        self.eye_time = time.time() - self.eye_time
        self.current_faces = faces

        return faces

    def handleImage(self, image_message):
        cv_image = self.bridge.imgmsg_to_cv(image_message, desired_encoding="rgb8")
        pyimg = self.opencv_to_pyvision(cv_image)

        self.onFrame(pyimg)

        # msg = self.bridge.cv_to_imgmsg(cv_image, encoding='rgb8')
        # self.imagePub.publish(msg)

    def handleEnrollFace(self, msg):
        result = "ok"
        print "Enrolling new name:" + msg.name

        result = self.enrollFace(msg.name)
        return EnrollResponse(result)

    def handleTrain(self, msg):
        result = "ok"
        print "Training..."

        if len(self.nameList) >= 2:
            result = self.trainFaces()
        else:
            result = "Error: need at least 2 faces to train"

        return TrainResponse(result)

    def handleReset(self, msg):
        result = "ok"
        print "Resetting..."

        result = self.resetFaces()

        return ResetResponse(result)
Ejemplo n.º 3
0
    def __init__(self,parent,id,name,size=(640,672)):
        '''
        Create all the windows and controls used for the window and 
        '''
        wx.Frame.__init__(self,parent,id,name,size=size)
        
        self.CenterOnScreen(wx.HORIZONTAL)
        self.timing_window = None # Initialize timing window
        
        # ------------- Face Processing -----------------
        self.face_detector = CascadeDetector(cascade_name=CASCADE_NAME,image_scale=0.5)
        self.fel = FilterEyeLocator(FEL_NAME)
        self.face_rec = SVMFaceRec()
        
        self.svm_mode  = SVM_AUTOMATIC
        self.svm_C     = 4.000e+00
        self.svm_Gamma = 9.766e-04
        
        self.current_faces = []
        self.enrolling    = None
        self.enroll_count = 0
        self.enroll_max   = 32
        self.enroll_list  = []
        
        self.previous_time = time.time()
        
        self.arialblack24 = PIL.ImageFont.truetype(ARIAL_BLACK_NAME, 24)

        # ---------------- Basic Data -------------------
        try:
            self.webcam = Webcam()
        except SystemExit:
            raise
        except:
            trace = traceback.format_exc()
            message = TraceBackDialog(None, "Camera Error", CAMERA_ERROR, trace)
            message.ShowModal()
            
            sys.stderr.write("FaceL Error: an error occurred while trying to connect to the camera.  Details follow.\n\n")
            sys.stderr.write(trace)
            sys.exit(CAMERA_ERROR_CODE)

        # ------------- Other Components ----------------
        self.CreateStatusBar()
        
        # ------------------- Menu ----------------------
        # Creating the menubar.
        
        # Menu IDs
        license_id = wx.NewId()
        
        mirror_id = wx.NewId()
        face_id = wx.NewId()
        svm_tune_id = wx.NewId()
        performance_id = wx.NewId()
        
        # Menu Items
        self.file_menu = wx.Menu();

        self.file_menu.Append( wx.ID_ABOUT, "&About..." )
        self.file_menu.Append( license_id, "FaceL License..." )
        self.file_menu.AppendSeparator();
        self.file_menu.Append( wx.ID_EXIT, "E&xit" )

        self.options_menu = wx.Menu();
        self.face_menuitem = self.options_menu.AppendCheckItem( face_id, "Face Processing" )
        self.eye_menuitem = self.options_menu.AppendCheckItem( face_id, "Eye Detection" )
        self.mirror_menuitem = self.options_menu.AppendCheckItem( mirror_id, "Mirror Video" )
        self.options_menu.AppendSeparator()
        self.options_menu.Append( svm_tune_id, "SVM Tuning..." )
        self.options_menu.Append( performance_id, "Performance..." )
        
        # Create Menu Bar
        self.menu_bar = wx.MenuBar();
        self.menu_bar.Append( self.file_menu, "&File" )
        self.menu_bar.Append( self.options_menu, "&Options" )

        self.SetMenuBar( self.menu_bar )
        
        # Menu Events
        wx.EVT_MENU(self, wx.ID_ABOUT, self.onAbout )
        wx.EVT_MENU(self, license_id, self.onLicense )

        wx.EVT_MENU(self, mirror_id, self.onNull )
        wx.EVT_MENU(self, face_id, self.onNull )
        wx.EVT_MENU(self, svm_tune_id, self.onSVMTune )
        wx.EVT_MENU(self, performance_id, self.onTiming )
        
        # Set up menu checks
        self.face_menuitem.Check(True)
        self.eye_menuitem.Check(True)
        self.mirror_menuitem.Check(True)
        
        
        # ----------------- Image List ------------------
        
        # --------------- Image Display -----------------
        self.static_bitmap = wx.StaticBitmap(self,wx.NewId(), bitmap=wx.EmptyBitmap(640, 480))
        
        self.controls_box = wx.StaticBox(self, wx.NewId(), "Controls")

        self.facel_logo = wx.StaticBitmap(self,wx.NewId(), bitmap=wx.Bitmap(FACEL_LOGO))
        self.csu_logo = wx.StaticBitmap(self,wx.NewId(), bitmap=wx.Bitmap(CSU_LOGO))
#        self.performance_box = wx.StaticBox(self, wx.NewId(), "Performance")
        
        self.enroll_chioce_label = wx.StaticText(self, wx.NewId(), "Enrollment Count:", style=wx.ALIGN_LEFT)
        self.enroll_choice = wx.Choice(self,wx.NewId(),wx.Point(0,0),wx.Size(-1,-1),['16','32','48','64','128','256'])
        self.enroll_choice.Select(3)
        
        self.train_button = wx.Button(self,wx.NewId(),'Train Labeler')
        self.reset_button = wx.Button(self,wx.NewId(),'Clear Labels')
        
        # --------------- Instrumentation ---------------
        
        
          
        self.enroll_label = wx.StaticText(self, wx.NewId(), "Click a face in the video to enroll.", style=wx.ALIGN_LEFT)

        self.ids_label = wx.StaticText(self, wx.NewId(), "Labels:", size=wx.Size(-1,16), style=wx.ALIGN_LEFT)
        self.ids_text = wx.StaticText(self, wx.NewId(), size = wx.Size(30,16), style= wx.ALIGN_RIGHT )  
        
        self.faces_label = wx.StaticText(self, wx.NewId(), "Faces:", size=wx.Size(-1,16), style=wx.ALIGN_LEFT)
        self.faces_text = wx.StaticText(self, wx.NewId(), size = wx.Size(30,16), style= wx.ALIGN_RIGHT )          
        

        # --------------- Window Layout -----------------
        enroll_sizer = wx.BoxSizer(wx.HORIZONTAL)
        enroll_sizer.Add(self.ids_label, flag = wx.ALIGN_CENTER | wx.ALL, border=4)
        enroll_sizer.Add(self.ids_text, flag = wx.ALIGN_CENTER | wx.ALL, border=4)
        enroll_sizer.AddSpacer(20)
        enroll_sizer.Add(self.faces_label, flag = wx.ALIGN_CENTER | wx.ALL, border=4)
        enroll_sizer.Add(self.faces_text, flag = wx.ALIGN_CENTER | wx.ALL, border=4)

        training_sizer = wx.BoxSizer(wx.HORIZONTAL)
        training_sizer.Add(self.train_button, flag = wx.ALIGN_CENTER | wx.ALL, border=4)
        training_sizer.Add(self.reset_button, flag = wx.ALIGN_CENTER | wx.ALL, border=4)

    
        enroll_choice_sizer = wx.BoxSizer(wx.HORIZONTAL)
        enroll_choice_sizer.Add(self.enroll_chioce_label, flag = wx.ALIGN_CENTER | wx.ALL, border=0)
        enroll_choice_sizer.Add(self.enroll_choice, flag = wx.ALIGN_CENTER | wx.ALL, border=0)

        controls_sizer = wx.StaticBoxSizer(self.controls_box,wx.VERTICAL) #wx.BoxSizer(wx.VERTICAL)
        controls_sizer.Add(self.enroll_label, flag = wx.ALIGN_LEFT | wx.ALL, border=0)
        controls_sizer.Add(enroll_sizer, flag = wx.ALIGN_LEFT | wx.ALL, border=0)
        controls_sizer.Add(enroll_choice_sizer, flag = wx.ALIGN_LEFT | wx.ALL, border=4)
        controls_sizer.Add(training_sizer, flag = wx.ALIGN_LEFT | wx.ALL, border=0)

        bottom_sizer = wx.BoxSizer(wx.HORIZONTAL)
        bottom_sizer.Add(self.facel_logo, flag = wx.ALIGN_CENTER | wx.ALL, border=0)
        bottom_sizer.Add(controls_sizer, flag = wx.ALIGN_TOP | wx.ALL, border=4)
        bottom_sizer.Add(self.csu_logo, flag = wx.ALIGN_CENTER | wx.ALL, border=0)

        main_sizer = wx.BoxSizer(wx.VERTICAL)
        main_sizer.Add(self.static_bitmap, flag = wx.ALIGN_CENTER | wx.ALL, border=0)
        main_sizer.Add(bottom_sizer, flag = wx.ALIGN_CENTER | wx.ALL, border=4)
        

        self.SetAutoLayout(True)
        self.SetSizer(main_sizer)
        self.Layout()
        
        # -----------------------------------------------
        self.timer = FrameTimer(self)
        self.timer.Start(200)
        
        # -------------- Event Handleing ----------------
        wx.EVT_SIZE(self.static_bitmap, self.onBitmapResize)
        wx.EVT_LEFT_DOWN(self.static_bitmap, self.onClick)
                
        self.Bind(wx.EVT_BUTTON, self.onTrain, id=self.train_button.GetId())
        self.Bind(wx.EVT_BUTTON, self.onReset, id=self.reset_button.GetId())
        
        # --------------- Setup State -------------------
        self.setupState()
Ejemplo n.º 4
0
class VideoWindow(wx.Frame):
    '''
    This is the main FaceL window which includes the webcam video and enrollment and training controls.
    '''
    
    def __init__(self,parent,id,name,size=(640,672)):
        '''
        Create all the windows and controls used for the window and 
        '''
        wx.Frame.__init__(self,parent,id,name,size=size)
        
        self.CenterOnScreen(wx.HORIZONTAL)
        self.timing_window = None # Initialize timing window
        
        # ------------- Face Processing -----------------
        self.face_detector = CascadeDetector(cascade_name=CASCADE_NAME,image_scale=0.5)
        self.fel = FilterEyeLocator(FEL_NAME)
        self.face_rec = SVMFaceRec()
        
        self.svm_mode  = SVM_AUTOMATIC
        self.svm_C     = 4.000e+00
        self.svm_Gamma = 9.766e-04
        
        self.current_faces = []
        self.enrolling    = None
        self.enroll_count = 0
        self.enroll_max   = 32
        self.enroll_list  = []
        
        self.previous_time = time.time()
        
        self.arialblack24 = PIL.ImageFont.truetype(ARIAL_BLACK_NAME, 24)

        # ---------------- Basic Data -------------------
        try:
            self.webcam = Webcam()
        except SystemExit:
            raise
        except:
            trace = traceback.format_exc()
            message = TraceBackDialog(None, "Camera Error", CAMERA_ERROR, trace)
            message.ShowModal()
            
            sys.stderr.write("FaceL Error: an error occurred while trying to connect to the camera.  Details follow.\n\n")
            sys.stderr.write(trace)
            sys.exit(CAMERA_ERROR_CODE)

        # ------------- Other Components ----------------
        self.CreateStatusBar()
        
        # ------------------- Menu ----------------------
        # Creating the menubar.
        
        # Menu IDs
        license_id = wx.NewId()
        
        mirror_id = wx.NewId()
        face_id = wx.NewId()
        svm_tune_id = wx.NewId()
        performance_id = wx.NewId()
        
        # Menu Items
        self.file_menu = wx.Menu();

        self.file_menu.Append( wx.ID_ABOUT, "&About..." )
        self.file_menu.Append( license_id, "FaceL License..." )
        self.file_menu.AppendSeparator();
        self.file_menu.Append( wx.ID_EXIT, "E&xit" )

        self.options_menu = wx.Menu();
        self.face_menuitem = self.options_menu.AppendCheckItem( face_id, "Face Processing" )
        self.eye_menuitem = self.options_menu.AppendCheckItem( face_id, "Eye Detection" )
        self.mirror_menuitem = self.options_menu.AppendCheckItem( mirror_id, "Mirror Video" )
        self.options_menu.AppendSeparator()
        self.options_menu.Append( svm_tune_id, "SVM Tuning..." )
        self.options_menu.Append( performance_id, "Performance..." )
        
        # Create Menu Bar
        self.menu_bar = wx.MenuBar();
        self.menu_bar.Append( self.file_menu, "&File" )
        self.menu_bar.Append( self.options_menu, "&Options" )

        self.SetMenuBar( self.menu_bar )
        
        # Menu Events
        wx.EVT_MENU(self, wx.ID_ABOUT, self.onAbout )
        wx.EVT_MENU(self, license_id, self.onLicense )

        wx.EVT_MENU(self, mirror_id, self.onNull )
        wx.EVT_MENU(self, face_id, self.onNull )
        wx.EVT_MENU(self, svm_tune_id, self.onSVMTune )
        wx.EVT_MENU(self, performance_id, self.onTiming )
        
        # Set up menu checks
        self.face_menuitem.Check(True)
        self.eye_menuitem.Check(True)
        self.mirror_menuitem.Check(True)
        
        
        # ----------------- Image List ------------------
        
        # --------------- Image Display -----------------
        self.static_bitmap = wx.StaticBitmap(self,wx.NewId(), bitmap=wx.EmptyBitmap(640, 480))
        
        self.controls_box = wx.StaticBox(self, wx.NewId(), "Controls")

        self.facel_logo = wx.StaticBitmap(self,wx.NewId(), bitmap=wx.Bitmap(FACEL_LOGO))
        self.csu_logo = wx.StaticBitmap(self,wx.NewId(), bitmap=wx.Bitmap(CSU_LOGO))
#        self.performance_box = wx.StaticBox(self, wx.NewId(), "Performance")
        
        self.enroll_chioce_label = wx.StaticText(self, wx.NewId(), "Enrollment Count:", style=wx.ALIGN_LEFT)
        self.enroll_choice = wx.Choice(self,wx.NewId(),wx.Point(0,0),wx.Size(-1,-1),['16','32','48','64','128','256'])
        self.enroll_choice.Select(3)
        
        self.train_button = wx.Button(self,wx.NewId(),'Train Labeler')
        self.reset_button = wx.Button(self,wx.NewId(),'Clear Labels')
        
        # --------------- Instrumentation ---------------
        
        
          
        self.enroll_label = wx.StaticText(self, wx.NewId(), "Click a face in the video to enroll.", style=wx.ALIGN_LEFT)

        self.ids_label = wx.StaticText(self, wx.NewId(), "Labels:", size=wx.Size(-1,16), style=wx.ALIGN_LEFT)
        self.ids_text = wx.StaticText(self, wx.NewId(), size = wx.Size(30,16), style= wx.ALIGN_RIGHT )  
        
        self.faces_label = wx.StaticText(self, wx.NewId(), "Faces:", size=wx.Size(-1,16), style=wx.ALIGN_LEFT)
        self.faces_text = wx.StaticText(self, wx.NewId(), size = wx.Size(30,16), style= wx.ALIGN_RIGHT )          
        

        # --------------- Window Layout -----------------
        enroll_sizer = wx.BoxSizer(wx.HORIZONTAL)
        enroll_sizer.Add(self.ids_label, flag = wx.ALIGN_CENTER | wx.ALL, border=4)
        enroll_sizer.Add(self.ids_text, flag = wx.ALIGN_CENTER | wx.ALL, border=4)
        enroll_sizer.AddSpacer(20)
        enroll_sizer.Add(self.faces_label, flag = wx.ALIGN_CENTER | wx.ALL, border=4)
        enroll_sizer.Add(self.faces_text, flag = wx.ALIGN_CENTER | wx.ALL, border=4)

        training_sizer = wx.BoxSizer(wx.HORIZONTAL)
        training_sizer.Add(self.train_button, flag = wx.ALIGN_CENTER | wx.ALL, border=4)
        training_sizer.Add(self.reset_button, flag = wx.ALIGN_CENTER | wx.ALL, border=4)

    
        enroll_choice_sizer = wx.BoxSizer(wx.HORIZONTAL)
        enroll_choice_sizer.Add(self.enroll_chioce_label, flag = wx.ALIGN_CENTER | wx.ALL, border=0)
        enroll_choice_sizer.Add(self.enroll_choice, flag = wx.ALIGN_CENTER | wx.ALL, border=0)

        controls_sizer = wx.StaticBoxSizer(self.controls_box,wx.VERTICAL) #wx.BoxSizer(wx.VERTICAL)
        controls_sizer.Add(self.enroll_label, flag = wx.ALIGN_LEFT | wx.ALL, border=0)
        controls_sizer.Add(enroll_sizer, flag = wx.ALIGN_LEFT | wx.ALL, border=0)
        controls_sizer.Add(enroll_choice_sizer, flag = wx.ALIGN_LEFT | wx.ALL, border=4)
        controls_sizer.Add(training_sizer, flag = wx.ALIGN_LEFT | wx.ALL, border=0)

        bottom_sizer = wx.BoxSizer(wx.HORIZONTAL)
        bottom_sizer.Add(self.facel_logo, flag = wx.ALIGN_CENTER | wx.ALL, border=0)
        bottom_sizer.Add(controls_sizer, flag = wx.ALIGN_TOP | wx.ALL, border=4)
        bottom_sizer.Add(self.csu_logo, flag = wx.ALIGN_CENTER | wx.ALL, border=0)

        main_sizer = wx.BoxSizer(wx.VERTICAL)
        main_sizer.Add(self.static_bitmap, flag = wx.ALIGN_CENTER | wx.ALL, border=0)
        main_sizer.Add(bottom_sizer, flag = wx.ALIGN_CENTER | wx.ALL, border=4)
        

        self.SetAutoLayout(True)
        self.SetSizer(main_sizer)
        self.Layout()
        
        # -----------------------------------------------
        self.timer = FrameTimer(self)
        self.timer.Start(200)
        
        # -------------- Event Handleing ----------------
        wx.EVT_SIZE(self.static_bitmap, self.onBitmapResize)
        wx.EVT_LEFT_DOWN(self.static_bitmap, self.onClick)
                
        self.Bind(wx.EVT_BUTTON, self.onTrain, id=self.train_button.GetId())
        self.Bind(wx.EVT_BUTTON, self.onReset, id=self.reset_button.GetId())
        
        # --------------- Setup State -------------------
        self.setupState()
                
    def onTrain(self,event=None):
        '''
        Start the SVM training process.
        '''
        print "Train"
        #progress = wx.ProgressDialog(title="SVM Training", message="Training the Face Recognition Algorithm. Please Wait...")
        if self.svm_mode == SVM_AUTOMATIC:
            # Train with automatic tuning.
            self.face_rec.train() #callback=progress.Update)
            self.svm_C = self.face_rec.svm.C
            self.svm_Gamma = self.face_rec.svm.gamma
        else:
            # Train with manual tuning.
            self.face_rec.train( C=[self.svm_C] , Gamma=[self.svm_Gamma])# ,callback=progress.Update)
        
        #progress.Destroy()
        
    def onReset(self,event=None):
        '''
        Clear the enrollment data for the SVM.
        '''
        self.face_rec.reset() 
        self.setupState()

        
    def onFrame(self,event=None):
        '''
        Retrieve and process a video frame.
        '''
        self.timer.Stop()        
        starttime = time.time()
        self.detect_time = 0.0
        self.eye_time = 0.0
        self.label_time = 0.0
        img = self.webcam.query()
        
        face_processing = self.face_menuitem.IsChecked()
        eye_processing = self.eye_menuitem.IsChecked()
        
        names = []
        
        if face_processing:
            faces = self.findFaces(img)
            if self.enrolling != None:
                success = None
                for rect,leye,reye in faces:
                    img.annotateRect(self.enrolling,color='yellow')
                    if (success == None) and is_success(self.enrolling,rect):
                        success = rect
                        img.annotateRect(rect,color='blue')
                        if eye_processing:
                            img.annotatePoint(leye,color='blue')
                            img.annotatePoint(reye,color='blue')
                        self.enroll_list.append([img,rect,leye,reye])

                    else:
                        img.annotateRect(rect,color='red')
                        if eye_processing:
                            img.annotatePoint(leye,color='red')
                            img.annotatePoint(reye,color='red')
                        img.annotateLine(pv.Point(rect.x,rect.y),pv.Point(rect.x+rect.w,rect.y+rect.h), color='red')
                        img.annotateLine(pv.Point(rect.x+rect.w,rect.y),pv.Point(rect.x,rect.y+rect.h), color='red')

                if success == None:
                    rect = self.enrolling
                    img.annotateLine(pv.Point(rect.x,rect.y),pv.Point(rect.x+rect.w,rect.y+rect.h), color='yellow')
                    img.annotateLine(pv.Point(rect.x+rect.w,rect.y),pv.Point(rect.x,rect.y+rect.h), color='yellow')
                else:
                    #enroll in the identification algorithm
                    pass
            else:
                for rect,leye,reye in faces:
                    img.annotateRect(rect,color='blue')
                    if eye_processing:
                        img.annotatePoint(leye,color='blue')
                        img.annotatePoint(reye,color='blue')
                    
            
            if self.face_rec.isTrained():
                self.label_time = time.time()
                for rect,leye,reye in faces:
                    label = self.face_rec.predict(img,leye,reye)
                    names.append([0.5*(leye+reye),label])
                self.label_time = time.time() - self.label_time


        # Displaying Annotated Frame
        im = img.asAnnotated()
        if self.mirror_menuitem.IsChecked():
            im = im.transpose(FLIP_LEFT_RIGHT)
            
        if self.enrolling != None:
            draw = PIL.ImageDraw.Draw(im)
            x,y = self.enrolling.x,self.enrolling.y
            if self.mirror_menuitem.IsChecked():
                x = 640 - (x + self.enrolling.w)
            self.enroll_count += 1
            draw.text((x+10,y+10), "Enrolling: %2d of %2d"%(self.enroll_count,self.enroll_max), fill='yellow', font=self.arialblack24)
            del draw
            
            if self.enroll_count >= self.enroll_max:
                print "Count:",self.enroll_count
                
                if len(self.enroll_list) == 0:
                    warning_dialog = wx.MessageDialog(self,
                                                      "No faces were detected during the enrollment process.  Please face towards the camera and keep your face in the yellow rectangle during enrollment.",
                                                      style=wx.ICON_EXCLAMATION | wx.OK,
                                                      caption="Enrollment Error")
                    warning_dialog.ShowModal()
                else:
                    name_dialog = wx.TextEntryDialog(self, "Please enter a name to associate with the face. (%d faces captured)"%len(self.enroll_list), caption = "Enrollment ID")
                    result = name_dialog.ShowModal()
                    sub_id = name_dialog.GetValue()
                    if result == wx.ID_OK:
                        if sub_id == "":
                            print "Warning: Empty Subject ID"
                            warning_dialog = wx.MessageDialog(self,
                                                              "A name was entered in the previous dialog so this face will not be enrolled in the database.  Please repeat the enrollment process for this person.",
                                                              style=wx.ICON_EXCLAMATION | wx.OK,
                                                              caption="Enrollment Error")
                            warning_dialog.ShowModal()
                        else:
                            for data,rect,leye,reye in self.enroll_list:
                                self.face_rec.addTraining(data,leye,reye,sub_id)
                                self.setupState()

                                
                self.enroll_count = 0
                self.enrolling    = None
                self.enroll_list  = []
            
            
        if len(names) > 0:
            draw = PIL.ImageDraw.Draw(im)
            for pt,name in names:
                x,y = pt.X(),pt.Y() 
                w,h = draw.textsize(name,font=self.arialblack24)
                if self.mirror_menuitem.IsChecked():
                    x = 640 - x - 0.5*w
                else:
                    x = x - 0.5*w
                draw.text((x,y-20-h), name, fill='green', font=self.arialblack24)
            del draw

            
            
        wxImg = wx.EmptyImage(im.size[0], im.size[1])
        wxImg.SetData(im.tostring())
        bm = wxImg.ConvertToBitmap()
            
        self.static_bitmap.SetBitmap(bm)
        
        # Update timing gauges
        full_time = time.time() - starttime
        if self.timing_window != None:
            self.timing_window.update(self.detect_time,self.eye_time,self.label_time,full_time)
               
        self.ids_text.SetLabel("%d"%(self.face_rec.n_labels,))
        self.faces_text.SetLabel("%d"%(self.face_rec.n_faces,))
        
        sleep_time = 1
        if sys.platform.startswith("linux"):
            sleep_time = 10 
        # TODO: For macosx milliseconds should be 1
        # TODO: For linux milliseconds may need to be set to a higher value 10
        self.timer.Start(milliseconds = sleep_time, oneShot = 1)


    
    def setupState(self):
        #print "state",self.face_rec.n_labels,self.IsEnabled()
        if self.face_rec.n_labels >= 2:
            self.train_button.Enable()
        else:
            self.train_button.Disable()
            
        
    def onBitmapResize(self,event):
        w = event.GetSize().GetWidth()
        h = event.GetSize().GetHeight()

        self.static_bitmap.SetSize(event.GetSize())
              
              
    def onClick(self,event):
        '''
        Process a click in the Video window which starts the enrollment process.
        '''
        x = event.GetX()
        y = event.GetY()
        
        if self.mirror_menuitem.IsChecked():
            x = 640-x
            
        for rect,leye,reye in self.current_faces:
            if rect.containsPoint(pv.Point(x,y)):
                self.enrolling = rect
                self.enroll_count = 0
                self.enroll_max = int(self.enroll_choice.GetStringSelection())
                

    def findFaces(self,im):
        eye_processing = self.eye_menuitem.IsChecked()
        
        self.detect_time = time.time()
        rects = self.face_detector.detect(im)
        self.detect_time = time.time() - self.detect_time
 
        
        self.eye_time = time.time()       
        if eye_processing:
            faces = self.fel.locateEyes(im, rects)
        else:
            faces = []
            for rect in rects:
                affine = pv.AffineFromRect(rect,(1,1))
                leye = affine.invertPoint(AVE_LEFT_EYE)
                reye = affine.invertPoint(AVE_RIGHT_EYE)
                faces.append([rect,leye,reye])
        
        self.eye_time = time.time() - self.eye_time

        self.current_faces = faces

        return faces
    
    def onAbout(self,event):
        wx.MessageBox( ABOUT_MESSAGE,
                  "About FaceL", wx.OK | wx.ICON_INFORMATION )
        
    def onLicense(self,event):
        wx.MessageBox( LICENSE_MESSAGE,
                  "FaceL License", wx.OK | wx.ICON_INFORMATION )

    def onNull(self,*args,**kwargs):
        pass
    
    def onSVMTune(self,event):
        dialog = SVMTuningDialog(self, self.svm_mode, self.svm_C, self.svm_Gamma)
        dialog.CenterOnParent()

        result = dialog.ShowModal()
        if result == wx.ID_OK:
            self.svm_mode  = dialog.mode
            self.svm_C     = dialog.C
            self.svm_Gamma = dialog.Gamma
        
        print "SVM Tuning Info <MODE:%s; C:%0.2e; Gamma:%0.2e>"%(self.svm_mode,self.svm_C,self.svm_Gamma)
        
        dialog.Destroy()
        
        
    def onTiming(self,event):
        if self.timing_window == None:
            self.timing_window = TimingWindow(self, wx.NewId(),"Performance")
            self.timing_window.CenterOnParent()
            self.timing_window.Show(True)
            self.timing_window.Bind(wx.EVT_CLOSE, self.onCloseTiming, id=self.timing_window.GetId())

        else:
            self.timing_window.Show(True)
            self.timing_window.Raise()
        
        
    def onCloseTiming(self,event):
        self.timing_window.Destroy()
        self.timing_window = None
Ejemplo n.º 5
0
    def __init__(self, parent, id, name, size=(640, 672)):
        '''
        Create all the windows and controls used for the window and 
        '''
        wx.Frame.__init__(self, parent, id, name, size=size)

        self.CenterOnScreen(wx.HORIZONTAL)
        self.timing_window = None  # Initialize timing window

        # ------------- Face Processing -----------------
        self.face_detector = CascadeDetector(cascade_name=CASCADE_NAME,
                                             image_scale=0.5)
        self.fel = FilterEyeLocator(FEL_NAME)
        self.face_rec = SVMFaceRec()

        self.svm_mode = SVM_AUTOMATIC
        self.svm_C = 4.000e+00
        self.svm_Gamma = 9.766e-04

        self.current_faces = []
        self.enrolling = None
        self.enroll_count = 0
        self.enroll_max = 32
        self.enroll_list = []

        self.previous_time = time.time()

        self.arialblack24 = PIL.ImageFont.truetype(ARIAL_BLACK_NAME, 24)

        # ---------------- Basic Data -------------------
        try:
            self.webcam = Webcam()
        except SystemExit:
            raise
        except:
            trace = traceback.format_exc()
            message = TraceBackDialog(None, "Camera Error", CAMERA_ERROR,
                                      trace)
            message.ShowModal()

            sys.stderr.write(
                "FaceL Error: an error occurred while trying to connect to the camera.  Details follow.\n\n"
            )
            sys.stderr.write(trace)
            sys.exit(CAMERA_ERROR_CODE)

        # ------------- Other Components ----------------
        self.CreateStatusBar()

        # ------------------- Menu ----------------------
        # Creating the menubar.

        # Menu IDs
        license_id = wx.NewId()

        mirror_id = wx.NewId()
        face_id = wx.NewId()
        svm_tune_id = wx.NewId()
        performance_id = wx.NewId()

        # Menu Items
        self.file_menu = wx.Menu()

        self.file_menu.Append(wx.ID_ABOUT, "&About...")
        self.file_menu.Append(license_id, "FaceL License...")
        self.file_menu.AppendSeparator()
        self.file_menu.Append(wx.ID_EXIT, "E&xit")

        self.options_menu = wx.Menu()
        self.face_menuitem = self.options_menu.AppendCheckItem(
            face_id, "Face Processing")
        self.eye_menuitem = self.options_menu.AppendCheckItem(
            face_id, "Eye Detection")
        self.mirror_menuitem = self.options_menu.AppendCheckItem(
            mirror_id, "Mirror Video")
        self.options_menu.AppendSeparator()
        self.options_menu.Append(svm_tune_id, "SVM Tuning...")
        self.options_menu.Append(performance_id, "Performance...")

        # Create Menu Bar
        self.menu_bar = wx.MenuBar()
        self.menu_bar.Append(self.file_menu, "&File")
        self.menu_bar.Append(self.options_menu, "&Options")

        self.SetMenuBar(self.menu_bar)

        # Menu Events
        wx.EVT_MENU(self, wx.ID_ABOUT, self.onAbout)
        wx.EVT_MENU(self, license_id, self.onLicense)

        wx.EVT_MENU(self, mirror_id, self.onNull)
        wx.EVT_MENU(self, face_id, self.onNull)
        wx.EVT_MENU(self, svm_tune_id, self.onSVMTune)
        wx.EVT_MENU(self, performance_id, self.onTiming)

        # Set up menu checks
        self.face_menuitem.Check(True)
        self.eye_menuitem.Check(True)
        self.mirror_menuitem.Check(True)

        # ----------------- Image List ------------------

        # --------------- Image Display -----------------
        self.static_bitmap = wx.StaticBitmap(self,
                                             wx.NewId(),
                                             bitmap=wx.EmptyBitmap(640, 480))

        self.controls_box = wx.StaticBox(self, wx.NewId(), "Controls")

        self.facel_logo = wx.StaticBitmap(self,
                                          wx.NewId(),
                                          bitmap=wx.Bitmap(FACEL_LOGO))
        self.csu_logo = wx.StaticBitmap(self,
                                        wx.NewId(),
                                        bitmap=wx.Bitmap(CSU_LOGO))
        #        self.performance_box = wx.StaticBox(self, wx.NewId(), "Performance")

        self.enroll_chioce_label = wx.StaticText(self,
                                                 wx.NewId(),
                                                 "Enrollment Count:",
                                                 style=wx.ALIGN_LEFT)
        self.enroll_choice = wx.Choice(self, wx.NewId(), wx.Point(0, 0),
                                       wx.Size(-1, -1),
                                       ['16', '32', '48', '64', '128', '256'])
        self.enroll_choice.Select(3)

        self.train_button = wx.Button(self, wx.NewId(), 'Train Labeler')
        self.reset_button = wx.Button(self, wx.NewId(), 'Clear Labels')

        # --------------- Instrumentation ---------------

        self.enroll_label = wx.StaticText(
            self,
            wx.NewId(),
            "Click a face in the video to enroll.",
            style=wx.ALIGN_LEFT)

        self.ids_label = wx.StaticText(self,
                                       wx.NewId(),
                                       "Labels:",
                                       size=wx.Size(-1, 16),
                                       style=wx.ALIGN_LEFT)
        self.ids_text = wx.StaticText(self,
                                      wx.NewId(),
                                      size=wx.Size(30, 16),
                                      style=wx.ALIGN_RIGHT)

        self.faces_label = wx.StaticText(self,
                                         wx.NewId(),
                                         "Faces:",
                                         size=wx.Size(-1, 16),
                                         style=wx.ALIGN_LEFT)
        self.faces_text = wx.StaticText(self,
                                        wx.NewId(),
                                        size=wx.Size(30, 16),
                                        style=wx.ALIGN_RIGHT)

        # --------------- Window Layout -----------------
        enroll_sizer = wx.BoxSizer(wx.HORIZONTAL)
        enroll_sizer.Add(self.ids_label,
                         flag=wx.ALIGN_CENTER | wx.ALL,
                         border=4)
        enroll_sizer.Add(self.ids_text,
                         flag=wx.ALIGN_CENTER | wx.ALL,
                         border=4)
        enroll_sizer.AddSpacer(20)
        enroll_sizer.Add(self.faces_label,
                         flag=wx.ALIGN_CENTER | wx.ALL,
                         border=4)
        enroll_sizer.Add(self.faces_text,
                         flag=wx.ALIGN_CENTER | wx.ALL,
                         border=4)

        training_sizer = wx.BoxSizer(wx.HORIZONTAL)
        training_sizer.Add(self.train_button,
                           flag=wx.ALIGN_CENTER | wx.ALL,
                           border=4)
        training_sizer.Add(self.reset_button,
                           flag=wx.ALIGN_CENTER | wx.ALL,
                           border=4)

        enroll_choice_sizer = wx.BoxSizer(wx.HORIZONTAL)
        enroll_choice_sizer.Add(self.enroll_chioce_label,
                                flag=wx.ALIGN_CENTER | wx.ALL,
                                border=0)
        enroll_choice_sizer.Add(self.enroll_choice,
                                flag=wx.ALIGN_CENTER | wx.ALL,
                                border=0)

        controls_sizer = wx.StaticBoxSizer(
            self.controls_box, wx.VERTICAL)  #wx.BoxSizer(wx.VERTICAL)
        controls_sizer.Add(self.enroll_label,
                           flag=wx.ALIGN_LEFT | wx.ALL,
                           border=0)
        controls_sizer.Add(enroll_sizer, flag=wx.ALIGN_LEFT | wx.ALL, border=0)
        controls_sizer.Add(enroll_choice_sizer,
                           flag=wx.ALIGN_LEFT | wx.ALL,
                           border=4)
        controls_sizer.Add(training_sizer,
                           flag=wx.ALIGN_LEFT | wx.ALL,
                           border=0)

        bottom_sizer = wx.BoxSizer(wx.HORIZONTAL)
        bottom_sizer.Add(self.facel_logo,
                         flag=wx.ALIGN_CENTER | wx.ALL,
                         border=0)
        bottom_sizer.Add(controls_sizer, flag=wx.ALIGN_TOP | wx.ALL, border=4)
        bottom_sizer.Add(self.csu_logo,
                         flag=wx.ALIGN_CENTER | wx.ALL,
                         border=0)

        main_sizer = wx.BoxSizer(wx.VERTICAL)
        main_sizer.Add(self.static_bitmap,
                       flag=wx.ALIGN_CENTER | wx.ALL,
                       border=0)
        main_sizer.Add(bottom_sizer, flag=wx.ALIGN_CENTER | wx.ALL, border=4)

        self.SetAutoLayout(True)
        self.SetSizer(main_sizer)
        self.Layout()

        # -----------------------------------------------
        self.timer = FrameTimer(self)
        self.timer.Start(200)

        # -------------- Event Handleing ----------------
        wx.EVT_SIZE(self.static_bitmap, self.onBitmapResize)
        wx.EVT_LEFT_DOWN(self.static_bitmap, self.onClick)

        self.Bind(wx.EVT_BUTTON, self.onTrain, id=self.train_button.GetId())
        self.Bind(wx.EVT_BUTTON, self.onReset, id=self.reset_button.GetId())

        # --------------- Setup State -------------------
        self.setupState()
Ejemplo n.º 6
0
class VideoWindow(wx.Frame):
    '''
    This is the main FaceL window which includes the webcam video and enrollment and training controls.
    '''
    def __init__(self, parent, id, name, size=(640, 672)):
        '''
        Create all the windows and controls used for the window and 
        '''
        wx.Frame.__init__(self, parent, id, name, size=size)

        self.CenterOnScreen(wx.HORIZONTAL)
        self.timing_window = None  # Initialize timing window

        # ------------- Face Processing -----------------
        self.face_detector = CascadeDetector(cascade_name=CASCADE_NAME,
                                             image_scale=0.5)
        self.fel = FilterEyeLocator(FEL_NAME)
        self.face_rec = SVMFaceRec()

        self.svm_mode = SVM_AUTOMATIC
        self.svm_C = 4.000e+00
        self.svm_Gamma = 9.766e-04

        self.current_faces = []
        self.enrolling = None
        self.enroll_count = 0
        self.enroll_max = 32
        self.enroll_list = []

        self.previous_time = time.time()

        self.arialblack24 = PIL.ImageFont.truetype(ARIAL_BLACK_NAME, 24)

        # ---------------- Basic Data -------------------
        try:
            self.webcam = Webcam()
        except SystemExit:
            raise
        except:
            trace = traceback.format_exc()
            message = TraceBackDialog(None, "Camera Error", CAMERA_ERROR,
                                      trace)
            message.ShowModal()

            sys.stderr.write(
                "FaceL Error: an error occurred while trying to connect to the camera.  Details follow.\n\n"
            )
            sys.stderr.write(trace)
            sys.exit(CAMERA_ERROR_CODE)

        # ------------- Other Components ----------------
        self.CreateStatusBar()

        # ------------------- Menu ----------------------
        # Creating the menubar.

        # Menu IDs
        license_id = wx.NewId()

        mirror_id = wx.NewId()
        face_id = wx.NewId()
        svm_tune_id = wx.NewId()
        performance_id = wx.NewId()

        # Menu Items
        self.file_menu = wx.Menu()

        self.file_menu.Append(wx.ID_ABOUT, "&About...")
        self.file_menu.Append(license_id, "FaceL License...")
        self.file_menu.AppendSeparator()
        self.file_menu.Append(wx.ID_EXIT, "E&xit")

        self.options_menu = wx.Menu()
        self.face_menuitem = self.options_menu.AppendCheckItem(
            face_id, "Face Processing")
        self.eye_menuitem = self.options_menu.AppendCheckItem(
            face_id, "Eye Detection")
        self.mirror_menuitem = self.options_menu.AppendCheckItem(
            mirror_id, "Mirror Video")
        self.options_menu.AppendSeparator()
        self.options_menu.Append(svm_tune_id, "SVM Tuning...")
        self.options_menu.Append(performance_id, "Performance...")

        # Create Menu Bar
        self.menu_bar = wx.MenuBar()
        self.menu_bar.Append(self.file_menu, "&File")
        self.menu_bar.Append(self.options_menu, "&Options")

        self.SetMenuBar(self.menu_bar)

        # Menu Events
        wx.EVT_MENU(self, wx.ID_ABOUT, self.onAbout)
        wx.EVT_MENU(self, license_id, self.onLicense)

        wx.EVT_MENU(self, mirror_id, self.onNull)
        wx.EVT_MENU(self, face_id, self.onNull)
        wx.EVT_MENU(self, svm_tune_id, self.onSVMTune)
        wx.EVT_MENU(self, performance_id, self.onTiming)

        # Set up menu checks
        self.face_menuitem.Check(True)
        self.eye_menuitem.Check(True)
        self.mirror_menuitem.Check(True)

        # ----------------- Image List ------------------

        # --------------- Image Display -----------------
        self.static_bitmap = wx.StaticBitmap(self,
                                             wx.NewId(),
                                             bitmap=wx.EmptyBitmap(640, 480))

        self.controls_box = wx.StaticBox(self, wx.NewId(), "Controls")

        self.facel_logo = wx.StaticBitmap(self,
                                          wx.NewId(),
                                          bitmap=wx.Bitmap(FACEL_LOGO))
        self.csu_logo = wx.StaticBitmap(self,
                                        wx.NewId(),
                                        bitmap=wx.Bitmap(CSU_LOGO))
        #        self.performance_box = wx.StaticBox(self, wx.NewId(), "Performance")

        self.enroll_chioce_label = wx.StaticText(self,
                                                 wx.NewId(),
                                                 "Enrollment Count:",
                                                 style=wx.ALIGN_LEFT)
        self.enroll_choice = wx.Choice(self, wx.NewId(), wx.Point(0, 0),
                                       wx.Size(-1, -1),
                                       ['16', '32', '48', '64', '128', '256'])
        self.enroll_choice.Select(3)

        self.train_button = wx.Button(self, wx.NewId(), 'Train Labeler')
        self.reset_button = wx.Button(self, wx.NewId(), 'Clear Labels')

        # --------------- Instrumentation ---------------

        self.enroll_label = wx.StaticText(
            self,
            wx.NewId(),
            "Click a face in the video to enroll.",
            style=wx.ALIGN_LEFT)

        self.ids_label = wx.StaticText(self,
                                       wx.NewId(),
                                       "Labels:",
                                       size=wx.Size(-1, 16),
                                       style=wx.ALIGN_LEFT)
        self.ids_text = wx.StaticText(self,
                                      wx.NewId(),
                                      size=wx.Size(30, 16),
                                      style=wx.ALIGN_RIGHT)

        self.faces_label = wx.StaticText(self,
                                         wx.NewId(),
                                         "Faces:",
                                         size=wx.Size(-1, 16),
                                         style=wx.ALIGN_LEFT)
        self.faces_text = wx.StaticText(self,
                                        wx.NewId(),
                                        size=wx.Size(30, 16),
                                        style=wx.ALIGN_RIGHT)

        # --------------- Window Layout -----------------
        enroll_sizer = wx.BoxSizer(wx.HORIZONTAL)
        enroll_sizer.Add(self.ids_label,
                         flag=wx.ALIGN_CENTER | wx.ALL,
                         border=4)
        enroll_sizer.Add(self.ids_text,
                         flag=wx.ALIGN_CENTER | wx.ALL,
                         border=4)
        enroll_sizer.AddSpacer(20)
        enroll_sizer.Add(self.faces_label,
                         flag=wx.ALIGN_CENTER | wx.ALL,
                         border=4)
        enroll_sizer.Add(self.faces_text,
                         flag=wx.ALIGN_CENTER | wx.ALL,
                         border=4)

        training_sizer = wx.BoxSizer(wx.HORIZONTAL)
        training_sizer.Add(self.train_button,
                           flag=wx.ALIGN_CENTER | wx.ALL,
                           border=4)
        training_sizer.Add(self.reset_button,
                           flag=wx.ALIGN_CENTER | wx.ALL,
                           border=4)

        enroll_choice_sizer = wx.BoxSizer(wx.HORIZONTAL)
        enroll_choice_sizer.Add(self.enroll_chioce_label,
                                flag=wx.ALIGN_CENTER | wx.ALL,
                                border=0)
        enroll_choice_sizer.Add(self.enroll_choice,
                                flag=wx.ALIGN_CENTER | wx.ALL,
                                border=0)

        controls_sizer = wx.StaticBoxSizer(
            self.controls_box, wx.VERTICAL)  #wx.BoxSizer(wx.VERTICAL)
        controls_sizer.Add(self.enroll_label,
                           flag=wx.ALIGN_LEFT | wx.ALL,
                           border=0)
        controls_sizer.Add(enroll_sizer, flag=wx.ALIGN_LEFT | wx.ALL, border=0)
        controls_sizer.Add(enroll_choice_sizer,
                           flag=wx.ALIGN_LEFT | wx.ALL,
                           border=4)
        controls_sizer.Add(training_sizer,
                           flag=wx.ALIGN_LEFT | wx.ALL,
                           border=0)

        bottom_sizer = wx.BoxSizer(wx.HORIZONTAL)
        bottom_sizer.Add(self.facel_logo,
                         flag=wx.ALIGN_CENTER | wx.ALL,
                         border=0)
        bottom_sizer.Add(controls_sizer, flag=wx.ALIGN_TOP | wx.ALL, border=4)
        bottom_sizer.Add(self.csu_logo,
                         flag=wx.ALIGN_CENTER | wx.ALL,
                         border=0)

        main_sizer = wx.BoxSizer(wx.VERTICAL)
        main_sizer.Add(self.static_bitmap,
                       flag=wx.ALIGN_CENTER | wx.ALL,
                       border=0)
        main_sizer.Add(bottom_sizer, flag=wx.ALIGN_CENTER | wx.ALL, border=4)

        self.SetAutoLayout(True)
        self.SetSizer(main_sizer)
        self.Layout()

        # -----------------------------------------------
        self.timer = FrameTimer(self)
        self.timer.Start(200)

        # -------------- Event Handleing ----------------
        wx.EVT_SIZE(self.static_bitmap, self.onBitmapResize)
        wx.EVT_LEFT_DOWN(self.static_bitmap, self.onClick)

        self.Bind(wx.EVT_BUTTON, self.onTrain, id=self.train_button.GetId())
        self.Bind(wx.EVT_BUTTON, self.onReset, id=self.reset_button.GetId())

        # --------------- Setup State -------------------
        self.setupState()

    def onTrain(self, event=None):
        '''
        Start the SVM training process.
        '''
        print "Train"
        #progress = wx.ProgressDialog(title="SVM Training", message="Training the Face Recognition Algorithm. Please Wait...")
        if self.svm_mode == SVM_AUTOMATIC:
            # Train with automatic tuning.
            self.face_rec.train()  #callback=progress.Update)
            self.svm_C = self.face_rec.svm.C
            self.svm_Gamma = self.face_rec.svm.gamma
        else:
            # Train with manual tuning.
            self.face_rec.train(C=[self.svm_C],
                                Gamma=[self.svm_Gamma
                                       ])  # ,callback=progress.Update)

        #progress.Destroy()

    def onReset(self, event=None):
        '''
        Clear the enrollment data for the SVM.
        '''
        self.face_rec.reset()
        self.setupState()

    def onFrame(self, event=None):
        '''
        Retrieve and process a video frame.
        '''
        self.timer.Stop()
        starttime = time.time()
        self.detect_time = 0.0
        self.eye_time = 0.0
        self.label_time = 0.0
        img = self.webcam.query()

        face_processing = self.face_menuitem.IsChecked()
        eye_processing = self.eye_menuitem.IsChecked()

        names = []

        if face_processing:
            faces = self.findFaces(img)
            if self.enrolling != None:
                success = None
                for rect, leye, reye in faces:
                    img.annotateRect(self.enrolling, color='yellow')
                    if (success == None) and is_success(self.enrolling, rect):
                        success = rect
                        img.annotateRect(rect, color='blue')
                        if eye_processing:
                            img.annotatePoint(leye, color='blue')
                            img.annotatePoint(reye, color='blue')
                        self.enroll_list.append([img, rect, leye, reye])

                    else:
                        img.annotateRect(rect, color='red')
                        if eye_processing:
                            img.annotatePoint(leye, color='red')
                            img.annotatePoint(reye, color='red')
                        img.annotateLine(pv.Point(rect.x, rect.y),
                                         pv.Point(rect.x + rect.w,
                                                  rect.y + rect.h),
                                         color='red')
                        img.annotateLine(pv.Point(rect.x + rect.w, rect.y),
                                         pv.Point(rect.x, rect.y + rect.h),
                                         color='red')

                if success == None:
                    rect = self.enrolling
                    img.annotateLine(pv.Point(rect.x, rect.y),
                                     pv.Point(rect.x + rect.w,
                                              rect.y + rect.h),
                                     color='yellow')
                    img.annotateLine(pv.Point(rect.x + rect.w, rect.y),
                                     pv.Point(rect.x, rect.y + rect.h),
                                     color='yellow')
                else:
                    #enroll in the identification algorithm
                    pass
            else:
                for rect, leye, reye in faces:
                    img.annotateRect(rect, color='blue')
                    if eye_processing:
                        img.annotatePoint(leye, color='blue')
                        img.annotatePoint(reye, color='blue')

            if self.face_rec.isTrained():
                self.label_time = time.time()
                for rect, leye, reye in faces:
                    label = self.face_rec.predict(img, leye, reye)
                    names.append([0.5 * (leye + reye), label])
                self.label_time = time.time() - self.label_time

        # Displaying Annotated Frame
        im = img.asAnnotated()
        if self.mirror_menuitem.IsChecked():
            im = im.transpose(FLIP_LEFT_RIGHT)

        if self.enrolling != None:
            draw = PIL.ImageDraw.Draw(im)
            x, y = self.enrolling.x, self.enrolling.y
            if self.mirror_menuitem.IsChecked():
                x = 640 - (x + self.enrolling.w)
            self.enroll_count += 1
            draw.text(
                (x + 10, y + 10),
                "Enrolling: %2d of %2d" % (self.enroll_count, self.enroll_max),
                fill='yellow',
                font=self.arialblack24)
            del draw

            if self.enroll_count >= self.enroll_max:
                print "Count:", self.enroll_count

                if len(self.enroll_list) == 0:
                    warning_dialog = wx.MessageDialog(
                        self,
                        "No faces were detected during the enrollment process.  Please face towards the camera and keep your face in the yellow rectangle during enrollment.",
                        style=wx.ICON_EXCLAMATION | wx.OK,
                        caption="Enrollment Error")
                    warning_dialog.ShowModal()
                else:
                    name_dialog = wx.TextEntryDialog(
                        self,
                        "Please enter a name to associate with the face. (%d faces captured)"
                        % len(self.enroll_list),
                        caption="Enrollment ID")
                    result = name_dialog.ShowModal()
                    sub_id = name_dialog.GetValue()
                    if result == wx.ID_OK:
                        if sub_id == "":
                            print "Warning: Empty Subject ID"
                            warning_dialog = wx.MessageDialog(
                                self,
                                "A name was entered in the previous dialog so this face will not be enrolled in the database.  Please repeat the enrollment process for this person.",
                                style=wx.ICON_EXCLAMATION | wx.OK,
                                caption="Enrollment Error")
                            warning_dialog.ShowModal()
                        else:
                            for data, rect, leye, reye in self.enroll_list:
                                self.face_rec.addTraining(
                                    data, leye, reye, sub_id)
                                self.setupState()

                self.enroll_count = 0
                self.enrolling = None
                self.enroll_list = []

        if len(names) > 0:
            draw = PIL.ImageDraw.Draw(im)
            for pt, name in names:
                x, y = pt.X(), pt.Y()
                w, h = draw.textsize(name, font=self.arialblack24)
                if self.mirror_menuitem.IsChecked():
                    x = 640 - x - 0.5 * w
                else:
                    x = x - 0.5 * w
                draw.text((x, y - 20 - h),
                          name,
                          fill='green',
                          font=self.arialblack24)
            del draw

        wxImg = wx.EmptyImage(im.size[0], im.size[1])
        wxImg.SetData(im.tostring())
        bm = wxImg.ConvertToBitmap()

        self.static_bitmap.SetBitmap(bm)

        # Update timing gauges
        full_time = time.time() - starttime
        if self.timing_window != None:
            self.timing_window.update(self.detect_time, self.eye_time,
                                      self.label_time, full_time)

        self.ids_text.SetLabel("%d" % (self.face_rec.n_labels, ))
        self.faces_text.SetLabel("%d" % (self.face_rec.n_faces, ))

        sleep_time = 1
        if sys.platform.startswith("linux"):
            sleep_time = 10
        # TODO: For macosx milliseconds should be 1
        # TODO: For linux milliseconds may need to be set to a higher value 10
        self.timer.Start(milliseconds=sleep_time, oneShot=1)

    def setupState(self):
        #print "state",self.face_rec.n_labels,self.IsEnabled()
        if self.face_rec.n_labels >= 2:
            self.train_button.Enable()
        else:
            self.train_button.Disable()

    def onBitmapResize(self, event):
        w = event.GetSize().GetWidth()
        h = event.GetSize().GetHeight()

        self.static_bitmap.SetSize(event.GetSize())

    def onClick(self, event):
        '''
        Process a click in the Video window which starts the enrollment process.
        '''
        x = event.GetX()
        y = event.GetY()

        if self.mirror_menuitem.IsChecked():
            x = 640 - x

        for rect, leye, reye in self.current_faces:
            if rect.containsPoint(pv.Point(x, y)):
                self.enrolling = rect
                self.enroll_count = 0
                self.enroll_max = int(self.enroll_choice.GetStringSelection())

    def findFaces(self, im):
        eye_processing = self.eye_menuitem.IsChecked()

        self.detect_time = time.time()
        rects = self.face_detector.detect(im)
        self.detect_time = time.time() - self.detect_time

        self.eye_time = time.time()
        if eye_processing:
            faces = self.fel.locateEyes(im, rects)
        else:
            faces = []
            for rect in rects:
                affine = pv.AffineFromRect(rect, (1, 1))
                leye = affine.invertPoint(AVE_LEFT_EYE)
                reye = affine.invertPoint(AVE_RIGHT_EYE)
                faces.append([rect, leye, reye])

        self.eye_time = time.time() - self.eye_time

        self.current_faces = faces

        return faces

    def onAbout(self, event):
        wx.MessageBox(ABOUT_MESSAGE, "About FaceL",
                      wx.OK | wx.ICON_INFORMATION)

    def onLicense(self, event):
        wx.MessageBox(LICENSE_MESSAGE, "FaceL License",
                      wx.OK | wx.ICON_INFORMATION)

    def onNull(self, *args, **kwargs):
        pass

    def onSVMTune(self, event):
        dialog = SVMTuningDialog(self, self.svm_mode, self.svm_C,
                                 self.svm_Gamma)
        dialog.CenterOnParent()

        result = dialog.ShowModal()
        if result == wx.ID_OK:
            self.svm_mode = dialog.mode
            self.svm_C = dialog.C
            self.svm_Gamma = dialog.Gamma

        print "SVM Tuning Info <MODE:%s; C:%0.2e; Gamma:%0.2e>" % (
            self.svm_mode, self.svm_C, self.svm_Gamma)

        dialog.Destroy()

    def onTiming(self, event):
        if self.timing_window == None:
            self.timing_window = TimingWindow(self, wx.NewId(), "Performance")
            self.timing_window.CenterOnParent()
            self.timing_window.Show(True)
            self.timing_window.Bind(wx.EVT_CLOSE,
                                    self.onCloseTiming,
                                    id=self.timing_window.GetId())

        else:
            self.timing_window.Show(True)
            self.timing_window.Raise()

    def onCloseTiming(self, event):
        self.timing_window.Destroy()
        self.timing_window = None