def show_all_faces(args, svm_clf, knn_clf): tmp_faces, img_labels = utils.load_img_labels(args.imgs_root) faces = utils.FACES(tmp_faces) for i,n in enumerate(faces.dict_by_name): args.face = n show_faces_by_name(args, svm_clf, knn_clf, faces, img_labels)
def export_face_imgs_only(args): tmp_faces, img_labels = utils.load_img_labels(args.imgs_root) faces = utils.FACES(tmp_faces) for im in faces.dict_by_files: rel_path = os.path.relpath(im, args.imgs_root) symlinkname = os.path.join(args.outdir, rel_path) xmp_path = os.path.splitext(im)[0] + '.xmp' xmp_path_link = os.path.splitext(symlinkname)[0] + '.xmp' names = faces.get_names(faces.dict_by_files[im]) if names.count('unknown') + names.count('deleted') + names.count( 'detected') == len(names): if os.path.exists(symlinkname): os.remove(symlinkname) if os.path.exists(xmp_path_link): os.remove(xmp_path_link) else: dirname = os.path.dirname(symlinkname) if not os.path.exists(dirname): os.makedirs(dirname) if not os.path.islink(symlinkname): os.symlink(im, symlinkname) if not os.path.islink(xmp_path_link): os.symlink(xmp_path, xmp_path_link)
def detect_faces(args): tmp_faces, img_labels = utils.load_img_labels(args.imgs_root) faces = utils.FACES(tmp_faces) # initialize counters total_faces = len(utils.get_images_in_dir_rec(args.input)) detect_faces_in_folder(args, faces, img_labels, utils.get_images_in_dir_rec(args.input), total_faces)
def main(): parser = argparse.ArgumentParser() parser.add_argument('--face', type=str, required=True, help="Face to show ('all' shows all faces).") parser.add_argument('--svm', type=str, required=True, help="Path to svm model file (e.g. svm.clf).") parser.add_argument('--knn', type=str, required=True, help="Path to knn model file (e.g. knn.clf).") # parser.add_argument('--db', type=str, required=True, # help="Path to folder with predicted faces (.csv files).") parser.add_argument('--imgs_root', type=str, required=True, help="Root directory of your image library.") parser.add_argument('--mask_folder', type=str, required=False, default='', help="Mask folder for faces. Only faces of images within this folder will be shown.") parser.add_argument('--min_size', type=str, required=False, default=0, help="Defines the min. size of a face. A face will be accepted if it is larger than min_size * img_height (img_width resp.)") args = parser.parse_args() # if not os.path.isdir(args.db): # print('args.db is not a valid directory') if os.path.isfile(args.knn): with open(args.knn, 'rb') as f: knn_clf = pickle.load(f) else: print('args.knn ({}) is not a valid file'.format(args.knn)) exit() if os.path.isfile(args.svm): with open(args.svm, 'rb') as f: svm_clf = pickle.load(f) else: print('args.svm ({}) is not a valid file'.format(args.svm)) exit() if os.path.isdir(args.face): print('Showing detections of folder {}'.format(args.face)) show_faces_in_folder(args, svm_clf, knn_clf) else: if args.face in ['predicted', 'unconfirmed']: print('Showing unconfirmed faces') show_unconfirmed_faces(args, svm_clf, knn_clf) else: print('Showing detections of class {}'.format(args.face)) tmp_faces, img_labels = utils.load_img_labels(args.imgs_root) # with open(os.path.join(args.imgs_root, 'faces_single_file.bin'), 'wb') as fid: # pickle.dump(tmp_faces, fid) faces = utils.FACES(tmp_faces) show_faces_by_name(args, svm_clf, knn_clf, faces, img_labels) # show_all_faces(args, svm_clf, knn_clf) print('Done.')
def tag_images(args): # images = utils.get_images_in_dir_rec(args.input) tmp_faces, img_labels = utils.load_img_labels(args.imgs_root) faces = utils.FACES(tmp_faces) images = list(faces.dict_by_files.keys()) random.shuffle(images) logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') rekognition_client = boto3.client('rekognition') for img in images: pkl_path = img + '.pkl' if os.path.isfile(pkl_path): with open(pkl_path, 'rb') as fid: img_label = pickle.load(fid) else: img_label = utils.IMG_LABELS(utils.get_timestamp(img)) img_label.path = img # if not hasattr(img_label, 'gcloud_labels'): # img_label.gcloud_labels = [] # if not hasattr(img_label, 'gcloud_objects'): # img_label.gcloud_objects = [] # if not hasattr(img_label, 'gcloud_landmarks'): # img_label.gcloud_landmarks = [] # if not hasattr(img_label, 'gcloud_web'): # img_label.gcloud_web = [] # if len(img_label.gcloud_labels) != 0 or \ # len(img_label.gcloud_objects) != 0 or \ # len(img_label.gcloud_web) != 0 or \ # len(img_label.gcloud_landmarks): # print('{} already tagged'.format(img)) # continue print('tagging {}'.format(img)) labels = detect_labels_local_file(img) # img_label.gcloud_labels = detect_labels(image) # img_label.gcloud_objects = detect_objects(image) # img_label.gcloud_web = detect_web(image) # img_label.gcloud_landmarks = detect_landmarks(image) if 1: ocv_img = cv2.imread(img) cv2.imshow("image", ocv_img) cv2.waitKey(0)
def show_unconfirmed_faces(args, svm_clf, knn_clf): tmp_faces, img_labels = utils.load_img_labels(args.imgs_root) faces = utils.FACES(tmp_faces) unconfirmed = faces.get_unconfirmed(args.face) if len(unconfirmed) == 0: print('no newly predicted or unconfirmed faces found') return False files = faces.get_paths(unconfirmed, allow_duplicates=True) i = 0 key = 0 while key != 27 and len(files) > 0: if i < 0: i = len(files) - 1 if i > len(files) - 1: i = 0 str_count = str(i + 1) + ' / ' + str(len(files)) + ' #' + args.face + ': ' + str(len(unconfirmed)) print(str_count) img_path = files[i] opencvImage = cv2.imread(img_path) height, width = opencvImage.shape[:2] scale = 600.0 / float(height) opencvImage = cv2.resize(opencvImage, (int(width * scale), int(height * scale))) opencvImage_clean = opencvImage.copy() main_idx = unconfirmed[i] utils.draw_faces_on_image(faces, faces.dict_by_files[img_path], scale, opencvImage, main_idx) utils.clicked_names, probs = utils.predict_face_svm(faces.get_face(main_idx).desc, svm_clf) cv2.imshow("faces", opencvImage) cv2.setMouseCallback("faces", utils.click_face, (opencvImage_clean, faces, scale, img_labels[img_path], svm_clf)) key = cv2.waitKey(0) if len(utils.clicked_idx) == 0 and main_idx != -1: utils.clicked_idx.append(main_idx) utils.perform_key_action(args, key, faces, img_labels, utils.clicked_idx, utils.clicked_names, img_path, knn_clf, "") utils.clicked_idx = [] if key == 46 or key == 47: # key '.' or key '/' i += 1 elif key == 44: # key ',' i -= 1 elif key == 114: # key 'r' i = random.randint(0, len(files) - 1) utils.store_to_img_labels(faces, img_labels)
def main(): parser = argparse.ArgumentParser() parser.add_argument('--imgs_root', type=str, required=True, help="Path to images folder.") args = parser.parse_args() # dlib face detector detector = dlib.get_frontal_face_detector() sp = dlib.shape_predictor("models/shape_predictor_68_face_landmarks.dat") facerec = dlib.face_recognition_model_v1("models/dlib_face_recognition_resnet_model_v1.dat") # win = dlib.image_window() tmp_faces, img_labels = utils.load_img_labels(args.imgs_root) faces = utils.FACES(tmp_faces) for im in faces.dict_by_files: for fi in faces.dict_by_files[im]: face = faces.get_face(fi) # if hasattr(face, 'shape_dlib68') and hasattr(face, 'desc_dlib68'): # continue img = dlib.load_rgb_image(face.path) # locations: list of tuples (t,r,b,l) # dlib rect: left: int, top: int, right: int, bottom: int d = dlib.chip_details(dlib.rectangle(face.loc[3], face.loc[0], face.loc[1], face.loc[2])) roi = dlib.extract_image_chip(np.array(img), d) # idx tells which sub-detector was used, see https://github.com/davisking/dlib/blob/master/dlib/image_processing/frontal_face_detector.h dets, scores, idx = detector.run(roi, 1, 0.3) print(scores, idx) if len(dets) == 0: face.shape_dlib68 = None face.desc_dlib68 = None else: shape = dlib.rectangle(dets[0].left()+face.loc[3], dets[0].top()+face.loc[0], dets[0].right()+face.loc[3], dets[0].bottom()+face.loc[0]) face.shape_dlib68 = sp(img, shape) face.desc_dlib68 = np.array(facerec.compute_face_descriptor(img, face.shape_dlib68)) # win.clear_overlay() # win.set_image(img) # win.add_overlay(face.shape_dlib68) # dlib.hit_enter_to_continue() if not face.path in faces.changed_files: faces.changed_files.append(face.path) utils.store_to_img_labels(faces, img_labels)
def train_detectors(args): X = [] y = [] tmp_faces, img_labels = utils.load_img_labels(args.imgs_root) faces = utils.FACES(tmp_faces) for p in faces.dict_by_name: if p not in ['unknown', 'deleted', 'detected', 'DELETED']: for l in faces.dict_by_name[p]: confirmed = faces.get_confirmed(l) if confirmed not in [2]: X.append(faces.get_desc(l)) y.append(p) if len(X) == 0: print('No faces found in database {}'.format(args.imgs_root)) return # Determine how many neighbors to use for weighting in the KNN classifier n_neighbors = int(round(math.sqrt(len(X)))) # n_neighbors = 100 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='auto', 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 show_faces_in_folder(args, svm_clf, knn_clf): tmp_faces, img_labels = utils.load_img_labels(args.imgs_root) faces = utils.FACES(tmp_faces) files = faces.get_paths_from_folder(args.face) i = 0 key = 0 while key != 27: if i < 0: i = len(files) - 1 if i > len(files) - 1: i = 0 str_count = str(i + 1) + ' / ' + str(len(files)) + ' #' + args.face + ': ' + str(len(files)) print(str_count) img_path = files[i] opencvImage = cv2.imread(img_path) height, width = opencvImage.shape[:2] scale = 600.0 / float(height) opencvImage = cv2.resize(opencvImage, (int(width * scale), int(height * scale))) opencvImage_clean = opencvImage.copy() utils.draw_faces_on_image(faces, faces.dict_by_folders[args.face][img_path], scale, opencvImage) cv2.imshow("faces", opencvImage) cv2.setMouseCallback("faces", utils.click_face, (opencvImage_clean, faces, scale, img_labels[img_path], svm_clf)) key = cv2.waitKey(0) utils.perform_key_action(args, key, faces, img_labels, utils.clicked_idx, utils.clicked_names, img_path, knn_clf, "") utils.clicked_idx = [] if key == 46 or key == 47: # key '.' or key '/' i += 1 elif key == 44: # key ',' i -= 1 elif key == 114: # key 'r' i = random.randint(0, len(files) - 1) utils.store_to_img_labels(faces, img_labels)
def export_face_crops(args): tmp_faces, img_labels = utils.load_img_labels(args.imgs_root) faces = utils.FACES(tmp_faces) sp = dlib.shape_predictor("models/shape_predictor_5_face_landmarks.dat") for name in faces.dict_by_name: if name == 'unknown' or name == 'deleted': continue face_dir = os.path.join(args.outdir, name) if not os.path.isdir(face_dir): utils.mkdir_p(face_dir) print('Writing {}'.format(name)) for i, f in enumerate(faces.dict_by_name[name]): face_path = os.path.join(face_dir, '{}_{:06d}.jpg'.format(name, i)) if not os.path.isfile(face_path) or args.overwrite: if 0: utils.save_face_crop(face_path, faces.get_face_path(f), faces.get_loc(f)) else: utils.save_face_crop_aligned(sp, face_path, faces.get_face_path(f), faces.get_loc(f))
# picture1_height = picture1.size[1] # window.geometry("{}x{}+100+100".format(picture_width+picture1_width+10, picture_height)) # if i == 0: # image_widget = tkinter.Label(window, image=tk_picture) # image_widget1 = tkinter.Label(window, image=tk_picture1) # else: # image_widget.configure(image=tk_picture) # image_widget1.configure(image=tk_picture1) # image_widget.place(x=0, y=0, width=picture_width, height=picture_height) # image_widget1.place(x=picture_width+10, y=0, width=picture1_width, height=picture1_height) # # # wait for events # window.mainloop() tmp_faces, img_labels = utils.load_img_labels("/Users/mhumenbe/Library/Mobile Documents/com~apple~CloudDocs/Fotos") faces = utils.FACES(tmp_faces) idxs = sorted(faces.dict_by_name['unknown'], key=lambda x: faces.get_face(x).timestamp, reverse=True) files = faces.get_paths(idxs) root = tk.Tk() root.geometry("400x400") def showimg(e): n = lst.curselection() fname = lst.get(n) img = tk.PhotoImage(file=fname) lab.config(image=img) lab.image = img print(fname)
def predict_faces(args, knn_clf, svm_clf): tmp_faces, img_labels = utils.load_img_labels(args.imgs_root) faces = utils.FACES(tmp_faces) if not args.cls in faces.dict_by_name: print('no faces found in this class') return False files = faces.get_paths(faces.dict_by_name[args.cls]) total_nr_files = len(files) i = 0 key = 0 while key != 27 and i < total_nr_files: str_count = str(i + 1) + ' / ' + str(total_nr_files) print(str_count) img_path = files[i] opencvImage = cv2.imread(img_path) height, width = opencvImage.shape[:2] scale = 600.0 / float(height) opencvImage = cv2.resize(opencvImage, (int(width * scale), int(height * scale))) opencvImage_clean = opencvImage.copy() idxs = sorted(faces.dict_by_name[args.cls], key=lambda x: faces.get_face(x).timestamp, reverse=True) face_idxs = faces.get_face_idxs_by_name_and_file(args.cls, img_path, idxs) for fi in face_idxs: opencvImage = opencvImage_clean.copy() face = faces.get_face(fi) name = face.name names, probs = utils.predict_face_svm(face.desc, svm_clf, print_top=True) if name == "unknown" or name == "detected" and name != 'deleted' and name != 'DELETED': if probs[0] >= 0.85: name = names[0] print('{} has high probability'.format(name)) else: name_knn = utils.predict_knn(knn_clf, face.desc, n=7, thresh=0.3) if name_knn != 'unknown': name = name_knn print('{} has majority in knn search'.format(name)) else: name = 'unknown' faces.rename(fi, name) if name != args.cls and name != 'unknown' and name != 'deleted' and name != 'DELETED': if args.confirm: utils.show_face_crop(img_path, face.loc) utils.draw_faces_on_image(faces, faces.dict_by_files[img_path], scale, opencvImage, fi) cv2.putText(opencvImage, name, (20, opencvImage.shape[0] - 40), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 1) cv2.imshow("faces", opencvImage) cv2.setMouseCallback("faces", utils.click_face, (opencvImage_clean, faces, scale, img_labels[img_path], svm_clf)) key = cv2.waitKey(0) if len(utils.clicked_idx) == 0: utils.clicked_idx.append(fi) utils.clicked_names = names utils.perform_key_action(args, key, faces, img_labels, utils.clicked_idx, utils.clicked_names, img_path, knn_clf, "") utils.clicked_idx = [] utils.clicked_names = [] if not args.cls in faces.dict_by_name: print('no faces found in this class') return False if key == 46 or key == 47: # key '.' or key '/' continue elif key == 111: # 'o' faces.rename(fi, name) faces.set_confirmed(fi, 1) else: # move to new class faces.rename(fi, name) if name == 'unknown': faces.set_confirmed(fi, 0) else: faces.set_confirmed(fi, 2) i += 1 # files = faces.get_paths(faces.dict_by_name[args.cls]) utils.store_to_img_labels(faces, img_labels)
def tag_images(args): # images = utils.get_images_in_dir_rec(args.input) tmp_faces, img_labels = utils.load_img_labels(args.imgs_root) faces = utils.FACES(tmp_faces) images = list(faces.dict_by_files.keys()) random.shuffle(images) counter = 0 for img in images: if counter >= 2000: print('{} images processed'.format(counter)) return -1 pkl_path = img + '.pkl' if os.path.isfile(pkl_path): with open(pkl_path, 'rb') as fid: img_label = pickle.load(fid) else: img_label = utils.IMG_LABELS(utils.get_timestamp(img)) img_label.path = img # if hasattr(img_label, 'imagga'): # rename_attribute(img_label, 'imagga', 'tags') # with open(pkl_path, 'wb') as fid: # pickle.dump(img_label, fid) if not hasattr(img_label, 'categories'): img_label.categories = [] if not hasattr(img_label, 'tags'): img_label.tags = [] if len(img_label.tags) != 0 and len(img_label.categories) != 0: print('{} already tagged'.format(img)) continue print('tagging {}'.format(img)) response = requests.post( 'https://api.imagga.com/v2/uploads', auth=(api_key, api_secret), files={'image': open(img, 'rb')}) if response.ok: image_upload_id = response.json()['result']['upload_id'] elif response.reason == 'Forbidden': print(response.text) return -1 else: print(response.text) continue if len(img_label.tags) == 0: response = requests.get( 'https://api.imagga.com/v2/tags?image_upload_id=%s' % image_upload_id, auth=(api_key, api_secret)) if response.ok: result_list = response.json()['result']['tags'] img_label.tags = [(t['tag']['en'], t['confidence']) for t in result_list if t['confidence'] > 0] counter += 1 print('ok') elif response.reason == 'Forbidden': print(response.text) return -1 else: print(response.text) continue # if len(img_label.categories) == 0: # categorizer_id = 'personal_photos' # response = requests.get( # 'https://api.imagga.com/v2/categories/%s?image_upload_id=%s' % (categorizer_id, image_upload_id), # auth=(api_key, api_secret)) # if response.ok: # result_list = response.json()['result']['categories'] # img_label.categories = [(t['name']['en'], t['confidence']) for t in result_list if t['confidence'] > 0] # counter += 1 # else: # print(response.text) # return -1 with open(pkl_path, 'wb') as fid: pickle.dump(img_label, fid)
def export_to_xmp_files(args): tmp_faces, img_labels = utils.load_img_labels(args.imgs_root) faces = utils.FACES(tmp_faces) if len(faces.dict_by_files) == 0: print('no faces loaded') exit() total_images = utils.get_images_in_dir_rec(args.imgs_root) for f in total_images: img_path = os.path.splitext(f)[0] + os.path.splitext(f)[1].lower() if os.path.dirname( img_path ) != args.mask_folder and args.mask_folder != None or img_path.lower( ).endswith('.png'): continue xmp_path = os.path.splitext(f)[0] + '.xmp' if os.path.exists(xmp_path): with open(xmp_path, 'r') as fptr: strbuffer = fptr.read() xmp = XMPMeta() xmp.parse_from_str(strbuffer) else: xmpfile = XMPFiles(file_path=f, open_forupdate=True) xmp = xmpfile.get_xmp() # print(f) kw_faces, kw_tags, kw_categories, kw_labels, kw_miscs = get_keywords( xmp) kw_tags = [] kw_categories = [] kw_miscs = [] if img_path in faces.dict_by_files: names = faces.get_names(faces.dict_by_files[img_path]) # remove detected, deleted and unknown unwanted_names = {'detected', 'deleted', 'unknown'} names = [ele for ele in names if ele not in unwanted_names] face_names = prepare_names(names, 'f ') else: # if not os.path.exists(xmp_path): # continue face_names = [] labels = [] if img_path in img_labels: if len(img_labels[img_path].tags) != 0: labels += prepare_names([ t[0].lower() for t in img_labels[img_path].tags if t[1] >= 30 ], 'l ') if len(img_labels[img_path].categories) != 0: labels += prepare_names( [c[0].lower() for c in img_labels[img_path].categories], 'l ') if hasattr(img_labels[img_path], 'gcloud_labels'): labels += prepare_names( [l.lower() for l in img_labels[img_path].gcloud_labels], 'l ') if hasattr(img_labels[img_path], 'gcloud_objects'): labels += prepare_names( [l.lower() for l in img_labels[img_path].gcloud_objects], 'l ') if hasattr(img_labels[img_path], 'gcloud_web'): labels += prepare_names( [l.lower() for l in img_labels[img_path].gcloud_web], 'l ') if hasattr(img_labels[img_path], 'gcloud_landmarks'): labels += prepare_names([ l.lower() for l in img_labels[img_path].gcloud_landmarks[::2] ], 'l ') labels = list(set(labels)) if sorted(face_names) != sorted(kw_faces) or sorted(labels) != sorted( kw_labels) or not os.path.exists(xmp_path): xmp.delete_property(consts.XMP_NS_DC, 'subject') for face in face_names: xmp.append_array_item(consts.XMP_NS_DC, 'subject', face, { 'prop_array_is_ordered': True, 'prop_value_is_array': True }) for l in labels: xmp.append_array_item(consts.XMP_NS_DC, 'subject', l, { 'prop_array_is_ordered': True, 'prop_value_is_array': True }) print('exporting file: {}'.format(os.path.basename(xmp_path))) with open(xmp_path, 'w') as fptr: fptr.write(xmp.serialize_to_str(omit_packet_wrapper=True))
def export_to_csv(args): tmp_faces, img_labels = utils.load_img_labels(args.imgs_root) faces = utils.FACES(tmp_faces) faces_csv_path = os.path.join(args.outdir, 'faces.csv') faces_input_csv_path = os.path.join(args.outdir, 'faces_exiftool.csv') if os.path.isfile(faces_input_csv_path): files_faces_csv = utils.load_faces_from_keywords_csv( faces_input_csv_path) else: files_faces_csv = None with open(faces_csv_path, 'w+') as csvfile: filewriter = csv.writer(csvfile, delimiter=',') header = ['SourceFile', 'Keywords'] # header = ['SourceFile','Subject','XPKeywords','LastKeywordXMP','LastKeywordIPTC','UserComment'] filewriter.writerow(header) if files_faces_csv != None: for f in files_faces_csv: full_path = os.path.join(args.imgs_root, f[2:]) real_image_path = getfile_sensitive(full_path) relpath = './' + os.path.relpath(real_image_path, args.imgs_root) if os.path.splitext(relpath)[1].lower() in [ '.jpg', '.png' ] and full_path not in faces.dict_by_files: row = [relpath, '-'] filewriter.writerow(row) for e, f in enumerate(faces.dict_by_files): print('{}/{}'.format(e, len(faces.dict_by_files))) if os.path.dirname( f) != args.mask_folder and args.mask_folder != None: continue real_image_path = getfile_sensitive(f) relpath = './' + os.path.relpath(real_image_path, args.imgs_root) relpath_lower = os.path.splitext(relpath)[0] + os.path.splitext( relpath)[1].lower() row = [relpath] face_names = [] tmp_faces = [] if len(faces.dict_by_files[f]) == 1: face_name = prepare_name( faces.get_face(faces.dict_by_files[f][0]).name, 'f ') tmp_faces.append(face_name) if face_name not in ['f unknown', 'f deleted']: face_names.append(face_name) else: str = '' for i in faces.dict_by_files[f]: face_name = prepare_name(faces.get_face(i).name, 'f ') if not face_name in tmp_faces and face_name not in [ 'f unknown', 'f deleted' ]: str += face_name + ',' tmp_faces.append(face_name) if str != '': face_names.append(str[:-1]) if len(face_names) != 0: if files_faces_csv != None: if relpath in files_faces_csv: if sorted(list(files_faces_csv[relpath].split( ', '))) == sorted(tmp_faces): continue elif relpath_lower in files_faces_csv: if sorted( list(files_faces_csv[relpath_lower].split( ', '))) == sorted(tmp_faces): continue row += face_names filewriter.writerow(row)