def feature_writer(img_path): img_name = os.path.basename(img_path) source_img = im.open(img_path) af_obj = af.detect(source_img) # if the image has no face or you don't choose any key to detect, it will stop if not af_obj: print('{} has no face'.format(img_name)) return False af_dict = af_obj[0] hair_color = af_dict.hair.color eye_color = af_dict.right_eye.color skin_color = af_dict.skin.color feat_list = [ skin_color.r, skin_color.g, skin_color.b, hair_color.r, hair_color.g, hair_color.b, eye_color.r, eye_color.g, eye_color.b ] feat_list_norm = [value / 256 for value in feat_list] return feat_list
def cleanImagesFolder(curPath, newPath, res=None, searchFaces=False, faceThreshold=0.5): """ Creates a new folder containing all the images from the current folder with anime faces on them, using the animeface library """ createDir(newPath) images = glob(os.path.join(curPath, '*.jpg')) for image in images: try: im = Image.open(image) if res != None: if min(im.size) < res: continue if searchFaces: faces = animeface.detect(im) if not faces: continue #Get rid of garbage if (faces[0].likelihood < faceThreshold): continue #Get rid of garbage imName = image.split('/')[-1] newImage = os.path.join(newPath, imName) copyfile(image, newImage) except OSError: continue
def find_face(img_path, parts=['face', 'eye']): img_name = os.path.basename(img_path) source_img = im.open(img_path) af_obj = af.detect(source_img) # if the image has no face or you don't choose any key to detect, it will stop if not af_obj or not parts: print('{} has no face'.format(img_name)) return 1 af_dict = af_obj[0] x, y, width, height = af_dict.face.pos.x, af_dict.face.pos.y, af_dict.face.pos.width, af_dict.face.pos.height draw = dr.Draw(source_img) if af_dict.likelihood < 0.9: return 1 draw.rectangle(((x - 1, y - 1), (x + width - 1, y + height - 1)), outline="rgb(160, 240, 60)") draw.rectangle(((x, y), (x + width, y + height)), outline="rgb(160, 240, 60)") draw.rectangle(((x + 1, y + 1), (x + width + 1, y + height + 1)), outline="rgb(160, 240, 60)") draw.text((x, y), 'face') draw.text((2, 0), 'L={0:03f}'.format(af_dict.likelihood)) b_x, b_y = 0, 10 hair_color = af_dict.hair.color draw.rectangle(((b_x, b_y), (b_x + 10, b_y + 10)), fill=(hair_color.r, hair_color.g, hair_color.b), outline='white') draw.text((b_x + 12, b_y), 'hair_color') eye_color = af_dict.right_eye.color draw.rectangle(((b_x, b_y + 10), (b_x + 10, b_y + 20)), fill=(eye_color.r, eye_color.g, eye_color.b), outline='white') draw.text((b_x + 12, b_y + 10), 'eye_color') if 'eye' in parts: eye_pos = af_dict.right_eye.pos x, y, width, height = af_dict.right_eye.pos.x, af_dict.right_eye.pos.y, af_dict.right_eye.pos.width, af_dict.right_eye.pos.height draw.rectangle(((x, y), (x + width, y + height)), outline="rgb(160, 240, 60)") eye_pos = af_dict.left_eye.pos x, y, width, height = af_dict.left_eye.pos.x, af_dict.left_eye.pos.y, af_dict.left_eye.pos.width, af_dict.left_eye.pos.height draw.rectangle(((x, y), (x + width, y + height)), outline="rgb(160, 240, 60)") #text shadows the face too much #draw.text((x,y), 'right_eye') if not os.path.exists(config.save_path): os.mkdir(config.save_path) source_img.save(os.path.join(config.save_path, '{}'.format(img_name)), 'JPEG') return 0
def face_detect(img): """ Returns an animeface object. If more than one face detected, only the largest and most plausible face will be used. Returns one face object. If no face objects found, returns false. Parameters: img: cv2 image """ faces = animeface.detect(util.convert_cv2_to_pil_image(img)) if (len(faces) == 0): return False return faces[0]
def mlp_anime_face_detect(image_path): img = cv2.imread(image_path) if type(image_path)==str else image_path # 读取图片 img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 图片灰度化 img_gray = cv2.equalizeHist(img_gray) # 直方图均衡化 faces = animeface.detect(Image.fromarray(img_gray)) # 人脸检测 for each in faces: # 遍历所有检测到的动漫脸 temp = each.face.pos x = temp.x y = temp.y w = temp.width h = temp.height img = cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 255), 5) # 绘制矩形框 # cv2.imwrite(f'../result/mlp_anime_face_detect_{image_path[-5]}.jpg', img) # 保存检测结果 return img
def run_face_detection_with_python_animeface(input_image_path): res = [] im = PIL.Image.open(input_image_path) faces = animeface.detect(im) for ff in faces: with tempfile.NamedTemporaryFile(delete=False) as temp_ff: temp_im = im.crop(( ff.face.pos.x, ff.face.pos.y, ff.face.pos.x + ff.face.pos.width, ff.face.pos.y + ff.face.pos.height, )) name = '{}.jpg'.format(temp_ff.name) temp_im.save(name) res.append(name) return res
def get_face_landmarks(image): faceboxes = animeface.detect(image) assert len(faceboxes) == 1, "Face detector couldn't find one and only one face on the image." facebox = faceboxes[0] left_eye_center = (int(facebox.left_eye.pos.x + facebox.left_eye.pos.width / 2), int(facebox.left_eye.pos.y + facebox.left_eye.pos.height / 2)) right_eye_center = (int(facebox.right_eye.pos.x + facebox.right_eye.pos.width / 2), int(facebox.right_eye.pos.y + facebox.right_eye.pos.height / 2)) eye_center = tuple(np.average([left_eye_center, right_eye_center], axis=0).astype(int)) return { 'left-eye-center-pos': left_eye_center, 'right-eye-center-pos': right_eye_center, 'eye-center-pos': eye_center, 'face-box': (facebox.face.pos.x, facebox.face.pos.y, facebox.face.pos.width, facebox.face.pos.height) }
def load_detect(img_path): """Read original image file, return the cropped face image in the size 96x96 Input: A string indicates the image path Output: Detected face image in the size 96x96 Note that there might be multiple faces in one image, the output crossponding to the face with highest probability """ im = Image.open(img_path) faces = animeface.detect(im) prob_list = [] len_f = len(faces) if len_f == 0: return 0 for i in range(len_f): prob_list.append(faces[i].likelihood) prob_array = np.array(prob_list) idx = np.argmax(prob_array) face_pos = faces[idx].face.pos im = faceCrop(im, face_pos, 0.5) return min_resize_crop(im, 96)
def split_fp(im): ''' This function take image array: im(np.array). In detail, animeface API was applied to extract the coordinates of the four corners of anime face inside of this image. Return value(np.array): coordinates of the four corners of anime face inside of this image. ''' faces = animeface.detect(im) if faces == []: return False else: fp = faces[0].face.pos list_1 = str(fp).split(';') list_1_1 = str(list_1[0]).split('(') list_1_2 = str(list_1[1]).split(')') list_1_1_1 = str(list_1_1[1]).split(',') list_1_2_1 = str(list_1_2[0]).split(',') list_final = [int(list_1_1_1[1]), int(list_1_1_1[1])+int(list_1_2_1[1]), int(list_1_1_1[0]), int(list_1_1_1[0])+int(list_1_2_1[0])] return np.array(list_final)
def crop_face(fn): filename = os.path.join(IMG_PATH, fn) im = PIL.Image.open(filename) faces = animeface.detect(im) if len(faces) != 1: return None image = cv2.imread(filename, cv2.IMREAD_COLOR) def imcrop(img, bbox): x1, y1, x2, y2 = bbox if x1 < 0 or y1 < 0 or x2 > img.shape[1] or y2 > img.shape[0]: img, x1, x2, y1, y2 = pad_img_to_fit_bbox(img, x1, x2, y1, y2) return img[y1:y2, x1:x2, :] def pad_img_to_fit_bbox(img, x1, x2, y1, y2): img = np.pad( img, ((np.abs(np.minimum(0, y1)), np.maximum(y2 - img.shape[0], 0)), (np.abs(np.minimum(0, x1)), np.maximum(x2 - img.shape[1], 0)), (0, 0)), mode="constant", constant_values=255) y1 += np.abs(np.minimum(0, y1)) y2 += np.abs(np.minimum(0, y1)) x1 += np.abs(np.minimum(0, x1)) x2 += np.abs(np.minimum(0, x1)) return img, x1, x2, y1, y2 for face in faces: L_x = face.left_eye.pos.x + face.left_eye.pos.height // 2 L_y = face.left_eye.pos.y + face.left_eye.pos.width // 2 R_x = face.right_eye.pos.x + face.right_eye.pos.height // 2 R_y = face.right_eye.pos.y + face.right_eye.pos.width // 2 dx = L_x - R_x dy = L_y - R_y deg = math.atan(dy / dx) * 360 / (2 * math.pi) if math.fabs(deg) > 60: deg = 0.0 # something wrong??? print(dx, dy, deg) x = face.face.pos.x y = face.face.pos.y w = face.face.pos.width h = face.face.pos.height cx = x + h // 2 cy = y + w // 2 image = np.pad(image, ((2 * x, 2 * x), (2 * y, 2 * y), (0, 0)), mode="constant", constant_values=255) rows, cols, _ = image.shape M = cv2.getRotationMatrix2D((0 / 2, 0 / 2), deg, 1) image = cv2.warpAffine(image, M, (cols, rows), borderValue=(255, 255, 255), flags=cv2.INTER_CUBIC) faces = animeface.detect(PIL.Image.fromarray(image)) if len(faces) != 1: continue face = faces[0] x = face.face.pos.x y = face.face.pos.y w = face.face.pos.width + 10 h = face.face.pos.height + 10 chinx = face.chin.pos.x chiny = face.chin.pos.y cx = x + h // 2 cy = y + w // 2 d = h cy = chiny - d + d // 3 if cy - d < 0: cy -= (cy - d) // 2 image = imcrop(image, (cx - d, cy - d, cx + d, cy + d)) cv2.imwrite(os.path.join(FINAL_IMG_PATH, fn), image)
# data scraping from the web , install the data below packages and run the commands to download the data !pip install --upgrade gallery-dl !pip install animeface !gallery-dl https://danbooru.donmai.us/posts?tags=face import animeface total_num_faces = 0 for index,filename in enumerate(glob.glob('your data path')): print(filename) try: im = Image.open(filename) faces = animeface.detect(im) except Exception as e: print("Exception:{}".format(e)) continue if len(faces) == 0: print("no faces found") continue fp = faces[0].face.pos coordinates = (fp.x,fp.y,fp.x+fp.width,fp.y+fp.height) cropped_image = im.crop(coordinates) cropped_image = cropped_image.resize((64,64),Image.ANTIALIAS) cropped_image.save("{}".format(filename))
face_cascade = cv2.CascadeClassifier( r"/code/cascaders/lbpcascade_animeface.xml") i = 1 for file in files: if os.path.isdir(file): continue print(path + file) img = cv2.imread(path + file) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) face_rects = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=3, minSize=(100, 100)) for (x, y, w, h) in face_rects: cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2) im = PIL.Image.open(path + file) gray = ImageOps.grayscale(im) faces = animeface.detect(gray) for face in faces: x = face.face.pos.x y = face.face.pos.y w = face.face.pos.width h = face.face.pos.height cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2) cv2.imwrite(r"/code/data/face/" + str(i) + ".jpg", img) i += 1
def get_faces(img, db_session=None, c_model=None): detector_name = 'python_animeface' create_a_new_face_model = False af_faces = animeface.detect(img) for ff in af_faces: face_model = None pos = vars(ff.face.pos) # NOQA color_tags = { key: value.color for key, value in vars(ff).items() if hasattr(value, 'color') } face_dict = { 'detector': detector_name, 'pos': ff.face.pos, 'likelihood': ff.likelihood, 'colors': color_tags, } if db_session and c_model and c_model.faces: # search any existing faces for ff_model in c_model.faces: same_coordinate = [x for x in pos.values() ] == list(ff_model.pos()) if same_coordinate and ff_model.method == detector_name: face_model = ff_model break # update or create face_model if face_model: face_model.likelihood = ff.likelihood # update color tags on face # by removing existing color vlaue c_tag_list = [] for color_m in face_model.color_tags: if color_m.value not in color_tags.values(): c_tag_list.append(color_m) for key, value in color_tags.items(): color_m, _ = models.get_or_create( db_session, models.ColorTag, value=key, color_value=get_hex_value(value.r, value.g, value.b)) db_session.add(color_m) c_tag_list.append(color_m) db_session.add(face_model) face_model.color_tags = c_tag_list else: create_a_new_face_model = True elif db_session and c_model: create_a_new_face_model = True if create_a_new_face_model: face_model = models.Face(checksum=c_model, method=detector_name, likelihood=ff.likelihood) for key, value in pos.items(): setattr(face_model, 'pos_{}'.format(key), value) for key, value in color_tags.items(): color_m, _ = models.get_or_create(db_session, models.ColorTag, value=key, color_value=get_hex_value( value.r, value.g, value.b)) face_model.color_tags.append(color_m) db_session.add(color_m) db_session.add(face_model) yield [face_dict, face_model]