def export_to_json(args): preds_per_person = utils.load_faces_from_csv(args.db, args.imgs_root) if len(preds_per_person) == 0: print('no faces loaded') exit() json_dir = os.path.join(args.db, 'exif_json') if not os.path.isdir(json_dir): utils.mkdir_p(json_dir) for p in preds_per_person: if p == 'deleted' or p == 'unknown': continue print('exporting {}'.format(p)) for f in preds_per_person[p]: # check mask if args.mask_folder != None: if os.path.dirname(f[1]) != args.mask_folder: continue if not os.path.isfile(f[1]): continue json_path = json_dir + f[1][:-3] + 'json' if os.path.isfile(json_path): continue if not os.path.isdir(os.path.dirname(json_path)): utils.mkdir_p(os.path.dirname(json_path)) arg_str = 'exiftool -json "' + f[1] + '" > "' + json_path + '"' os.system(arg_str)
def export_new_format(args): # faces = utils.load_img_labels(args.imgs_root) # d1, d2, d3 = utils.get_faces_dicts(faces) # utils.store_to_img_labels(faces, d1) preds_per_person = utils.load_faces_from_csv(args.db, args.imgs_root) if len(preds_per_person) == 0: print('no faces loaded') exit() files_faces = utils.get_faces_in_files(preds_per_person, ignore_unknown=False) faces = [] names = [] for f in files_faces: (name, idx) = files_faces[f][0] img_timestamp = preds_per_person[name][idx][4] img_labels = utils.IMG_LABELS(img_timestamp) for (name, idx) in files_faces[f]: if not name in names: names.append(name) name_id = len(names) - 1 else: name_id = names.index(name) ppp = preds_per_person[name][idx] loc = ppp[0][1] desc = ppp[2] timestamp = ppp[4] confirmed = ppp[3] face = utils.FACE(loc, desc, name_id, timestamp, confirmed) faces.append(face) img_labels.faces.append(face) # write img_label # bin_path = os.path.join(os.path.dirname(f), os.path.splitext(os.path.basename(f))[0] + '.pkl') bin_path = f + '.pkl' with open(bin_path, 'wb') as fid: pickle.dump(img_labels, fid) # with open(bin_path, 'rb') as fid: # img_labels_test = pickle.load(fid) # for face in img_labels_test.faces: # face.path = f # write name_id mapping names_path = os.path.join(args.outdir, 'name_mapping.csv') with open(names_path, "w") as csvfile: filewriter = csv.writer(csvfile, delimiter=';') for i, n in enumerate(names): filewriter.writerow([str(i), n])
def export_album(args): preds_per_person = utils.load_faces_from_csv(args.db) if len(preds_per_person) == 0: print('no faces loaded') exit() album_dir = os.path.join(args.outdir, 'faces') utils.mkdir_p(album_dir) for p in preds_per_person: print('exporting {}'.format(p)) face_dir = os.path.join(album_dir, p) utils.mkdir_p(face_dir) for f in preds_per_person[p]: symlinkname = os.path.join(face_dir, os.path.basename(f[1])) if not os.path.islink(symlinkname): os.symlink(f[1], symlinkname) return album_dir
def export_to_json(args): preds_per_person = utils.load_faces_from_csv(args.db) if len(preds_per_person) == 0: print('no faces loaded') exit() json_dir = os.path.join(args.db, 'exif_json') if not os.path.isdir(json_dir): utils.mkdir_p(json_dir) for p in preds_per_person: print('exporting {}'.format(p)) for f in preds_per_person[p]: if not os.path.isfile(f[1]): continue json_path = os.path.join(json_dir, f[1].replace('/', '_')[1:-3] + 'json') json_path = json_path.replace(' ', '_') if os.path.isfile(json_path): continue else: arg_str = 'exiftool -json "' + f[1] + '" > ' + json_path os.system(arg_str)
def export_thumbnails(args): preds_per_person = utils.load_faces_from_csv(args.db, args.imgs_root) files_faces = utils.get_faces_in_files(preds_per_person) if len(preds_per_person) == 0: print('no faces loaded') exit() # face_prefix = 'f ' size = (1024, 1024) for f in files_faces: rel_path = os.path.relpath(f, args.imgs_root) out_path = os.path.join(args.outdir, rel_path) print('Writing {}'.format(f)) if not os.path.isdir(os.path.dirname(out_path)): os.makedirs(os.path.dirname(out_path)) keywords = [] for i in files_faces[f]: cls, idx = i if cls != 'unknown' and cls != 'detected' and cls != 'deleted': keywords.append(cls) if len(keywords) == 0: print('only ignored keywords found -> skipping') continue if os.path.isfile(out_path): print('skipping') continue im = cv2.imread(f) im = utils.resizeCV(im, size[1]) if f.lower().endswith(('.jpg', '.jpeg')): cv2.imwrite(out_path, im, [cv2.IMWRITE_JPEG_QUALITY, 80]) elif f.lower().endswith(('.png')): cv2.imwrite(out_path, im, [cv2.IMWRITE_PNG_COMPRESSION, 2]) else: print('unsupported file format of {}'.format(f)) exit()
def show_class(args, svm_clf): preds_per_person = utils.load_faces_from_csv(args.db) if args.face == 'all': classes = preds_per_person else: classes = [args.face] for cls in classes: face_locations, face_encodings = utils.initialize_face_data( preds_per_person, cls) print('{} members of {}'.format(len(face_locations), cls)) if len(face_locations) == 0: return key = 0 ix = 0 save = [] while key != 27 and len(face_locations) > 0: while len(save) > 100: save.pop(0) if ix >= len(face_locations): ix = 0 elif ix < 0: ix = len(face_locations) - 1 names, probs = predict_face_svm(face_encodings[ix], svm_clf) name = names[0] #nr_conf, nr_ignored, nr_not_ignored = utils.count_preds_status(preds_per_person[cls]) #str_count = 'total: ' + str(len(preds_per_person[cls])) + ', confirmed: ' + str(nr_conf) + ', ignored: ' + str(nr_ignored) str_count = str(ix + 1) + ' / ' + str(len(preds_per_person[cls])) predictions = [] predictions.append((cls, face_locations[ix])) key = utils.show_prediction_labels_on_image( predictions, None, preds_per_person[cls][ix][3], 0, preds_per_person[cls][ix][1], str_count) if key == 46: # key '.' ix += 1 elif key == 44: # key ',' ix -= 1 elif key == 114: # key 'r' ix = random.randint(0, len(face_locations)) while (preds_per_person[cls][ix][3] != 0): ix = random.randint(0, len(face_locations) - 1) elif key == 99: # key 'c' new_name = utils.guided_input(preds_per_person) if new_name != "": save.append(copy.deepcopy(preds_per_person[cls])) # add pred in new list if preds_per_person.get(new_name) == None: preds_per_person[new_name] = [] tmp = preds_per_person[cls][ix] preds_per_person[new_name].append( ((new_name, tmp[0][1]), tmp[1], tmp[2], tmp[3], tmp[4])) # delete pred in current list face_locations, face_encodings = utils.delete_element_preds_per_person( preds_per_person, cls, ix) print("face changed: {} ({})".format( new_name, len(preds_per_person[new_name]))) elif key == 117: # key 'u' save.append(copy.deepcopy(preds_per_person[cls])) new_name = 'unknown' # add pred in new list if preds_per_person.get(new_name) == None: preds_per_person[new_name] = [] tmp = preds_per_person[cls][ix] preds_per_person[new_name].append( ((new_name, tmp[0][1]), tmp[1], tmp[2], tmp[3], tmp[4])) # delete pred in current list face_locations, face_encodings = utils.delete_element_preds_per_person( preds_per_person, cls, ix) print("face changed: {} ({})".format( new_name, len(preds_per_person[new_name]))) elif key == 47: # key '/' save.append(copy.deepcopy(preds_per_person[cls])) tmp = preds_per_person[cls][ix] if tmp[3] == 0: preds_per_person[cls][ix] = tmp[0], tmp[1], tmp[2], 1, tmp[ 4] elif tmp[3] == 1: preds_per_person[cls][ix] = tmp[0], tmp[1], tmp[2], 0, tmp[ 4] #while (preds_per_person[cls][ix][3] == 0 and not ix == len(face_locations) - 1): ix += 1 print("face confirmed: {} ({})".format( tmp[0], len(preds_per_person[cls]))) elif key == 102: #key 'f' while (preds_per_person[cls][ix][3] != 0 and ix < len(face_locations) - 1): ix += 1 elif key >= 48 and key <= 57: # keys '0' - '9' save.append(copy.deepcopy(preds_per_person[cls])) new_name = names[key - 48] tmp = preds_per_person[cls][ix] preds_per_person[new_name].append( ((new_name, tmp[0][1]), tmp[1], tmp[2], tmp[3], tmp[4])) # delete pred in current list face_locations, face_encodings = utils.delete_element_preds_per_person( preds_per_person, cls, ix) print("face confirmed: {} ({})".format( new_name, len(preds_per_person[new_name]))) elif key == 100: # key 'd' if 1: save.append(copy.deepcopy(preds_per_person[cls])) new_name = 'deleted' # add pred in new list if preds_per_person.get(new_name) == None: preds_per_person[new_name] = [] tmp = preds_per_person[cls][ix] preds_per_person[new_name].append( ((new_name, tmp[0][1]), tmp[1], tmp[2], tmp[3], tmp[4])) # delete pred in current list face_locations, face_encodings = utils.delete_element_preds_per_person( preds_per_person, cls, ix) else: save.append(copy.deepcopy(preds_per_person[cls])) # delete face face_locations, face_encodings = utils.delete_element_preds_per_person( preds_per_person, cls, ix) print("face deleted") elif key == 97: # key 'a' # delete all faces of this class in the current image save.append(copy.deepcopy(preds_per_person[cls])) image_path = preds_per_person[cls][ix][1] i = 0 while i < len(preds_per_person[cls]): compare_path = preds_per_person[cls][i][1] if preds_per_person[cls][i][1] == image_path: face_locations, face_encodings = utils.delete_element_preds_per_person( preds_per_person, cls, i) else: i += 1 print("all faces in {} deleted".format(image_path)) elif key == 98: #key 'b' if len(save) > 0: preds_per_person[cls] = copy.deepcopy(save.pop()) face_locations, face_encodings = utils.initialize_face_data( preds_per_person, cls) print("undone last action") elif key == 115: #key 's' utils.export_persons_to_csv(preds_per_person, args.db) print('saved') utils.export_persons_to_csv(preds_per_person, args.db)
def train(args): X = [] y = [] train_dir = args.traindir detector = dlib.get_frontal_face_detector() sp = dlib.shape_predictor("models/shape_predictor_5_face_landmarks.dat") facerec = dlib.face_recognition_model_v1( "models/dlib_face_recognition_resnet_model_v1.dat") if len(utils.get_files_in_dir(train_dir, '.csv')) != 0: # train using csv files print('Training using .csv files.') preds_per_person = utils.load_faces_from_csv(train_dir) for p in preds_per_person: if p != 'unknown': for l in preds_per_person[p]: X.append(l[2]) y.append(p) if len(X) == 0: print('No faces found in database {}'.format(train_dir)) return elif len(os.listdir(train_dir)) != 0: # train using train folder # Loop through each person in the training set print('Training using faces in subfolders.') for class_dir in os.listdir(train_dir): if not os.path.isdir(os.path.join(train_dir, class_dir)): continue images = utils.get_images_in_dir(os.path.join( train_dir, class_dir)) if len(images) == 0: continue print('adding {} to training data'.format(class_dir)) # Loop through each training image for the current person for img_path in images: locations, descriptors = utils.detect_faces_in_image( img_path, detector, facerec, sp, use_entire_image=True) # Add face descriptor for current image to the training set X.append(descriptors[0]) y.append(class_dir) print('{} faces used for training'.format(len(images))) else: print('Training directory does not contain valid training data.') return # Determine how many neighbors to use for weighting in the KNN classifier n_neighbors = int(round(math.sqrt(len(X)))) print("Chose n_neighbors automatically:", n_neighbors) # Create and train the KNN classifier print("Training model with KNN ...") knn_clf = neighbors.KNeighborsClassifier(n_neighbors=n_neighbors, algorithm='ball_tree', weights='distance') knn_clf.fit(X, y) # Save the trained KNN classifier with open(os.path.join(args.outdir, 'knn.clf'), 'wb') as f: pickle.dump(knn_clf, f) # train the svm print("Training model with an SVM ...") recognizer = SVC(C=1.0, kernel="linear", probability=True) recognizer.fit(X, y) # Save the trained SVM with open(os.path.join(args.outdir, 'svm.clf'), 'wb') as f: pickle.dump(recognizer, f) print('Trained models with {} faces'.format(len(X)))
def save_to_exif(args): preds_per_person = utils.load_faces_from_csv(args.db) if len(preds_per_person) == 0: print('no faces loaded') exit()
def save_to_exif(args): face_prefix = 'f ' # json_dir = os.path.join(args.db, 'exif_json') preds_per_person = utils.load_faces_from_csv(args.db, args.imgs_root) if len(preds_per_person) == 0: print('no faces loaded') exit() keywords_files = {} for p in preds_per_person: # print('exporting {}'.format(p)) for f in preds_per_person[p]: # check mask if args.mask_folder != None: if os.path.dirname(f[1]) != args.mask_folder: continue if os.path.isfile(f[1]): if keywords_files.get(f[1]) == None: keywords_files[f[1]] = [] if p != 'unknown' and p != 'deleted': keywords_files[f[1]].append(face_prefix + p) if args.mask_folder == None: all_images = utils.get_images_in_dir_rec(args.imgs_root) else: all_images = utils.get_images_in_dir_rec(args.mask_folder) for i, k in enumerate(all_images): if args.mask_folder != None: if os.path.dirname(k) != args.mask_folder: continue changed = False print('processing exif {}/{} ... {}'.format(i, len(all_images), k)) ex = exif.ExifEditor(k) # test = ex.getDictTags() tag = ex.getTag('Description') if tag != os.path.basename(os.path.dirname(k)): ex.setTag('Description', os.path.basename(os.path.dirname(k))) print('updated tag <Description>') # get face keywords (they start with 'f ') kw_faces_exif = [] kw_others = [] kws = ex.getKeywords() # multiple keywords found for kw in kws: if kw[:2] == face_prefix: kw_faces_exif.append(kw) else: kw_others.append(kw) new_kws = [] if keywords_files.get(k) == None: if args.overwrite: changed = True else: if set(keywords_files[k]) != set(kw_faces_exif): new_kws = keywords_files[k] if not args.overwrite: new_kws = new_kws + kw_others changed = True if changed: ex.setKeywords(new_kws) else: print('no change in exif found')
def cluster_faces_in_class(args): preds_per_person = utils.load_faces_from_csv(args.db, args.imgs_root) if preds_per_person.get(args.cls) == None: print('Class {} not found.'.format(args.cls)) return descriptors = [] for i, p in enumerate(preds_per_person[args.cls]): descriptors.append(dlib.vector(p[2])) # cluster the faces print('clustering...') all_indices = [] all_lengths = [] if 1: # chinese whispers labels = dlib.chinese_whispers_clustering(descriptors, args.threshold) num_classes = len(set(labels)) print("Number of clusters: {}".format(num_classes)) for j in range(0, num_classes): class_length = len([label for label in labels if label == j]) if class_length >= args.min_members: indices = [] for i, label in enumerate(labels): if label == j: indices.append(i) all_indices.append(indices) all_lengths.append(class_length) else: #DBSCAN from sklearn.cluster import DBSCAN clt = DBSCAN(eps=args.threshold, metric="euclidean", n_jobs=4, min_samples=args.min_members) clt.fit(descriptors) labels = np.unique(clt.labels_) num_classes = len(np.where(labels > -1)[0]) if num_classes > 1: # to be checked!! print("Number of clusters: {}".format(num_classes)) for j in labels: idxs = np.where(clt.labels_ == j)[0] class_length = len(idxs) indices = [] for i in idxs: indices.append(i) all_indices.append(indices) all_lengths.append(class_length) sort_index = np.argsort(np.array(all_lengths))[::-1] # Move the clustered faces to individual groups print('Moving the clustered faces to the database.') to_delete = [] for i in sort_index[:args.max_clusters]: cluster_name = "group_" + str(i) # export to folders if args.export: cluster_path = os.path.join(args.outdir, cluster_name) if not os.path.isdir(cluster_path): os.makedirs(cluster_path) to_delete += all_indices[i] for n, index in enumerate(all_indices[i]): utils.insert_element_preds_per_person(preds_per_person, args.cls, index, cluster_name) if args.export: file_name = os.path.join( cluster_path, 'face_' + cluster_name + '_' + str(n) + '.jpg') utils.save_face_crop(file_name, preds_per_person[args.cls][index][1], preds_per_person[args.cls][index][0][1]) to_delete = sorted(to_delete) to_delete.reverse() for i in to_delete: preds_per_person[cls].pop( i ) # if not, they would exist double, in 'deleted' and in the cluster group # utils.delete_element_preds_per_person(preds_per_person, args.cls, i) utils.export_persons_to_csv(preds_per_person, args.imgs_root, args.db)