Spaces:
Paused
Paused
| import cv2 | |
| import math | |
| import argparse | |
| import numpy as np | |
| import os | |
| # detect face | |
| def highlightFace(net, frame, conf_threshold=0.95): | |
| frameOpencvDnn = frame.copy() | |
| frameHeight = frameOpencvDnn.shape[0] | |
| frameWidth = frameOpencvDnn.shape[1] | |
| blob = cv2.dnn.blobFromImage( | |
| frameOpencvDnn, 1.0, (300, 300), [104, 117, 123], True, False | |
| ) | |
| net.setInput(blob) | |
| detections = net.forward() | |
| faceBoxes = [] | |
| for i in range(detections.shape[2]): | |
| confidence = detections[0, 0, i, 2] | |
| if confidence > conf_threshold: | |
| x1 = int(detections[0, 0, i, 3] * frameWidth) | |
| y1 = int(detections[0, 0, i, 4] * frameHeight) | |
| x2 = int(detections[0, 0, i, 5] * frameWidth) | |
| y2 = int(detections[0, 0, i, 6] * frameHeight) | |
| faceBoxes.append(scale([x1, y1, x2, y2])) | |
| return faceBoxes | |
| # scale current rectangle to box | |
| def scale(box): | |
| width = box[2] - box[0] | |
| height = box[3] - box[1] | |
| maximum = max(width, height) | |
| dx = int((maximum - width) / 2) | |
| dy = int((maximum - height) / 2) | |
| bboxes = [box[0] - dx, box[1] - dy, box[2] + dx, box[3] + dy] | |
| return bboxes | |
| # crop image | |
| def cropImage(image, box): | |
| num = image[box[1] : box[3], box[0] : box[2]] | |
| return num | |
| # main | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument("-i", "--image", type=str, required=False, help="input image") | |
| args = parser.parse_args() | |
| # 创建输出目录 | |
| output_dir = "../output" | |
| if not os.path.exists(output_dir): | |
| os.makedirs(output_dir) | |
| faceProto = "models/opencv_face_detector.pbtxt" | |
| faceModel = "models/opencv_face_detector_uint8.pb" | |
| ageProto = "models/age_googlenet.prototxt" | |
| ageModel = "models/age_googlenet.caffemodel" | |
| genderProto = "models/gender_googlenet.prototxt" | |
| genderModel = "models/gender_googlenet.caffemodel" | |
| beautyProto = "models/beauty_resnet.prototxt" | |
| beautyModel = "models/beauty_resnet.caffemodel" | |
| MODEL_MEAN_VALUES = (104, 117, 123) | |
| ageList = [ | |
| "(0-2)", | |
| "(4-6)", | |
| "(8-12)", | |
| "(15-20)", | |
| "(25-32)", | |
| "(38-43)", | |
| "(48-53)", | |
| "(60-100)", | |
| ] | |
| genderList = ["Male", "Female"] | |
| # 定义性别对应的颜色 (BGR格式) | |
| gender_colors = { | |
| "Male": (255, 165, 0), # 橙色 Orange | |
| "Female": (255, 0, 255), # 洋红 Magenta / Fuchsia | |
| } | |
| faceNet = cv2.dnn.readNet(faceModel, faceProto) | |
| ageNet = cv2.dnn.readNet(ageModel, ageProto) | |
| genderNet = cv2.dnn.readNet(genderModel, genderProto) | |
| beautyNet = cv2.dnn.readNet(beautyModel, beautyProto) | |
| # 读取图片 | |
| image_path = args.image if args.image else "images/charlize.jpg" | |
| frame = cv2.imread(image_path) | |
| if frame is None: | |
| print(f"无法读取图片: {image_path}") | |
| exit() | |
| faceBoxes = highlightFace(faceNet, frame) | |
| if not faceBoxes: | |
| print("No face detected") | |
| exit() | |
| print(f"检测到 {len(faceBoxes)} 张人脸") | |
| for i, faceBox in enumerate(faceBoxes): | |
| # 提取人脸区域 | |
| face = cropImage(frame, faceBox) | |
| face_resized = cv2.resize(face, (224, 224)) | |
| # gender net | |
| blob = cv2.dnn.blobFromImage( | |
| face_resized, 1.0, (224, 224), MODEL_MEAN_VALUES, swapRB=False | |
| ) | |
| genderNet.setInput(blob) | |
| genderPreds = genderNet.forward() | |
| gender = genderList[genderPreds[0].argmax()] | |
| print(f"Gender: {gender}") | |
| # age net | |
| ageNet.setInput(blob) | |
| agePreds = ageNet.forward() | |
| age = ageList[agePreds[0].argmax()] | |
| print(f"Age: {age[1:-1]} years") | |
| # beauty net | |
| blob = cv2.dnn.blobFromImage( | |
| face_resized, 1.0 / 255, (224, 224), MODEL_MEAN_VALUES, swapRB=False | |
| ) | |
| beautyNet.setInput(blob) | |
| beautyPreds = beautyNet.forward() | |
| beauty = round(2.0 * sum(beautyPreds[0]), 1) | |
| print(f"Beauty: {beauty}/10.0") | |
| # 根据性别选择颜色 | |
| color = gender_colors[gender] | |
| # 保存人脸图片 - 使用cv2.imwrite | |
| face_filename = f"{output_dir}/face_{i+1}.webp" | |
| cv2.imwrite(face_filename, face, [cv2.IMWRITE_WEBP_QUALITY, 95]) | |
| print(f"人脸图片已保存: {face_filename}") | |
| # 保存评分到图片上(可选) | |
| face_with_text = face.copy() | |
| cv2.putText( | |
| face_with_text, f"{gender}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, color, 2 | |
| ) | |
| cv2.putText( | |
| face_with_text, | |
| f"{age[1:-1]} years", | |
| (10, 60), | |
| cv2.FONT_HERSHEY_SIMPLEX, | |
| 0.7, | |
| color, | |
| 2, | |
| ) | |
| cv2.putText( | |
| face_with_text, | |
| f"{beauty}/10.0", | |
| (10, 90), | |
| cv2.FONT_HERSHEY_SIMPLEX, | |
| 0.7, | |
| color, | |
| 2, | |
| ) | |
| annotated_filename = f"{output_dir}/face_{i+1}_annotated.webp" | |
| cv2.imwrite(annotated_filename, face_with_text, [cv2.IMWRITE_WEBP_QUALITY, 95]) | |
| print(f"标注人脸已保存: {annotated_filename}") | |
| # 在原图上绘制人脸框和信息 | |
| cv2.rectangle( | |
| frame, | |
| (faceBox[0], faceBox[1]), | |
| (faceBox[2], faceBox[3]), | |
| color, | |
| int(round(frame.shape[0] / 400)), | |
| 8, | |
| ) | |
| cv2.putText( | |
| frame, | |
| f"{gender}, {age}, {beauty}", | |
| (faceBox[0], faceBox[1] - 10), | |
| cv2.FONT_HERSHEY_SIMPLEX, | |
| 1.25, | |
| color, | |
| 2, | |
| cv2.LINE_AA, | |
| ) | |
| # 保存完整的标注图片 | |
| result_filename = f"{output_dir}/result_full.webp" | |
| cv2.imwrite(result_filename, frame, [cv2.IMWRITE_WEBP_QUALITY, 95]) | |
| print(f"完整结果图片已保存: {result_filename}") | |
| # 显示图片 | |
| cv2.imshow("howbeautifulami", frame) | |
| cv2.waitKey(0) | |
| cv2.destroyAllWindows() | |