def __match_faces(self, encoded_faces): if len(self.__pattern_encodings) == 0: log.warning('Empty patterns') for i in range(len(encoded_faces)): if self.__step_stage_face(): return False encoding = encoded_faces[i]['encoding'] dist, name, pattern = self.__match_face_by_nearest( encoding, patterns.PATTERN_TYPE_GOOD) if dist > 0.001: # skip zero match dist_bad, name_bad, pattern_bad = self.__match_face_by_nearest( encoding, patterns.PATTERN_TYPE_BAD) # match to bad only equal faces if dist_bad < self.__threshold_equal and dist_bad < dist: name = name_bad + '_bad' dist = dist_bad pattern = pattern_bad log.debug(f'matched: {name}: {dist}: {pattern}') if 'name' in encoded_faces[i]: encoded_faces[i]['oldname'] = encoded_faces[i]['name'] if dist < self.__threshold: pass elif dist < self.__threshold_weak: name += '_weak' else: name = '' dist = 1 encoded_faces[i]['name'] = name encoded_faces[i]['dist'] = dist encoded_faces[i]['pattern'] = pattern return True
def recognize_files(self, filenames, debug_out_folder, skip_face_gen=False): self.__make_debug_out_folder(debug_out_folder) self.__start_stage(len(filenames)) for f in filenames: if self.__step_stage(): break try: ext = tools.get_low_ext(f) if ext in tools.IMAGE_EXTS: encoded_faces, media = self.recognize_image(f) elif ext in tools.VIDEO_EXTS: encoded_faces, media = self.recognize_video(f) else: log.warning(f'Unknown ext: {ext}') continue if media is None: continue self.__db.insert(f, encoded_faces, commit=False) if debug_out_folder: debug_out_file_name = self.__extract_filename(f) self.__save_debug_images( encoded_faces, media, debug_out_folder, debug_out_file_name, is_video=ext in tools.VIDEO_EXTS, skip_face_gen=skip_face_gen) except Exception as ex: log.exception(f'Image {f} recognition failed') self.__end_stage()
def clean_tags(self, filename, tags=None, tag_prefix=None, commit=True): fid = self.__get_id(filename) if fid is None: log.warning(f'Filename not found: {filename}') return 0 res = 0 if tags is not None: for tag in tags: res += self.__clean_tag(fid, self.__get_tag_id(tag, TAG_TYPE_PHOTO), commit) res += self.__clean_tag(fid, self.__get_tag_id(tag, TAG_TYPE_VIDEO), commit) if tag_prefix is not None: tag_ids = self.__get_tag_ids(tag_prefix) for tag_id in tag_ids: res += self.__clean_tag(fid, tag_id, commit) if commit: self.__conn.commit() log.debug(f'Removed {res} tags for {filename}') return res
def __filenames_to_dict(self, filenames): res = {} for f in filenames: path, name = os.path.split(f) if name in res: log.warning(f'Duplicate file {name} in {path} and {res[name]}') res[name] = path return res
def __start_recognizer(self, method, *args): self.status() if self.__recognizer is not None: log.warning('Trying to create second recognizer') raise Exception('Recognizer already started') self.__recognizer = recognizer_runner.RecognizerRunner( self.__cfg.filename(), method, *args) self.__recognizer.start()
def __analyze_duplicates(self, print_out): log.info(f'Analyze duplicates') fset = {} for f in self.__files: f = self.fullpath(f) filename = os.path.split(f)[1] if filename in fset: log.warning(f'Duplicate pattern file: {f} ({fset[filename]})') if print_out: print(f) print(fset[filename]) else: fset[filename] = f
def do_GET(self): log.debug('do_GET: ' + self.path) try: path, params = self.__path_params() if path == '/list_cache': self.__list_cache(params) return if path == '/get_names': self.__get_names() return if path == '/get_name_image': self.__get_name_image(params) return if path == '/get_folders': self.__get_folders() return if path == '/get_status': self.__get_status() return if path == '/get_face_src': self.__get_face_src(params) return if path == '/get_face_pattern': self.__get_face_pattern(params) return if path == '/': path = 'index.html' if '..' in path: log.warning('".." in path: ' + path) self.__not_found_response() return ext = tools.get_low_ext(path) if ext in ('.html', '.js', '.css', '.png', '.jpg'): self.__file_request(path, params) return log.warning('Wrong path: ' + path) self.__not_found_response() except Exception as ex: self.__server_error_response(str(ex)) log.exception(ex)
def get_tags(self, filename): fid = self.__get_id(filename) if fid is None: log.warning(f'Filename not found: {filename}') return None c = self.__conn.cursor() res = c.execute( 'SELECT tags.tag \ FROM taggings \ JOIN tags ON tags.id=taggings.tag_id \ WHERE taggings.metadata_item_id=?', (fid, )) return [r[0] for r in res.fetchall()]
def set_tags(self, filename, tags, tag_type, commit=True): fid = self.__get_id(filename) if fid is None: log.warning(f'Filename not found: {filename}') return False for tag in tags: tag_id = self.__get_tag_id(tag, tag_type) if tag_id is None: log.warning(f'Tag not found: {tag}') continue self.__set_tag(fid, tag_id, commit) return True
def optimize(self): encoder = self.__get_encoder() # get encodings and reverse to preserve old patterns encs, names, files = self.encodings() encs.reverse() names.reverse() files.reverse() # convert to numpy array and get length for optimization reasons encs = np.array(encs) encs_len = len(encs) to_remove = [] while 0 < encs_len: log.debug(f'to optimize check: {encs_len}') name = names.pop() fname = files.pop() # numpy array pop() enc, encs = encs[-1], encs[:-1] encs_len -= 1 dists = encoder.distance(encs, enc) i = 0 while i < encs_len: if dists[i] < self.__threshold_equal: if name != names[i]: fn1 = self.fullpath(fname) fn2 = self.fullpath(files[i]) log.warning( f'Different persons {dists[i]} "{fn1}" "{fn2}"') else: to_remove.append(self.fullpath(files[i])) log.info(f'eq: {fname} {files[i]}') names.pop(i) files.pop(i) encs = np.delete(encs, i, axis=0) dists = np.delete(dists, i, axis=0) encs_len -= 1 i += 1 self.remove_files(to_remove) log.info(f'{len(to_remove)} files was optimized.')
def __analyze_encodings_size(self, print_out): log.info(f'Analyze encodings') dct = collections.defaultdict(list) for f, (enc, name, time, tp) in self.__files.items(): f = self.fullpath(f) dct[len(enc)].append(f) if len(dct) != 1: log.warning('Inconsistent encoding: ' + str(dct.keys())) max_key = list(dct.keys())[0] for key in dct: if len(dct[max_key]) < len(dct[key]): max_key = key del dct[max_key] for lst in dct.values(): for f in lst: log.warning(f'wrong encoding: {f}') if print_out: print(f)
def reencode_files(self, files_faces): self.__start_stage(len(files_faces)) for ff in files_faces: try: encoded_faces = ff['faces'] filename = ff['filename'] ext = tools.get_low_ext(filename) if ext in tools.IMAGE_EXTS: self.reencode_image(filename, encoded_faces) encoded_faces = self.__filter_encoded_faces(encoded_faces) elif ext in tools.VIDEO_EXTS: encoded_faces, media = self.recognize_video(filename) else: log.warning(f'Unknown ext: {ext}') continue self.__db.insert(filename, encoded_faces, commit=False) except Exception as ex: log.exception(f'{filename} reencoding failed') self.__end_stage()
def enable_landmarks(filename, enable): descr, thumbnail = load_face_description(filename) enabled = thumbnail is not None if enable == enabled: log.debug(f'enable_landmarks skip: {filename}') return if descr is None or 'landmarks' not in descr: log.warning(f'has no landmarks: {filename}') return image = Image.open(filename) if enable: thumbnail = image.copy() __set_landmarks_lines(image, descr['landmarks']) else: image = thumbnail thumbnail = None save_with_description(image, descr, thumbnail, filename)
def __analyze_landmarks(self, print_out): log.info(f'Analyze landmarks') for f in self.__files: f = self.fullpath(f) descr = tools.load_face_description(f)[0] if descr is None: log.warning(f'missed description: {f}') if print_out: print(f) continue if 'landmarks' not in descr: log.warning(f'missed landmarks: {f}') if print_out: print(f) continue if not tools.test_landmarks(descr['landmarks']): log.warning(f'wrong landmarks: {f}') if print_out: print(f)
def __get_face_pattern(self, params): path = params['path'][0] descr = self.__get_face_file_description(path) if descr is None: self.__not_found_response() return face_id = descr.get('face_id', None) if face_id is None: log.warning(f'face file {path} without face_id') self.__not_found_response() return count, ff = self.server.db().get_face(face_id) if count == 0: log.warning(f'face with id {face_id} not found') self.__not_found_response() return pattern_filename = next(ff)['faces'][0]['pattern'] if pattern_filename == '': log.warning(f'pattern file not specified') self.__not_found_response() return self.__ok_response(pattern_filename)
def generate(self, regenerate=False): log.info(f'Patterns generation: {self.__folder} ({regenerate})') image_files = {} for image_file in tools.list_files(self.__folder, tools.IMAGE_EXTS): if os.path.split(image_file)[1] == FACE_FILENAME: continue image_files[image_file] = os.stat(image_file).st_mtime if not regenerate: self.load() filtered = {} for image_file in image_files: filename_exsists = self.relpath(image_file) in self.__files if not filename_exsists or \ self.__files[self.relpath(image_file)][self.FILES_TIME] != \ image_files[image_file]: filtered[image_file] = image_files[image_file] if filename_exsists: self.__remove_file(image_file) if len(filtered) == 0: log.info('Nothing changed') return image_files = filtered for (i, image_file) in enumerate(image_files): splitted = image_file.split(os.path.sep) name = splitted[-2] if name == BAD_FOLDERNAME: name = splitted[-3] tp = PATTERN_TYPE_BAD elif name == OTHER_FOLDERNAME: name = splitted[-3] tp = PATTERN_TYPE_OTHER else: tp = PATTERN_TYPE_GOOD log.info(f'{i + 1}/{len(image_files)} file: {image_file}') descr, thumbnail = tools.load_face_description(image_file) try: encoding = descr['encoding'] except Exception: encoding = None if encoding is None: import face_recognition try: image = tools.read_image(image_file, self.__max_size) except Exception: log.exception(f'read_image failed') continue boxes = face_recognition.face_locations(image, model=self.__model) if len(boxes) != 1: log.warning( f'{len(boxes)} faces detected in {image_file}. Skip.') continue encodings, landmarks = \ self.__get_encoder().encode(image, boxes) if not tools.test_landmarks(landmarks[0]): log.warning(f'bad face detected in {image_file}. Skip.') continue encoding = encodings[0] self.__files[self.relpath(image_file)] = \ [encoding, name, image_files[image_file], tp] self.__init_basenames() self.__persons = self.__calc_persons() self.__save()