Пример #1
0
class Face_App:

    # 初始化函数
    def __init__(self):
        self.face_tools = ft()
        self.vs = VideoStream(0)
        self.vs.run()
        self.frame = None
        self.thread = None
        self.guanliyuan_accept_login = True
        self.run_manage = False
        self.change_list = self.vs.get_sources()
        self.source_number = 0
        self.update_label_flag = True

        # 主界面
        self.root = tk.Tk()
        self.root.wm_resizable(False, False)  # 使窗口尺寸不变
        self.root.wm_title("基于机器视觉的人脸识别系统")
        self.root.wm_protocol("WM_DELETE_WINDOW", self.close)

        # 人脸画面
        self.face_image = tk.Label()
        self.face_image.pack(side="top", padx=10, pady=10)

        # 添加人脸按钮相关
        self.add_button_var = tk.StringVar()
        self.add_button_var.set("添加人脸")
        self.press_add = False
        self.add_button = tk.Button(self.root,
                                    textvariable=self.add_button_var,
                                    command=self.add)

        # 切换源按钮相关
        self.is_vedio_source = True
        self.change_source_var = tk.StringVar()
        self.change_source_var.set("切换图像")
        self.press_change_source = False
        self.change_source_button = tk.Button(
            self.root,
            textvariable=self.change_source_var,
            command=self.change_source)

        # 人脸识别按钮相关
        self.recognize_button_var = tk.StringVar()
        self.recognize_button_var.set("人脸识别")
        self.press_recognize = False
        self.recognize_button = tk.Button(
            self.root,
            textvariable=self.recognize_button_var,
            command=self.recognize)
        self.max_face = []

        # 人脸检测按钮相关
        self.detect_button_var = tk.StringVar()
        self.detect_button_var.set("人脸检测")
        self.press_detect = False
        self.detect_button = tk.Button(self.root,
                                       textvariable=self.detect_button_var,
                                       command=self.detect)

        # 姓名编号输入界面
        self.frame_h = tk.Frame(self.root)
        self.frame_l = tk.Frame(self.root)
        self.name_label = tk.Label(self.frame_h, text="姓名:")
        self.id_label = tk.Label(self.frame_l, text="编号:")
        self.name_entry = tk.Entry(self.frame_h)
        self.id_entry = tk.Entry(self.frame_l)
        self.ok_button = tk.Button(self.root,
                                   text="确认",
                                   width=20,
                                   command=self.save_id)

        # 是我按钮
        self.is_me_var = tk.StringVar()
        self.is_me_var.set("是我")
        self.is_me_button = tk.Button(self.root,
                                      textvariable=self.is_me_var,
                                      command=self.is_me)
        self.press_is_me_button = False

        # 不是我按钮
        self.not_me_button = tk.Button(self.root,
                                       text="不是我",
                                       command=self.not_me)
        self.press_not_me_button = False

        # 线程相关
        self.run_thread = True
        self.thread = threading.Thread(target=self.video_loop)
        self.thread.start()
        self.last_img = None
        self.last_max_face = [0, 0, 0, 0]
        self.pack_all_button()
        self.root.mainloop()

    # 视频循环流
    def video_loop(self):
        try:
            print("启动画面")
            while self.run_thread:
                if self.press_change_source:
                    self.change_sources()
                    self.press_change_source = False
                self.grabbed, self.frame = self.vs.read()
                if self.grabbed:
                    self.update_img(self.frame)
                elif self.run_thread == True:
                    self.change_sources()
                else:
                    break
        except RuntimeError:
            print("视频流出现异常")

    # 根据用户所选功能能的不同,将每一帧画面进行不同处理
    def update_img(self, img):
        if self.press_recognize:
            user_id, new_img = self.face_tools.face_recognize(img)
            self.update_label(new_img)
            if user_id == '1' and self.guanliyuan_accept_login == True and self.is_vedio_source == True and self.press_recognize and self.source_number == 0:
                if tk.messagebox.askokcancel(message="你好像是管理员,你要登录吗?"):
                    self.guanliyuan_accept_login = True
                    self.run_manage = True
                    self.run_thread = False
                    tk.messagebox.showinfo(message="请关闭本页面在终端进行操作。")
                else:
                    self.guanliyuan_accept_login = False
        elif self.press_detect:
            new_img = self.face_tools.face_detection(img)
            self.update_label(new_img)
        elif self.press_add:
            if self.update_label_flag:
                new_img, self.max_face = self.face_tools.face_collect(img)
                self.update_label(new_img)
            if self.max_face[2] > 10:
                self.vs.stop()
                self.update_label_flag = False
            if self.press_is_me_button:
                self.press_is_me_button = False
                self.update_label_flag = True
                self.face_tools.face_save(img, self.max_face)
                self.is_me_var.set("是我" + " (" + str(self.face_tools.number) +
                                   ")")
                self.vs.go_on()
            elif self.press_not_me_button:
                self.update_label_flag = True
                self.press_not_me_button = False
                self.vs.go_on()
        else:
            self.update_label(img)

    # 更新显示画面
    def update_label(self, new_img):
        cv2image = cv2.cvtColor(new_img, cv2.COLOR_BGR2RGBA)  # 转换颜色从BGR到RGBA
        current_image = Image.fromarray(cv2image)  # 将图像转换成Image对象
        imgtk = ImageTk.PhotoImage(image=current_image)
        if imgtk == None:
            tk.messagebox.showerror(message="更新画面出现异常请关闭程序。")
            return
        if self.face_image is None:
            self.face_image = tk.Label(image=imgtk)
            self.face_image.image = imgtk
            self.face_image.pack(side="top", padx=10, pady=10)
        else:
            if self.run_thread == False:
                return
            self.face_image.configure(image=imgtk)
            self.face_image.image = imgtk

    # 人脸识别按钮对应程序
    def recognize(self):
        if self.press_recognize == False:
            is_recognize = tk.messagebox.askokcancel(title='',
                                                     message="确定要开始识别吗?")
            if is_recognize:
                self.press_recognize = True
                self.destroy_all_button()
                self.recognize_button_var.set("取消识别")
                self.recognize_button.pack(fill="both",
                                           expand="yes",
                                           padx=200,
                                           pady=10)
                print("识别")
        else:
            is_cancel_recognize = tk.messagebox.askokcancel(
                title='', message="确定要取消识别吗?")
            if is_cancel_recognize:
                print('\n' + str(self.face_tools.predict_dict) + '\n')
                self.face_tools.predict_dict = {}
                self.face_tools.predict_number = 0
                self.press_recognize = False
                self.guanliyuan_accept_login = True
                self.destroy_all_button()
                self.recognize_button_var.set("人脸识别")
                self.pack_all_button()
                print("取消识别")

    # 人脸检测按钮对应程序
    def detect(self):

        if self.press_detect == False:
            is_detect = tk.messagebox.askokcancel(
                title='', message="确定要开始检测吗?")  # return True 0r False
            if is_detect:
                self.press_detect = True
                self.destroy_all_button()
                self.detect_button_var.set("取消检测")
                self.detect_button.pack(fill="both",
                                        expand="yes",
                                        padx=200,
                                        pady=10)
                print("人脸检测")
        else:
            is_cancel_detect = tk.messagebox.askokcancel(
                title='', message="确定要取消检测吗?")  # return True 0r False
            if is_cancel_detect:
                self.press_detect = False
                self.detect_button_var.set("人脸检测")
                self.destroy_all_button()
                self.pack_all_button()
                print("取消检测")

    # 添加人脸/停止添加按钮对应程序
    def add(self):
        if self.press_add == False:
            is_add = tk.messagebox.askokcancel(
                title='', message="确定要添加人脸吗?")  # return True 0r False
            if is_add:
                self.press_add = True
                self.destroy_all_button()
                self.add_button_var.set("停止添加")
                self.get_name_id()
                print("人脸识别")
        else:
            is_cancel_add = tk.messagebox.askokcancel(
                title='', message="确定要停止添加吗?")  # return True 0r False
            if is_cancel_add:
                self.face_tools.number = 0
                self.is_me_var.set("是我")
                self.update_label_flag = True
                self.press_add = False
                self.destroy_all_button()
                self.add_button_var.set("添加人脸")
                self.pack_all_button()
                self.face_tools.face_train()
                tk.messagebox.showinfo(message="已添加新的人脸,正在重新训练模型!")
                self.vs.go_on()
                print("添加完成")

    # 切换视频源
    def change_source(self):
        if self.press_change_source == False:
            self.press_change_source = True

    # 是我按钮对应程序
    def is_me(self):
        self.press_not_me_button = False
        self.press_is_me_button = True

    # 不是我按钮对应程序
    def not_me(self):
        self.press_not_me_button = True
        self.press_is_me_button = False

    # 得到姓名及编号
    def get_name_id(self):
        self.frame_h.pack()
        self.frame_l.pack()
        self.name_label.pack(side="left", fill="both", padx=5, pady=5)
        self.name_entry.pack(side="right", fill="both", padx=5, pady=5)
        self.id_label.pack(side="left", fill="both", padx=5, pady=5)
        self.id_entry.pack(side="right", fill="both", padx=5, pady=5)
        self.ok_button.pack(side="bottom", fill="y", ipadx=5, pady=5)

    # 保存id
    def save_id(self):
        get_name = self.name_entry.get()
        get_id = self.id_entry.get()
        if get_id != "" and get_name != "" and len(get_id) <= 6 and len(
                get_name) <= 20:
            if get_id.isdigit():
                if get_id in self.face_tools.usrs_dict.keys():
                    tk.messagebox.showinfo(
                        message="此id已使用,如果你再使用会影响之前用户!\n请联系管理员操作。")
                    meaage = "有一个名为%s的用户想使用已被使用编号%s被拒绝。" % (get_name, get_id)
                    self.face_tools.sent_message("有人要有已有编号", meaage)
                    return
                self.face_tools.usrs_dict[str(int(get_id))] = get_name
                self.face_tools.save_dict()
                meaage = "有一个名为%s,编号为%s的用户录入了人脸信息。" % (get_name, get_id)
                self.face_tools.sent_message("有新人脸添加", meaage)
                self.face_tools.face_id = get_id
                print("已经保存了您的姓名和编号")
                print(self.face_tools.usrs_dict)
                self.destroy_all_button()
                self.press_not_me_button = True
                self.is_me_button.pack(side="left",
                                       fill="both",
                                       expand="yes",
                                       padx=5,
                                       pady=5)
                self.not_me_button.pack(side="left",
                                        fill="both",
                                        expand="yes",
                                        padx=5,
                                        pady=5)
                self.add_button.pack(side="right",
                                     fill="both",
                                     expand="yes",
                                     padx=5,
                                     pady=5)
            else:
                tk.messagebox.showinfo(message="编号只能为数字哦!")
        else:
            tk.messagebox.showinfo(message="姓名和编号都不能为空且符合字数要求哦!")

    # 切换视频源
    def change_sources(self):
        self.source_number += 1
        if self.source_number == len(self.change_list):
            self.source_number = 0
        self.vs.close()
        self.vs = VideoStream(self.change_list[self.source_number])
        self.vs.run()

    # 放置初始四大按钮
    def pack_all_button(self):
        self.add_button.pack(side="right",
                             fill="both",
                             expand="yes",
                             padx=10,
                             pady=10)
        self.detect_button.pack(side="right",
                                fill="both",
                                expand="yes",
                                padx=10,
                                pady=10)
        self.recognize_button.pack(side="right",
                                   fill="both",
                                   expand="yes",
                                   padx=10,
                                   pady=10)
        self.change_source_button.pack(side="right",
                                       fill="both",
                                       expand="yes",
                                       padx=10,
                                       pady=10)

    # 删除所有按钮
    def destroy_all_button(self):
        self.recognize_button.pack_forget()
        self.add_button.pack_forget()
        self.detect_button.pack_forget()
        self.frame_h.pack_forget()
        self.frame_l.pack_forget()
        self.name_label.pack_forget()
        self.name_entry.pack_forget()
        self.id_label.pack_forget()
        self.id_entry.pack_forget()
        self.ok_button.pack_forget()
        self.is_me_button.pack_forget()
        self.not_me_button.pack_forget()
        self.change_source_button.pack_forget()

    # 关闭vedio_loop线程
    def close(self):
        if self.run_manage:
            self.vs.close()
            self.root.destroy()
            print("关闭窗口")
            return
        self.run_thread = False
        is_quit = tk.messagebox.askyesno(title='请求确认', message="确定退出了吗?")
        if is_quit:
            self.vs.close()
            self.root.destroy()
        else:
            self.run_thread = True
            self.thread = threading.Thread(target=self.video_loop)
            self.thread.start()