capsule AI-native Unix-like composition layer

src/models/flash_head/utils/facecrop.py

3,046 bytes · 110 lines · capsule://quake0day/[email protected] raw on github

#!/usr/bin/env python3
"""
人脸裁剪处理脚本
从单张图像中检测人脸,裁剪并调整大小到指定尺寸
"""
import os
from PIL import Image
import numpy as np

from flash_head.utils.cpu_face_handler import CPUFaceHandler

def get_scaled_bbox(
    bbox, img_w, img_h, ratio: float = 1.0, face_image: Image.Image = None
):
    """
    根据人脸边界框计算缩放后的裁剪区域
    
    Args:
        bbox: 人脸边界框 [x1, y1, x2, y2]
        img_w: 图像宽度
        img_h: 图像高度
        ratio: 缩放比例,数值越大,人脸在画面中的比例越小(周围留白越多)
        face_image: PIL Image 对象
    
    Returns:
        裁剪后的人脸图像
    """
    x1, y1, x2, y2 = bbox

    # Calculate center point
    center_x = (x1 + x2) / 2
    center_y = (y1 + y2) / 2

    # Calculate width and height
    width = x2 - x1

    # Scale width and height
    new_width = width * ratio
    new_height = new_width

    # tile pix
    dis_x_left = new_width * 0.5
    dis_x_right = new_width - dis_x_left  # 0.5new_width
    dis_y_up = new_height * 0.55
    dis_y_down = new_height - dis_y_up  # 0.45new_height

    # Calculate new coordinates
    new_x1 = int(max(0, center_x - dis_x_left))
    new_y1 = int(max(0, center_y - dis_y_up))
    new_x2 = int(min(img_w, center_x + dis_x_right))
    new_y2 = int(min(img_h, center_y + dis_y_down))
    scaled_bbox = [new_x1, new_y1, new_x2, new_y2]
    crop_face = face_image.crop(scaled_bbox)
    return crop_face


def process_image(
    input_path,
    face_ratio=2.0,
    target_size=(512, 512),
):
    """
    处理单张图像,进行人脸检测和裁剪
    
    Args:
        input_path: 输入图像路径
        face_ratio: 人脸缩放比例,建议范围:1.5-3.0,默认2.0
        target_size: 输出图像尺寸,默认(512, 512)
    
    Returns:
        imgae: 处理后的图像
    """
    # 初始化人脸检测器
    face_detector = CPUFaceHandler()
    
    # 验证输入文件
    if not os.path.isfile(input_path):
        raise ValueError(f"File not found: {input_path}")
    
    try:
        # 读取图像
        image = Image.open(input_path)
        image = image.convert("RGB")
        image_rgb = np.array(image)
        img_h, img_w = image_rgb.shape[:2]
        
        # 检测人脸
        boxes, scores = face_detector(image_rgb)
        
        if len(boxes) == 0:
            raise ValueError("No face detected")
        
        # 转换边界框坐标(从相对坐标转为绝对坐标)
        boxes_abs = [
            boxes[0][0] * img_w,
            boxes[0][1] * img_h,
            boxes[0][2] * img_w,
            boxes[0][3] * img_h
        ]
        
        # 裁剪人脸
        crop_face = get_scaled_bbox(boxes_abs, img_w, img_h, face_ratio, image)
        
        # 调整大小
        crop_face = crop_face.resize(target_size)
        
        return crop_face
            
    except Exception as e:
        raise ValueError(f"Error processing {input_path}: {e}")