def show_from_opt_command(self, *args): """ Show file dialog or turn on the camera. """ show_from = self.get_dict_key_by_value( self.show_from_opt_dict, self.show_from_opt_stringvar.get()) if show_from == "file": self.face_src_path = tkf.askopenfilename( title=_("Select a file"), filetypes=[(_("Image or video"), self.var_img_vid_exts)], initialdir="~", ) if len(self.face_src_path) < 1: return ext = os.path.splitext(self.face_src_path)[1][1:] self.show_from_opt_stringvar.set(self.face_src_path) if ext in self.var_image_exts: self.view_image() elif ext in self.var_video_exts: self.source = self.face_src_path self.play_video() elif show_from == "camera": self.source = 0 self.show_from_opt_stringvar.set(self.source) self.play_video()
def get_saved_info_combobox_values(self): basic_infos = self.get_basic_infos() if basic_infos is None: return [] combobox_values = [info + "(" + _id + ")" for _id, info in basic_infos] combobox_values += [_("New information") + "(" + _("_Add") + ")"] return combobox_values
def open_src(self, *args): """ Entry source and open it. """ go_combobox_var = self.go_combobox.get() if len(go_combobox_var.strip()) < 1: return self.rec_img = False self.cancel_root_after() show_from_ext = go_combobox_var.split(".")[-1] if show_from_ext in self.var_video_exts: self.source = go_combobox_var self.play_video() return elif re.match(r"\d+", go_combobox_var): self.source = int(go_combobox_var) self.play_video() return elif show_from_ext in self.var_image_exts: self.view_image() return elif go_combobox_var == _("File"): self.show_from_file() return elif go_combobox_var == _("Camera"): self.show_from_camera() return self.go_combobox.current(1) self.show_nsrc_error()
def update_frame_labels_for_recog(self, frames=None): frames = frames or self.get_picked_frames_from_frame() if frames is not None: for f in frames: label = ttk.Label(self.pick_scrolledframe_innerframe) self.set_label_image(f, label) index = self.get_picked_frame_labels_for_recog_len() label.bind( "<Button-1>", lambda event, index=index: self.recog_frame_by_index(index ), ) label.pack( side="left", anchor="nw", padx=self.picked_frame_label_margin / 2, ) simpletooltip.create(label, _("Click to recognize.")) self.add_picked_frame_label_for_recog(label) self.set_picked_frames_without_update_widgets(frames) else: self.set_msg(_("Nothing picked.")) if self.is_test(): print(_("Picked frame is None.")) pass
def set_frame_labels_image_use_saved_frames(self, frames=None, for_read=False): if for_read: if not self.is_action_read(): print("`NOT` is_action_read.") return saved_frames = frames or self.get_saved_frames() if saved_frames is None: if self.is_test(): print(self.get_info_id(), _("Saved frames is None.")) return if self.is_test(): print("saved_frames_len", len(saved_frames)) for _id, f in saved_frames: if self.is_test(): print("`saved_frame.id`", _id) label = ttk.Label(self.pick_scrolledframe_innerframe) self.set_label_image(f, label) label.bind( "<Button-1>", lambda event, _id=_id: self.del_saved_frame_by_id(_id), ) label.pack( side="left", anchor="nw", padx=self.frame_label_margin / 2, ) simpletooltip.create(label, _("Saved frame, Click to delete.")) self.saved_frame_labels.append(label) pass
def run(test=False): if test: print(_("Hello, Welcome to Funing!")) print(_("Version: %s") % (app_version)) from funing.widgets import show show(test)
def recognizer_train(self): self.set_status_msg(_("Recognizer training. . .")) images, labels, self.info_ids = self.load_images() if len(labels) < 1: self.show_data_empty() return recognizer.train(images, labels) self.set_status_msg(_("Recognizer finish training."))
def set_widgets(self): self.menubar = Menu(self.root) self.root.config(menu=self.menubar) self.about_menu = Menu(self.menubar, tearoff=False) self.about_menu.add_command(label=_("About Funing"), command=self.about_command) self.menubar.add_cascade(label=_("About"), menu=self.about_menu)
def go_combobox_selected(self, args): go_combobox_var = self.go_combobox.get() if len(go_combobox_var.strip()) < 1: return self.rec_img = False self.cancel_root_after() if go_combobox_var == _("File"): self.show_from_file() return elif go_combobox_var == _("Camera"): self.show_from_camera() return
def show_info(self, label, index, cur_info_id): if (self.zoomed_in_face_label[0] != 0) and (self.zoomed_in_face_label[0] != label): self.restore_face_label_size_rec(index) frame = self.showed_face_frames[index] frame = cv2.resize(frame, self.zoom_in_size) vid_img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) vid_img = Image.fromarray(vid_img) imgtk = ImageTk.PhotoImage(image=vid_img) label.imgtk = imgtk label.configure(image=imgtk) self.zoomed_in_face_label = (label, index) info_file_path = self.get_info_file_path(cur_info_id) self.info_text.delete(1.0, END) if not os.path.exists(info_file_path): _nif_ = _("No informations found") self.info_text.insert("1.0", _nif_) self.set_status_msg(_nif_) with open(info_file_path, "r") as f: self.info_text.insert("1.0", f.read())
def set_labels_image_by_frames_return_labels(self, frames=None, parent_widget=None, label_func=None): assert frames is not None label_func = label_func or ( lambda: print("`set_labels_image_by_frames.label_func` is None.")) parent_widget = parent_widget or self.pick_scrolledframe_innerframe index = 0 labels = [] for f in frames: label = ttk.Label(parent_widget) self.set_label_image(f, label) label.bind( "<Button-1>", lambda event, _index=index: label_func(_index), ) label.pack( side="left", anchor="nw", padx=self.frame_label_margin / 2, ) simpletooltip.create(label, _("Saved frame, Click to delete.")) labels.append(label) return labels
def save(self): if self.cur_info_id is None: return if self.face_frame is None: self.set_msg(_("No face picture picked")) return data_dir_path = os.path.join(data_path, self.cur_info_id) os.makedirs(data_dir_path, exist_ok=True) info = self.info_text.get("1.0", "end-1c") info_file_path = self.get_info_file_path(self.cur_info_id) with open(info_file_path, "w+") as f: f.write(info) img_num = len(os.listdir(data_dir_path)) for f in self.added_face_frames: if f is None or len(f) < 1: return cv2.imwrite(f"{data_dir_path}/{str(uuid.uuid4())}.jpg", f) self.cancel_master_after() self.get_name_data() self.show_data(self.cur_info_id)
def __init__(self, master=None): if master is None: master = tk.Toplevel() master.title(_("Funing Data")) # data self.id_name_dict = {} self.data_ids = os.listdir(data_path) self.cur_name = "" self.cur_face_labels = [] self.name_btns = [] self.cur_page_num = 0 self.cur_p_item_count = 10 self.source = 0 self.cur_info_id = None # widgets self.add_face_label = None # page self.d_item_count = len(self.data_ids) # vid self.vid = None self.vid_fps = 30 self.save_size = (100, 100) self.master_after = -1 self.face_frame = 0 # default: add new face label self.added_face_frames = [] super().__init__(master)
def delete_button_command(self): if not self.is_action_read(): if self.is_test(): print(_("ACTION isn't 'READ'.")) return self.del_saved_info_by_info_id() pass
def show_from_file(self): self.face_src_path = tkf.askopenfilename( title=_("Select a file"), filetypes=[(_("Image or video"), self.var_img_vid_exts)], initialdir="~", ) if len(self.face_src_path) < 1: return ext = os.path.splitext(self.face_src_path)[1][1:] self.go_combobox.set(self.face_src_path) if ext in self.var_image_exts: self.view_image() elif ext in self.var_video_exts: self.source = self.face_src_path self.play_video()
def cancel_master_after(self): if self.master_after != -1: self.master.after_cancel(self.master_after) self.vid.release() self.master_after = -1 self.vid = None if self.face_frame is None: self.set_msg(_("No face picture picked"))
def save_information( self, info_id=None, save_basic_info=True, save_info=True, save_image=True, refresh=True, update_widgets=True, ): if not self.is_action_read() and len(self.picked_frames) < 1: self.set_msg(_("Nothing picked.")) return basic_info_entry_get = self.get_basic_info_entry_content() info_text_get = self.get_info_text_content() info_id = info_id or self.get_info_id() or str(uuid.uuid4()) if not self.get_info_id(): self.set_info_id(_id=info_id) if save_basic_info: with open(get_basic_info_path(info_id), "w") as f: f.write(basic_info_entry_get) if save_info: with open(get_info_path(info_id), "w") as f: f.write(info_text_get) if save_image: for f in self.picked_frames: cv2.imwrite(get_new_random_face_image_path(info_id), f) if refresh: self.set_info_ids(refresh=True) self.update_saved_info_combobox_values() if update_widgets: self.set_action_to_read() # First `read` after adding. self.set_picked_frames(to_none=True) self.clear_picked_frame_labels() self.clear_saved_frame_labels() self.set_saved_info_combobox_content_by_info_id(info_id) self.update_widgets_by_info_id() pass self.set_msg(_("Information saved.")) pass
def add_face_pic(self): if self.master_after == -1: if self.face_frame is not None: # default value of self.face_frame is 0. if (not isinstance(self.face_frame, int) and self.face_frame is not None): self.added_face_frames.append(self.face_frame) new_face_label = tk.Label(self.face_pic_frame) added_face_frames_len = len(self.added_face_frames) menu = Menu(self.master, tearoff=0) menu.add_command( label=_("delete"), command=(lambda label=new_face_label, index= added_face_frames_len: self.del_face_pic_new( new_face_label, index)), ) menu.add_command( label=_("pick/stop"), command=(lambda: self._update_pause_play_()), ) new_face_label.bind("<Button-1>", (lambda e: self._update_pause_play_())) new_face_label.bind( "<Button-3>", lambda event: menu.tk_popup(event.x_root, event.y_root), ) self.cur_face_labels.insert(-1, new_face_label) self.grid_face_labels() self.face_frame = None self.added_face_frames.append(self.face_frame) self.scroll_face_pic_tkscrolledframe_bottom() self.set_msg( _("Right click: pause or play, double click: delete.")) self.refresh_frame()
def del_saved_info_by_info_id(self, info_id=None): info_id = info_id or self.get_info_id() if not info_id: if self.is_test(): print(_("'info_id' is None.")) return basic_info_path = get_basic_info_path(info_id) info_path = get_info_path(info_id) image_dir_path = get_image_dir_path(info_id) basic_info = self.get_basic_info_by_info_id(info_id) deleted_paths = [basic_info_path, info_path, image_dir_path] for src in deleted_paths: if os.path.exists(p): shutil.move(src, get_new_backup_path()) self.set_basic_infos(to_none=True) self.update_saved_info_combobox_values() self.del_showed_info() self.set_msg( _("Information of %s\(%s\) is deleted.") % (basic_info, info_id)) pass
def run(self): if not self.mainwindow: self.mainwindow = self.builder.get_object("about_toplevel") self.mainwindow.title(_("About Funing")) self.builder.get_object("version_label")["text"] = version self.mainwindow.protocol("WM_DELETE_WINDOW", self.on_closing) # connect callbacks self.builder.connect_callbacks(self) else: self.mainwindow.deiconify() self.is_showing = True
def pause_play(self, *args): if self.source_type != SourceType.VID: return if self.paused: self.paused = False self.refresh_frame() self.pause_play_btn_stringvar.set(_("Pause")) self.set_status_msg("") if debug: print("Play. . .") else: self.cancel_root_after() self.pause_play_btn_stringvar.set(_("Play")) self.paused = True if len(self.face_rects) > 0: self.show_face_was_detected_status_msg() else: self.show_no_face_was_detected_status_msg() if debug: print("Pause. . .")
def add_face_label_rec(self, f_index): showed_face_index = len(self.showed_face_frames) new_face_label = Label(self.face_frame) x, y, w, h = self.face_rects[f_index] roi_gray = self.rec_gray_img[y:y + h, x:x + w] roi_gray = cv2.resize(roi_gray, self.save_size, interpolation=cv2.INTER_LINEAR) _label, confidence = recognizer.predict(roi_gray) self.cur_info_id = cur_info_id = self.info_ids[ _label] # global self.x and x are different. _h = max(h, w) frame = self.cur_frame[y:y + _h, x:x + _h] frame = cv2.resize(frame, self.show_size) self.showed_face_frames.append(frame) vid_img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) vid_img = Image.fromarray(vid_img) imgtk = ImageTk.PhotoImage(image=vid_img) new_face_label.imgtk = imgtk new_face_label.configure(image=imgtk) menu = Menu(self.master, tearoff=0) menu.add_command( label=_("delete"), command=(lambda _label=new_face_label, _index=showed_face_index: self.del_face_label_rec(_label, _index)), ) new_face_label.bind( "<Double-Button-1>", lambda e, _label=new_face_label, _index=showed_face_index: self. del_face_label_rec(_label, _index), ) new_face_label.bind( "<Button-1>", (lambda e, _label=new_face_label, _index=showed_face_index, _info_id=cur_info_id: self.show_info(_label, _index, _info_id)), ) new_face_label.bind( "<Button-3>", (lambda event: menu.tk_popup(event.x_root, event.y_root)), ) new_face_label.pack(side=LEFT) self.show_info(new_face_label, showed_face_index, cur_info_id)
def set_text_content(self): self.default_text_insert( content=app_name_t, font="None 18", ) self.default_text_insert( content=app_version, font="None 10", ) self.default_text_insert( content=app_description_t, font="None 10", ) app_url_tag = self.default_text_insert( content=app_url, font="None 10", foreground="blue", cursor="shuttle", ) self.text.tag_bind(app_url_tag, "<1>", self.open_app_url) self.default_text_insert(content=_("Author:"), font="None 10", justify="center") self.default_text_insert(content=app_author[0], font="None 10", justify="center") self.default_text_insert(content=_("Contributors:"), font="None 10", justify="center") for app_contributor in app_contributors[1:]: self.default_text_insert(content=app_contributor[0], font="None 10", justify="center") self.text.config(state="disabled")
def del_face_pic_file(self, info_id, filename="", del_all=False): if debug: print(info_id, filename) _is_last_pic_ = del_all or len(self.cur_face_labels) < 2 ask_str = _("Do you want to delete this face picture?") if _is_last_pic_: ask_str += "\n" + _("All data of {0} will be removed").format( self.cur_name) del_or_not = messagebox.askyesnocancel(_("Delete face picture?"), ask_str, parent=self.master) if del_or_not: info_path = os.path.join(data_path, info_id) if _is_last_pic_: self.clear_face_labels() # shutil.rmtree(info_path) shutil.move(info_path, backup_path) self.data_ids = os.listdir(data_path) self.d_item_count = len(self.data_ids) self.get_name_data(self.cur_p_item_count, self.cur_page_num) self.set_msg(_("face picture has been removed!")) self.clear_info_text() else: img_path = os.path.join(info_path, filename) os.remove(img_path) self.set_msg( _("All data of {0} have been removed!").format( self.cur_name)) self.show_data(info_id) self.data_ids = os.listdir(data_path) self.d_item_count = len(self.data_ids)
def refresh_frame(self): if self.cur_face_labels is None: return if self.vid is None: self.vid = cv2.VideoCapture(self.source) if not self.vid.isOpened(): self.set_msg(_("Unable to open video source.")) return rect, cur_frame = self.vid.read() rec_gray_img = cv2.cvtColor(cur_frame, cv2.COLOR_BGR2GRAY) face_rects = face_casecade.detectMultiScale(rec_gray_img, 1.3, 5) (x, y, w, h) = ( int((cur_frame.shape[1] - self.save_size[0]) / 2), int((cur_frame.shape[0] - self.save_size[0]) / 2), self.save_size[0], self.save_size[1], ) if len(face_rects) > 0: (x, y, w, h) = face_rects[0] self.face_frame = cur_frame = cv2.resize( cur_frame[y:y + h, x:x + w], self.save_size, interpolation=cv2.INTER_LINEAR, ) else: _h = cur_frame.shape[0] _w = cur_frame.shape[1] _wh_min = _h if _h < _w else _w _wh_diff_d2 = int(abs(_h - _w) / 2) _y_start = 0 if _h < _w else _wh_diff_d2 _x_start = 0 if _w < _h else _wh_diff_d2 cur_frame = cv2.resize( cur_frame[_y_start:_wh_min, _x_start:_wh_min], self.save_size, interpolation=cv2.INTER_LINEAR, ) self.face_frame = None vid_img = cv2.cvtColor(cur_frame, cv2.COLOR_BGR2RGB) vid_img = Image.fromarray(vid_img) imgtk = ImageTk.PhotoImage(image=vid_img) new_label = self.cur_face_labels[-2] new_label.imgtk = imgtk new_label.configure(image=imgtk) self.master_after = self.master.after(int(1000 / self.vid_fps), self.refresh_frame)
def set_basic_infos(self, refresh=False, to_none=False): if to_none: self.basic_infos = None return info_ids = self.get_info_ids() if info_ids is None: self.set_msg(_("Information IDs is None.")) return basic_infos = [] for i in info_ids: if os.path.exists(get_basic_info_path(i)): with open(get_basic_info_path(i), "r") as f: basic_infos.append((i, f.read())) self.basic_infos = basic_infos
def set_frame_labels_image_use_picked_frames(self, frames=None, from_new_frame=False): """ Set frame label images using picked_frames Args: frames (Unit[int, numpy.array]): The video or image frame or the the `return` signal if `frames` is 0. """ if frames == 0: return if frames is None: frames = (self.get_picked_frames() or (from_new_frame and self.get_picked_frames_from_frame()) or None) if frames is not None: for f in frames: label = ttk.Label(self.pick_scrolledframe_innerframe, state="active") self.set_label_image(f, label) index = len(self.picked_frame_labels) label.bind( "<Button-1>", lambda event, index=index: self.del_picked_frame_by_index( index), ) label.pack( side="left", anchor="nw", padx=self.picked_frame_label_margin / 2, ) simpletooltip.create(label, _("Click to delete.")) self.picked_frame_labels.append(label) else: if self.is_test(): print(_("Picked frame is None."))
def del_saved_frame_by_id(self, frame_id=None, ask=True, update_widgets=True): if frame_id is None: return if ask: if not messagebox.askyesno( _("Delete saved frame"), _("Do you want to delete saved frame?"), ): return image_path = get_frame_path_by_ids(self.get_info_id(), frame_id) if not os.path.exists(image_path): if self.is_test(): print(_("Image(%s) doesn't exist.") % image_path) return backup_file_path = get_new_backup_file_path(frame_id) if not os.path.exists(backup_file_path): with open(backup_file_path, "wb") as f: pass shutil.move(image_path, backup_file_path) index = 0 for _id, f in self.get_saved_frames(): if _id == frame_id: del self.saved_frames[index] if update_widgets: self.saved_frame_labels[index].destroy() del self.saved_frame_labels[index] break index += 1 pass self.set_frame_labels_image() pass
def set_widgets(self): super().set_widgets() self.set_frame_widget() self.saved_info_combobox = ttk.Combobox( self.root, textvariable=self.saved_info_combobox_var, values=self.get_saved_info_combobox_values(), justify="center", ) self.saved_info_combobox_var.trace( "w", self.saved_info_combobox_var_trace_w) self.pick_scrolledframe = ScrolledFrame(self.root, scrolltype="horizontal") self.pick_scrolledframe_innerframe = self.pick_scrolledframe.innerframe self.pick_scrolledframe_innerframe.configure( height=self.get_pick_scrolledframe_innerframe_height()) self.info_tip_label = ttk.Label( self.root, text=_("Write information in your strict format.")) self.basic_info_entry = tk.Entry(self.root, justify="center") simpletooltip.create(self.basic_info_entry, _("Write basic information here.")) self.info_text = tk.Text(self.root) simpletooltip.create(self.info_text, _("Write additional information here.")) self.save_button = ttk.Button(self.root, text=_("Save"), command=self.save_button_command) self.delete_button = tk.Button( self.root, text=_("Delete"), background="red", activebackground="red", command=self.delete_button_command, )
def get_saved_frames_by_id(self, info_id=None, set_self=True): info_id = info_id or self.get_info_id() if info_id is None: if self.is_test(): print(_("info ID is None.")) return None image_path_list = get_face_image_path_list(info_id) saved_frames = [] for p in image_path_list: image = cv2.imread(p, cv2.IMREAD_COLOR) saved_frames.append( (self.get_saved_frame_id_by_frame_path(p), image)) if set_self: self.set_saved_frames(saved_frames) return saved_frames