python代码实现图片人脸识别以及一键覆盖图片~
本文介绍一款基于Python的人脸检测与图像处理工具,支持透明图片覆盖、动态尺寸调整及实时预览功能,适用于图像编辑、隐私保护等场景。
核心功能:
精准人脸检测
采用OpenCV Haar级联检测算法,自动识别图片中的人脸并标记红色圆圈。支持多人脸同步检测,适应不同角度和尺寸。透明图片覆盖
支持带Alpha通道的PNG文件,通过Alpha混合算法实现无白边覆盖。可自定义覆盖位置,自动适配人脸中心区域。动态尺寸调节
提供0.5x-3.0x实时缩放滑块,覆盖尺寸动态调整。智能处理边界溢出,确保放大后图片居中显示。可视化操作界面
集成Tkinter图形界面,支持一键导入/导出、实时双屏对比预览(原始图与效果图),操作反馈直观。
技术亮点:
多线程混合计算:结合OpenCV矩阵运算与PIL图像处理,兼顾效率与精度
自适应显示优化:自动按600px宽度等比缩放预览图,保持画面比例
异常处理机制:自动检测文件缺失、尺寸超限等问题并弹窗提示
操作流程:
导入基础图片 → 2. 滑动调节覆盖尺寸 → 3. 点击"覆盖"应用效果 → 4. 实时预览 → 5. 导出结果图
该工具将人脸检测与图像编辑功能结合,通过简洁的交互设计满足快速打码、创意合成等需求,可广泛应用于自媒体制作、隐私数据处理等领域。代码已开源,支持二次开发扩展。
效果如图
代码如下
import tkinter as tk
from tkinter import filedialog, ttk, messagebox
import cv2
import numpy as np
from PIL import Image, ImageTk
class FaceDetectionApp:
def __init__(self, root):
self.root = root
self.root.title("人脸检测工具")
# 初始化变量
self.original_image = None
self.processed_image = None
self.display_width = 600
self.faces = []
self.scale_factor = 1.0 # 覆盖缩放比例
# 创建界面
self.create_widgets()
def create_widgets(self):
# 控制面板
control_frame = tk.Frame(self.root)
control_frame.pack(pady=10)
# 第一行按钮
btn_row1 = tk.Frame(control_frame)
btn_row1.pack(pady=5)
self.btn_load = ttk.Button(btn_row1, text="导入图片", command=self.load_image)
self.btn_load.pack(side=tk.LEFT, padx=5)
self.btn_preview = ttk.Button(btn_row1, text="预览", command=self.preview, state=tk.DISABLED)
self.btn_preview.pack(side=tk.LEFT, padx=5)
self.btn_overlay = ttk.Button(btn_row1, text="覆盖", command=self.overlay_faces, state=tk.DISABLED)
self.btn_overlay.pack(side=tk.LEFT, padx=5)
self.btn_export = ttk.Button(btn_row1, text="导出", command=self.export_image, state=tk.DISABLED)
self.btn_export.pack(side=tk.LEFT, padx=5)
# 第二行缩放控制
scale_frame = tk.Frame(control_frame)
scale_frame.pack(pady=5)
ttk.Label(scale_frame, text="覆盖缩放:").pack(side=tk.LEFT)
self.scale = ttk.Scale(
scale_frame,
from_=0.5,
to=3.0,
value=1.0,
command=self.update_scale,
orient=tk.HORIZONTAL,
length=200
)
self.scale.pack(side=tk.LEFT, padx=5)
self.scale_label = ttk.Label(scale_frame, text="1.0x")
self.scale_label.pack(side=tk.LEFT)
# 图片显示区域
self.image_frame = tk.Frame(self.root)
self.image_frame.pack(pady=10)
self.label_original = tk.Label(self.image_frame)
self.label_original.pack(side=tk.LEFT, padx=10)
self.label_processed = tk.Label(self.image_frame)
self.label_processed.pack(side=tk.LEFT, padx=10)
def update_scale(self, value):
"""更新缩放比例"""
self.scale_factor = round(float(value), 1)
self.scale_label.config(text=f"{self.scale_factor:.1f}x")
def load_image(self):
"""加载图片"""
file_path = filedialog.askopenfilename()
if not file_path:
return
try:
image = cv2.imread(file_path)
self.original_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
self.processed_image = self.detect_faces(self.original_image.copy())
# 更新按钮状态
self.btn_preview.config(state=tk.NORMAL)
self.btn_export.config(state=tk.NORMAL)
self.btn_overlay.config(state=tk.NORMAL if len(self.faces) > 0 else tk.DISABLED)
# 自动预览
self.preview()
except Exception as e:
messagebox.showerror("错误", f"图片加载失败: {str(e)}")
def detect_faces(self, image):
"""人脸检测"""
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
self.faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5)
# 绘制检测框
for (x, y, w, h) in self.faces:
center = (x + w // 2, y + h // 2)
radius = int((w + h) // 4)
cv2.circle(image, center, radius, (255, 0, 0), 2)
return image
def overlay_faces(self):
"""覆盖透明图片"""
try:
# 加载带透明通道的图片
overlay_img = cv2.imread("0.png", cv2.IMREAD_UNCHANGED)
if overlay_img is None:
raise FileNotFoundError("找不到1.png文件")
# 分离通道
overlay_bgra = cv2.cvtColor(overlay_img, cv2.COLOR_BGRA2RGBA)
overlay_rgb = overlay_bgra[:, :, :3]
alpha = overlay_bgra[:, :, 3] / 255.0
except Exception as e:
messagebox.showerror("错误", f"覆盖图片加载失败: {str(e)}")
return
overlaid_image = self.original_image.copy()
for (x, y, w, h) in self.faces:
# 计算缩放后尺寸
scaled_w = int(w * self.scale_factor)
scaled_h = int(h * self.scale_factor)
# 计算新位置(居中)
new_x = max(0, x + (w - scaled_w) // 2)
new_y = max(0, y + (h - scaled_h) // 2)
# 调整覆盖图片
resized_overlay = cv2.resize(overlay_rgb, (scaled_w, scaled_h), interpolation=cv2.INTER_AREA)
resized_alpha = cv2.resize(alpha, (scaled_w, scaled_h), interpolation=cv2.INTER_AREA)
resized_alpha = np.expand_dims(resized_alpha, axis=-1)
# 获取目标区域
target_area = overlaid_image[new_y:new_y + scaled_h, new_x:new_x + scaled_w]
# 边界检查
if target_area.shape[0] == 0 or target_area.shape[1] == 0:
continue
# 混合图像
blended = (resized_overlay * resized_alpha) + (target_area * (1 - resized_alpha))
overlaid_image[new_y:new_y + scaled_h, new_x:new_x + scaled_w] = blended.astype(np.uint8)
self.processed_image = overlaid_image
self.preview()
def preview(self):
"""预览图片"""
if self.original_image is None or self.processed_image is None:
return
# 调整图片大小
original = self.resize_image(Image.fromarray(self.original_image))
processed = self.resize_image(Image.fromarray(self.processed_image))
# 更新显示
self.label_original.imgtk = original
self.label_original.config(image=original)
self.label_processed.imgtk = processed
self.label_processed.config(image=processed)
def resize_image(self, image):
"""调整显示尺寸"""
w, h = image.size
ratio = self.display_width / w
new_size = (self.display_width, int(h * ratio))
resized = image.resize(new_size, Image.Resampling.LANCZOS)
return ImageTk.PhotoImage(resized)
def export_image(self):
"""导出图片"""
if self.processed_image is None:
return
file_path = filedialog.asksaveasfilename(
defaultextension=".png",
filetypes=[("PNG文件", "*.png"), ("JPEG文件", "*.jpg"), ("所有文件", "*.*")]
)
if file_path:
try:
save_image = cv2.cvtColor(self.processed_image, cv2.COLOR_RGB2BGR)
cv2.imwrite(file_path, save_image)
messagebox.showinfo("成功", "图片导出成功!")
except Exception as e:
messagebox.showerror("错误", f"导出失败: {str(e)}")
if __name__ == "__main__":
root = tk.Tk()
app = FaceDetectionApp(root)
root.mainloop()


