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()