人脸对齐代码

import os
import cv2
import argparse
import numpy as np
from PIL import Image
import skimage.transform
import dlib





def get_standard_landmarks(align_size):
    # 加载 Dlib 的 5 点标准模板
    # detector = dlib.get_frontal_face_detector()
    # predictor = dlib.shape_predictor("shape_predictor_5_face_landmarks.dat")

    # Dlib 默认模板
    standard_landmarks = np.array([
        [30.2946, 51.6963],  # 左眼
        [65.5318, 51.5014],  # 右眼
        [48.0252, 71.7366],  # 鼻尖
        [33.5493, 92.3655],  # 左嘴角
        [62.7299, 92.2041]   # 右嘴角
    ], dtype=np.float32)

    # 将 landmarks 映射到目标尺寸
    return standard_landmarks * np.array(align_size) / 112.0

def load_keypoints_from_file(keypoints_file):
    """
    :param keypoints_file: dir
    :return: keypoints (numpy array, shape=(5, 2))
    """
    keypoints = []
    with open(keypoints_file, 'r') as f:
        for line in f:
            x, y = map(float, line.strip().split())
            keypoints.append((x, y))
    return np.array(keypoints, dtype=np.float32)


def get_aligned_face(image, keypoints, align_size):
    """
    :param image: 输入图像 (numpy array, RGB)
    :param keypoints: 检测到的人脸关键点 (numpy array, shape=(5, 2))
    :param align_size: 对齐后的目标尺寸 (tuple)
    :return: 对齐后的图像
    """
    # 基准点与目标尺寸匹配
    # target_keypoints = np.array([
    #     [0.34191607, 0.46157411],
    #     [0.65653393, 0.45983393],
    #     [0.500225, 0.64050536],
    #     [0.37097589, 0.82469196],
    #     [0.63151696, 0.82325089]
    # ], dtype=np.float32) * np.array(align_size)
    target_keypoints = get_standard_landmarks(align_size)

    st = skimage.transform.SimilarityTransform()   # 使用相似变换 
    st.estimate(keypoints, target_keypoints)
    aligned_face = cv2.warpAffine(          # 仿射变换图像
        image, st.params[0:2, :], (align_size[0], align_size[1]),
        flags=cv2.INTER_LINEAR, borderValue=(0, 0, 0)
    )

    # st, _ = cv2.estimateAffinePartial2D(keypoints, target_keypoints)
    # # 仿射变换图像
    # aligned_face = cv2.warpAffine(
    #     image, st, (align_size[0], align_size[1]),
    #     flags=cv2.INTER_LINEAR, borderValue=(0, 0, 0)
    # )

    return aligned_face

# align and crop images
def process_images(indir, target_size=1024, center_crop_size=700, output_size=512):
    """
    :param indir: image folder
    :param target_size: 对齐图像的目标尺寸
    :param center_crop_size: 中心裁剪尺寸
    :param output_size: 输出图像的尺寸
    """
    out_dir = os.path.join(indir, "crop")
    os.makedirs(out_dir, exist_ok=True)

    lm_dir = os.path.join(indir, "detections")
    img_files = sorted([x for x in os.listdir(indir) if x.lower().endswith(".png") or x.lower().endswith(".jpg")])
    lm_files = sorted([x for x in os.listdir(lm_dir) if x.endswith(".txt")])

    for img_file, lm_file in zip(img_files, lm_files):
        img_path = os.path.join(indir, img_file)
        lm_path = os.path.join(lm_dir, lm_file)

        im = Image.open(img_path).convert('RGB')
        im_np = np.array(im)

        keypoints = np.loadtxt(lm_path).astype(np.float32)

        # faces = detector(im_np, 1)    # detect faces
        # if len(faces) == 0:
        #     print(f"No faces detected in {img_file}. Skipping.")
        #     continue

        aligned_face = get_aligned_face(im_np, keypoints, (target_size, target_size))  # 对齐人脸
        aligned_face = Image.fromarray(aligned_face) # 转换为 PIL 图片

        # 中心裁剪
        left = max(0, int(aligned_face.size[0] / 2 - center_crop_size / 2))
        upper = max(0, int(aligned_face.size[1] / 2 - center_crop_size / 2))
        right = min(aligned_face.size[0], left + center_crop_size)
        lower = min(aligned_face.size[1], upper + center_crop_size)
        im_cropped = aligned_face.crop((left, upper, right, lower))

        # 调整为固定输出尺寸
        im_cropped = im_cropped.resize((output_size, output_size), resample=Image.LANCZOS)

        # 保存结果
        out_path = os.path.join(out_dir, img_file.split(".")[0] + ".png")
        im_cropped.save(out_path)
        print(f"Processed: {out_path}")


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--indir', type=str, required=True, help='input image folder')
    args = parser.parse_args()

    target_size = 1024
    center_crop_size = 900
    output_size = 512

    process_images(args.indir, target_size, center_crop_size, output_size)

参考代码:

https://huggingface.co/spaces/onnx/ArcFace/raw/651aecbd5380a7e0aef5f3f78bbf7e3fde601ec7/app.py

https://github.com/modelscope/facechain/blob/34d1e9976b80cf99e57c0cf2c9080c37c04958c8/face_adapter/face_preprocess.py#L36 令人叹为观止的StyleGAN - 知乎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值