首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >让图片眨眼睛的软件,人脸识别照片眨眼软件,照片眨眼python生成器

让图片眨眼睛的软件,人脸识别照片眨眼软件,照片眨眼python生成器

原创
作者头像
用户11719788
发布2025-07-02 11:50:56
发布2025-07-02 11:50:56
5520
举报

下载地址:http://m.pan38.com/download.php?code=MDADTF 访问密码(可选):6666

图片眨眼动画生成功能,包含人脸检测、关键点定位、图像变形和GIF生成。使用时需要先下载dlib的68点人脸形状预测器。代码通过Delaunay三角剖分实现自然的眼部变形效果,可以生成平滑的眨眼动画。

代码语言:txt
复制

import cv2
import dlib
import numpy as np
from PIL import Image
from scipy.spatial import Delaunay
from matplotlib import pyplot as plt
import os
import time
from tqdm import tqdm
import argparse

class FaceBlinkGenerator:
    def __init__(self, predictor_path="shape_predictor_68_face_landmarks.dat"):
        self.detector = dlib.get_frontal_face_detector()
        self.predictor = dlib.shape_predictor(predictor_path)
        self.eye_indices = {
            'left': list(range(36, 42)),
            'right': list(range(42, 48))
        }
        self.blink_frames = 5
        
    def load_image(self, image_path):
        image = cv2.imread(image_path)
        if image is None:
            raise ValueError(f"无法加载图像: {image_path}")
        return cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    
    def detect_face(self, image):
        gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
        faces = self.detector(gray)
        if len(faces) == 0:
            raise ValueError("未检测到人脸")
        return faces[0]
    
    def get_landmarks(self, image, face):
        landmarks = self.predictor(image, face)
        return np.array([(landmarks.part(i).x, landmarks.part(i).y) 
                        for i in range(68)], dtype=np.int32)
    
    def create_eye_mask(self, landmarks, eye_type):
        indices = self.eye_indices[eye_type]
        eye_points = landmarks[indices]
        
        hull = cv2.convexHull(eye_points)
        mask = np.zeros_like(image[:, :, 0])
        cv2.fillConvexPoly(mask, hull, 255)
        
        return mask, eye_points
    
    def interpolate_eye(self, upper, lower, progress):
        middle = (1 - progress) * upper + progress * lower
        return middle.astype(np.int32)
    
    def generate_blink_sequence(self, image, landmarks):
        height, width = image.shape[:2]
        frames = []
        
        # 获取左右眼关键点
        left_mask, left_points = self.create_eye_mask(landmarks, 'left')
        right_mask, right_points = self.create_eye_mask(landmarks, 'right')
        
        # 计算闭眼时的位置(上下眼睑合并)
        left_upper = left_points[:3]
        left_lower = np.vstack([left_points[4], left_points[3], left_points[5]])
        
        right_upper = right_points[:3]
        right_lower = np.vstack([right_points[4], right_points[3], right_points[5]])
        
        # 生成眨眼动画序列
        for i in range(self.blink_frames):
            progress = i / (self.blink_frames - 1)
            if i < self.blink_frames // 2:
                # 闭眼过程
                progress = 2 * progress
            else:
                # 睁眼过程
                progress = 2 * (1 - progress)
                
            # 插值计算中间状态
            left_inter = self.interpolate_eye(left_upper, left_lower, progress)
            right_inter = self.interpolate_eye(right_upper, right_lower, progress)
            
            # 创建新关键点数组
            new_landmarks = landmarks.copy()
            new_landmarks[36:42] = left_inter
            new_landmarks[42:48] = right_inter
            
            # 生成新图像
            warped = self.warp_image(image, landmarks, new_landmarks)
            frames.append(warped)
            
        return frames
    
    def warp_image(self, img, src_points, dst_points):
        h, w = img.shape[:2]
        
        # 计算Delaunay三角剖分
        tri = Delaunay(src_points)
        triangles = src_points[tri.simplices]
        
        # 创建空白图像
        warped = np.zeros_like(img)
        
        for triangle in triangles:
            # 获取源三角形和目标三角形
            src_tri = np.float32([src_points[i] for i in tri.simplices[0]])
            dst_tri = np.float32([dst_points[i] for i in tri.simplices[0]])
            
            # 计算仿射变换
            transform = cv2.getAffineTransform(src_tri, dst_tri)
            
            # 应用变换
            warped_triangle = cv2.warpAffine(img, transform, (w, h), 
                                           flags=cv2.INTER_LINEAR, 
                                           borderMode=cv2.BORDER_REFLECT_101)
            
            # 创建三角形mask
            mask = np.zeros((h, w), dtype=np.uint8)
            cv2.fillConvexPoly(mask, np.int32(dst_tri), 255)
            
            # 将三角形合并到结果图像
            warped = cv2.bitwise_or(warped, cv2.bitwise_and(warped_triangle, 
                                                           warped_triangle, 
                                                           mask=mask))
        
        # 混合原始图像和变形图像
        alpha = 0.7
        result = cv2.addWeighted(img, 1-alpha, warped, alpha, 0)
        return result
    
    def save_gif(self, frames, output_path, duration=100):
        pil_images = [Image.fromarray(frame) for frame in frames]
        pil_images[0].save(output_path, save_all=True, 
                          append_images=pil_images[1:], 
                          duration=duration, loop=0)
    
    def process_image(self, image_path, output_path):
        try:
            image = self.load_image(image_path)
            face = self.detect_face(image)
            landmarks = self.get_landmarks(image, face)
            frames = self.generate_blink_sequence(image, landmarks)
            self.save_gif(frames, output_path)
            return True
        except Exception as e:
            print(f"处理图像时出错: {str(e)}")
            return False

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='生成眨眼动画')
    parser.add_argument('input', help='输入图片路径')
    parser.add_argument('output', help='输出GIF路径')
    parser.add_argument('--predictor', default='shape_predictor_68_face_landmarks.dat',
                       help='dlib形状预测器路径')
    
    args = parser.parse_args()
    
    generator = FaceBlinkGenerator(args.predictor)
    if generator.process_image(args.input, args.output):
        print(f"成功生成眨眼动画: {args.output}")
    else:
        print("生成失败")
代码语言:txt
复制
umpy==1.23.5
opencv-python==4.7.0.72
dlib==19.24.2
pillow==9.4.0
scipy==1.10.1
matplotlib==3.7.1
tqdm==4.65.0
argparse==1.4.0
代码语言:txt
复制
import unittest
import os
import tempfile
from blink_generator import FaceBlinkGenerator

class TestBlinkGenerator(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.test_image = "test_face.jpg"
        cls.predictor = "shape_predictor_68_face_landmarks.dat"
        cls.generator = FaceBlinkGenerator(cls.predictor)
        
    def test_load_image(self):
        image = self.generator.load_image(self.test_image)
        self.assertIsNotNone(image)
        
    def test_detect_face(self):
        image = self.generator.load_image(self.test_image)
        face = self.generator.detect_face(image)
        self.assertIsNotNone(face)
        
    def test_generate_blink(self):
        with tempfile.NamedTemporaryFile(suffix='.gif', delete=False) as tmp:
            output_path = tmp.name
            
        success = self.generator.process_image(self.test_image, output_path)
        self.assertTrue(success)
        self.assertTrue(os.path.exists(output_path))
        self.assertGreater(os.path.getsize(output_path), 0)
        
        os.unlink(output_path)

if __name__ == '__main__':
    unittest.main()

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
作者已关闭评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档