最近在短视频平台刷到不少“真人版茄子鬼”的 cos 创意很多人都好奇这种紫色幽灵质感是怎么做出来的。看视频时觉得后期很复杂但其实用 Python 写一个实时的风格化滤镜并不难核心就是人脸关键点检测 HSV 颜色空间映射 光晕合成。本文就把整个实现过程拆开从环境准备到源码运行再到常见报错排查完整地记录下来。无论你是想复刻青霧cos那种“真人变角色”的视觉张力还是单纯想练一练图像处理这篇教程都能直接用起来。1. 背景与核心概念1.1 什么是“真人版茄子鬼”特效“茄子鬼”其实可以拆成两个视觉关键词茄子的紫色以及鬼魂的发光半透明感。真人版茄子鬼就是把真实拍摄的人像素材通过后期处理让人物面部和整体氛围向“紫色幽灵”方向靠拢从而产生一种介于真人实拍和二次元角色之间的视觉效果。传统做法是在 After Effects、剪映、Photoshop 里手动做蒙版、调色、加光晕。这么做的好处是可控性强但缺点也很明显处理一段视频需要一帧一帧地调参时间成本高且很难实时输出。如果只是拍一张照片还好要是想直播或者录短视频手动后期就非常吃力了。而用 OpenCV MediaPipe 这类开发库可以把“人脸区域定位、肤色偏紫、边缘发光”这些步骤全部自动化在普通笔记本上也能做到接近实时的处理。代码写好后不管是单张图片、摄像头实时画面还是视频文件都可以直接复用。1.2 为什么选择 Python OpenCV MediaPipeOpenCVOpen Source Computer Vision Library是最流行的开源计算机视觉库提供了大量图像处理和视频处理接口比如颜色空间转换、形态学操作、高斯模糊、图像叠加等。MediaPipe 是 Google 开源的跨平台多媒体机器学习框架其中 FaceMesh 模型可以在画面中定位人脸 468 个关键点覆盖额头、眼睛、鼻子、嘴巴、脸颊和脸部轮廓。有了这些关键点我们就可以生成一个精确的人脸遮罩只对人脸区域做特效而不是把整张背景都变成紫色。选择这套技术栈有几点考虑环境轻量普通电脑都能跑不需要 GPU。生态成熟OpenCV 和 MediaPipe 都有现成的包安装简单。方便二次开发处理后可以继续接入其他算法比如表情识别、虚拟形象驱动、直播推流等。成本低不依赖商用特效软件适合个人开发者和爱好者。1.3 需要掌握的核心术语在阅读下文之前先简单说明几个关键概念BGR / RGBOpenCV 默认使用 BGR 颜色顺序而其他很多库使用 RGB转换时要格外注意。HSV色调Hue、饱和度Saturation、明度Value颜色空间。调整 H 可以改变颜色偏向调整 S 可以让颜色更鲜艳调整 V 可以改变亮度。Face Landmark人脸关键点表示眉毛、眼睛、鼻子、嘴、下巴等位置的坐标。Mask遮罩一张黑白的图像白色区域表示需要处理的部分黑色区域表示需要保留的部分。凸包Convex Hull将一堆点包起来的最小凸多边形用于生成人脸轮廓。Gaussian Blur高斯模糊可以让遮罩边缘更加柔和避免后期出现明显的硬边。2. 环境准备与版本说明2.1 运行环境本文示例以 Python 3.9~3.11 为主。Python 3.12 以上虽然很多库已经支持但 MediaPipe 部分版本可能出现安装或导入问题建议优先使用 3.10 或 3.11。操作系统推荐 Windows 10/11、Ubuntu 20.04 或 macOS 12。摄像头方面笔记本电脑自带摄像头即可也可以使用 USB 外接摄像头。如果没有摄像头可以先使用静态图片版本练习或者准备一段视频文件。需要安装的 Python 库如下pip install opencv-python mediapipe numpy如果想保存视频还可以安装pip install opencv-python-mediapipe不过上面这个包名不一定每个版本都有保持opencv-python就足够。建议把依赖写入 requirements.txt方便以后重建环境# requirements.txt opencv-python4.8.1.78 mediapipe0.10.9 numpy1.24.3需要注意OpenCV、MediaPipe、NumPy 之间有时存在版本兼容问题。如果安装时出现依赖冲突可以创建一个全新的虚拟环境再安装。例如python -m venv venv source venv/bin/activate # Windows 下使用 venv\Scripts\activate pip install -r requirements.txt2.2 项目目录结构建议把项目文件组织成下面的结构eggplant_ghost/ ├── input_images/ # 存放待处理的图片 ├── output_images/ # 存放处理后的图片 ├── eggplant_ghost_image.py # 静态图片风格化 ├── eggplant_ghost_camera.py # 摄像头实时风格化 ├── batch_process.py # 批量处理图片 └── requirements.txt # 依赖清单这样的好处是代码、输入输出、依赖分离后续扩展也不容易混乱。3. 核心原理拆解3.1 人脸关键点检测MediaPipe FaceMesh 的输入是一张 RGB 图像输出是归一化的人脸关键点坐标。所谓归一化是指关键点的 x 和 y 坐标都在 0 到 1 之间需要乘以图像的宽和高才能得到真实像素坐标。使用 FaceMesh 的基本流程如下import cv2 import mediapipe as mp mp_face_mesh mp.solutions.face_mesh face_mesh mp_face_mesh.FaceMesh( static_image_modeTrue, max_num_faces1, refine_landmarksTrue, min_detection_confidence0.5 ) rgb cv2.cvtColor(image, cv2.COLOR_BGR2RGB) results face_mesh.process(rgb)得到results.multi_face_landmarks后里面每一组都是 468 个关键点。我们可以取所有关键点的坐标用cv2.convexHull计算一个覆盖整张脸的最小凸多边形再通过cv2.fillConvexPoly生成一张人脸遮罩图。这里有一个容易踩的坑OpenCV 默认使用 BGR 色彩空间而 MediaPipe 需要 RGB。很多人忘记转换导致检测结果不稳定或检测不到人脸。3.2 HSV 颜色空间与“茄子紫”调色为什么调色不直接修改 BGR 三个通道因为 BGR 三个分量关联性太强直接改 B 和 R 很难控制颜色偏移方向。HSV 把颜色分成色调、饱和度、明度三个独立维度改起来更直观。在 OpenCV 中HSV 的 H 范围是 0 到 179S 和 V 范围是 0 到 255。紫色对应的 H 大概在 130 到 170 之间。皮肤原本的色调大约在 10 到 25 之间所以我们需要把 H 值加上一个偏移量比如加 120 到 140让肤色整体跳到紫色区域。同时为了更接近“茄子”那种浓郁的感觉可以把饱和度提高再稍微降低亮度。核心代码如下hsv cv2.cvtColor(image, cv2.COLOR_BGR2HSV).astype(np.float32) hsv[..., 0] (hsv[..., 0] 125) % 180 hsv[..., 1] np.clip(hsv[..., 1] 45, 0, 255) hsv[..., 2] np.clip(hsv[..., 2] - 10, 0, 255) purple cv2.cvtColor(hsv.astype(np.uint8), cv2.COLOR_HSV2BGR)为什么先转成float32因为后面要做加法和减法如果用uint8可能会在边界处产生溢出或截断导致颜色出现异常跳变。先转浮点处理完再转回uint8是更稳妥的写法。3.3 遮罩融合与外发光人脸遮罩可以直接用fillConvexPoly生成。但是直接用二值遮罩做像素替换脸部边缘会特别生硬看起来像贴了一张紫色纸片。解决方法是把遮罩做一次高斯模糊将硬边变成渐进过渡的 alpha 通道。公式可以理解为输出 原图 × (1 - alpha) 紫色变体图 × alphaalpha 是 0 到 1 之间的浮点数边缘处自然过渡。外发光效果可以通过cv2.dilate先扩张人脸遮罩再做更强烈的高斯模糊然后把扩张区域的紫色半透明叠加到最终结果上。这样脸部周围就会有一圈淡淡的紫光比较接近“幽灵”的感觉。3.4 视频流处理整体流程实时摄像头处理其实就是在视频循环里重复执行以下步骤从摄像头读取一帧 BGR 图像。镜像翻转方便自拍视角。转换颜色空间调用 MediaPipe 检测人脸关键点。根据关键点生成人脸遮罩。在 HSV 空间调整颜色生成紫色版本。通过 alpha 混合完成人脸区域风格化。叠加外发光。显示画面并等待按键退出。整个流程的耗时主要被人脸检测占据。MediaPipe 在 CPU 上每帧大约需要 20 到 40 毫秒整体可以做到 25 帧左右已经能满足实时预览需求。4. 完整实战案例4.1 静态图片风格化先写一个最简单的静态图片版本方便在没有摄像头的时候快速预览效果。新建eggplant_ghost_image.py完整代码如下# eggplant_ghost_image.py import cv2 import numpy as np import mediapipe as mp mp_face_mesh mp.solutions.face_mesh face_mesh mp_face_mesh.FaceMesh( static_image_modeTrue, max_num_faces1, refine_landmarksTrue, min_detection_confidence0.5 ) def get_face_mask(image, landmarks): 根据人脸关键点生成凸包遮罩 h, w image.shape[:2] points [] for lm in landmarks: x int(lm.x * w) y int(lm.y * h) points.append([x, y]) pts np.array(points, dtypenp.int32).reshape(-1, 1, 2) mask np.zeros((h, w), dtypenp.uint8) cv2.fillConvexPoly(mask, pts, 255) return mask def eggplant_ghost_effect(image, hue_shift125, sat_boost45, val_drop10, edge_smooth31): 将图片中的人脸区域调整为茄子紫幽灵风格 # 1. HSV 空间偏色 hsv cv2.cvtColor(image, cv2.COLOR_BGR2HSV).astype(np.float32) hsv[..., 0] (hsv[..., 0] hue_shift) % 180 hsv[..., 1] np.clip(hsv[..., 1] sat_boost, 0, 255) hsv[..., 2] np.clip(hsv[..., 2] - val_drop, 0, 255) purple_face cv2.cvtColor(hsv.astype(np.uint8), cv2.COLOR_HSV2BGR) # 2. 检测人脸 rgb cv2.cvtColor(image, cv2.COLOR_BGR2RGB) results face_mesh.process(rgb) if not results.multi_face_landmarks: return image, None # 3. 生成遮罩并模糊边缘 landmarks results.multi_face_landmarks[0].landmark mask get_face_mask(image, landmarks) mask_smooth cv2.GaussianBlur(mask, (edge_smooth, edge_smooth), 0) alpha (mask_smooth.astype(np.float32) / 255.0)[..., np.newaxis] # 4. 混合原图与紫色变体 result ( image.astype(np.float32) * (1 - alpha) purple_face.astype(np.float32) * alpha ).astype(np.uint8) return result, mask if __name__ __main__: img cv2.imread(input_images/portrait.jpg) if img is None: raise FileNotFoundError(请检查 input_images/portrait.jpg 是否存在) out, _ eggplant_ghost_effect(img) cv2.imwrite(output_images/portrait_eggplant.jpg, out) print(处理完成结果已保存到 output_images/portrait_eggplant.jpg)这段代码包含三个关键动作加载图片、调用特效函数、保存结果。hue_shift、sat_boost、val_drop这三个参数是风格化的核心建议根据自己素材的肤色和背景亮度微调。4.2 摄像头实时版本静态图片版本能验证效果但要体验“真人版”的实时感还需要摄像头版本。新建eggplant_ghost_camera.py# eggplant_ghost_camera.py import cv2 import numpy as np import mediapipe as mp mp_face_mesh mp.solutions.face_mesh face_mesh mp_face_mesh.FaceMesh( static_image_modeFalse, max_num_faces1, refine_landmarksTrue, min_detection_confidence0.5, min_tracking_confidence0.5 ) def create_face_mask(image, landmarks): 根据人脸关键点生成凸包遮罩 h, w image.shape[:2] pts np.array( [(int(lm.x * w), int(lm.y * h)) for lm in landmarks], dtypenp.int32 ).reshape(-1, 1, 2) mask np.zeros((h, w), dtypenp.uint8) cv2.fillConvexPoly(mask, pts, 255) return mask def apply_effect(image, hue_shift125, sat_boost45, val_drop10, blur_ksize25): 对单帧图像应用茄子鬼风格 # 调色为紫色版本 hsv cv2.cvtColor(image, cv2.COLOR_BGR2HSV).astype(np.float32) hsv[..., 0] (hsv[..., 0] hue_shift) % 180 hsv[..., 1] np.clip(hsv[..., 1] sat_boost, 0, 255) hsv[..., 2] np.clip(hsv[..., 2] - val_drop, 0, 255) purple cv2.cvtColor(hsv.astype(np.uint8), cv2.COLOR_HSV2BGR) # 人脸检测 rgb cv2.cvtColor(image, cv2.COLOR_BGR2RGB) results face_mesh.process(rgb) if not results.multi_face_landmarks: return image landmarks results.multi_face_landmarks[0].landmark mask create_face_mask(image, landmarks) # 脸部边缘平滑混合 mask_blur cv2.GaussianBlur(mask, (blur_ksize, blur_ksize), 0) alpha (mask_blur.astype(np.float32) / 255.0)[..., np.newaxis] merged ( image.astype(np.float32) * (1 - alpha) purple.astype(np.float32) * alpha ).astype(np.uint8) # 外发光扩张遮罩并模糊叠加半透明紫色 glow_mask cv2.dilate(mask, np.ones((7, 7), np.uint8), iterations3) glow_mask cv2.GaussianBlur(glow_mask, (51, 51), 0) glow_alpha (glow_mask.astype(np.float32) / 255.0)[..., np.newaxis] * 0.35 glow_color np.full(image.shape, (200, 60, 200), dtypenp.uint8) # BGR 紫色 result ( merged.astype(np.float32) * (1 - glow_alpha) glow_color.astype(np.float32) * glow_alpha ).astype(np.uint8) return result if __name__ __main__: cap cv2.VideoCapture(0) if not cap.isOpened(): raise RuntimeError(无法打开摄像头请检查设备及权限) print(按 ESC 键退出) while True: ok, frame cap.read() if not ok: print(读取视频帧失败) break # 左右翻转接近镜子效果 frame cv2.flip(frame, 1) out apply_effect(frame) cv2.imshow(Eggplant Ghost - press ESC to quit, out) key cv2.waitKey(1) 0xFF if key 27: break cap.release() cv2.destroyAllWindows()运行方式python eggplant_ghost_camera.py如果运行成功屏幕上会显示摄像头画面。人脸区域会被紫色风格覆盖脸部周围有一圈淡淡的紫光。按键盘左上角的 ESC 键退出。4.3 批量处理图片在拍完一组 cos 照片后如果不想一张一张用 Photoshop 修可以写一个批量处理脚本。新建batch_process.py# batch_process.py import os import cv2 import numpy as np import mediapipe as mp mp_face_mesh mp.solutions.face_mesh face_mesh mp_face_mesh.FaceMesh( static_image_modeTrue, max_num_faces1, refine_landmarksTrue, min_detection_confidence0.5 ) def process_image(path): 处理单张图片并返回结果 image cv2.imread(path) if image is None: print(f读取失败跳过: {path}) return None hsv cv2.cvtColor(image, cv2.COLOR_BGR2HSV).astype(np.float32) hsv[..., 0] (hsv[..., 0] 125) % 180 hsv[..., 1] np.clip(hsv[..., 1] 45, 0, 255) hsv[..., 2] np.clip(hsv[..., 2] - 10, 0, 255) purple cv2.cvtColor(hsv.astype(np.uint8), cv2.COLOR_HSV2BGR) rgb cv2.cvtColor(image, cv2.COLOR_BGR2RGB) results face_mesh.process(rgb) if not results.multi_face_landmarks: return image landmarks results.multi_face_landmarks[0].landmark h, w image.shape[:2] pts np.array( [(int(lm.x * w), int(lm.y * h)) for lm in landmarks], dtypenp.int32 ).reshape(-1, 1, 2) mask np.zeros((h, w), dtypenp.uint8) cv2.fillConvexPoly(mask, pts, 255) mask_blur cv2.GaussianBlur(mask, (31, 31), 0) alpha (mask_blur.astype(np.float32) / 255.0)[..., np.newaxis] result ( image.astype(np.float32) * (1 - alpha) purple.astype(np.float32) * alpha ).astype(np.uint8) return result if __name__ __main__: input_dir input_images output_dir output_images os.makedirs(output_dir, exist_okTrue) for file_name in os.listdir(input_dir): if not file_name.lower().endswith((.jpg, .jpeg, .png)): continue full_path os.path.join(input_dir, file_name) result process_image(full_path) if result is None: continue save_path os.path.join(output_dir, file_name) cv2.imwrite(save_path, result) print(f已处理: {file_name} - {save_path})批量处理脚本相当于把静态图片版本的逻辑包装成一个函数。读者可以在此基础上增加进度条、多线程、错误重试等机制。4.4 运行与验证运行静态图片版本前确保input_images目录下有一张正脸照片。如果没有可以先用手机拍一张或者下载一张开源的人像测试图。执行命令python eggplant_ghost_image.py正常输出处理完成结果已保存到 output_images/portrait_eggplant.jpg打开输出图片应该能看到人脸区域呈现紫色并且边缘过渡自然没有生硬边界。摄像头版本则直接运行python eggplant_ghost_camera.py如果一切正常画面里会出现实时紫色人脸效果。这里需要特别提醒摄像头实时处理时光线越均匀人脸检测越稳定强逆光或大面积遮挡会导致检测丢失。5. 常见问题与排查思路下面把最容易遇到的问题整理成表格方便快速排查。问题现象常见原因解决思路安装 mediapipe 失败Python 版本过高或网络问题使用 Python 3.9~3.11配置国内镜像源重试导入 mediapipe 时崩溃依赖库版本冲突重建虚拟环境固定 numpy 版本摄像头无法打开设备占用或权限未开启检查系统摄像头权限关闭其他占用软件检测不到人脸输入颜色空间错误确保传入 MediaPipe 的是 RGB 图像画面很卡每帧都做全分辨率检测缩小处理尺寸降低检测频率脸部颜色太假色调偏移参数不合适调整 hue_shift、sat_boost、val_drop边缘有黑边遮罩没有做高斯模糊增大 blur_ksize比如 31 或 41外发光效果不明显glow_alpha 太低提高 0.35 到 0.5或增加 dilate 迭代次数5.1 MediaPipe 安装失败常见错误ERROR: Could not find a version that satisfies the requirement mediapipe可能原因包括Python 版本过高、系统缺少 Visual C 运行库、网络无法访问官方源。解决方法是先切换 Python 版本再使用清华源安装pip install mediapipe -i https://pypi.tuna.tsinghua.edu.cn/simple如果仍然失败可以在 MediaPipe 官方 GitHub 的 Release 页面下载对应 Python 版本的 wheel 文件然后本地安装。5.2 摄像头打不开在 Windows 上如果同时打开 QQ、微信、OBS 等软件摄像头可能被占用。关闭这些软件后再试。macOS 需要在系统设置中允许终端或 IDE 访问摄像头。Ubuntu 下则需要确认用户是否在video用户组中。5.3 画面卡顿优化如果实时预览卡顿有两种最直接的优化方式第一种是缩小处理帧。将摄像头帧缩放到 640x480 或更小检测完再放大显示。第二种是每隔 N 帧检测一次人脸中间帧复用上一次的遮罩坐标但头动剧烈时会有延迟。实际项目中推荐每隔 3 到 5 帧做一次 MediaPipe 检测其他帧直接使用最近一次检测结果这样能明显提升实时性。5.4 颜色效果不对如果你发现调整后整张脸偏绿色或偏红大概率是hue_shift偏移量不对。肤色 H 值是变量建议在代码里加一个滑动条实时调试。OpenCV 的cv2.createTrackbar可以很方便地调节三个颜色参数这也是后面工程化的方向之一。6. 最佳实践与工程建议6.1 把参数抽成配置不要把参数散落在函数里写死。建议用字典或者dataclass管理from dataclasses import dataclass dataclass class EggplantGhostConfig: hue_shift: int 125 sat_boost: int 45 val_drop: int 10 edge_smooth: int 31 glow_strength: float 0.35 glow_dilate_iterations: int 3这样以后想同时对比不同风格只需要生成多个 config 实例代码会清晰很多。6.2 性能优化建议使用cv2.resize降低图像分辨率后再检测人脸。使用cv2.setNumThreads调整 OpenCV 线程数避免和 MediaPipe 抢 CPU。实时视频中MediaPipe FaceMesh 的refine_landmarks参数会额外计算虹膜关键点如果不需要眼睛细节可以设为 False 提升速度。如果开发环境有 GPU可以考虑使用 OpenCV 的 CUDA 版本但普通 CPU 项目不必强求。6.3 隐私与合规摄像头实时处理涉及人脸数据。在开发和部署时要注意处理本地图片或视频时不要将人脸数据上传到第三方服务除非用户明确授权。如果做成产品必须在使用前向用户明示数据用途并提供删除机制。不要在未经授权的情况下对他人照片进行风格化并公开发布。批量处理大量人脸数据时建议在数据进入程序前先做脱敏处理。这些不仅是技术问题也是最基本的合规和伦理要求。6.4 从“人脸特效”扩展到“完整角色化”本文方案只处理了人脸区域的颜色和外发光。如果想让“真人版茄子鬼”的完成度更高还可以继续扩展使用 MediaPipe Selfie Segmentation 将整个人体分割出来全身体色偏紫。使用头发分割模型将头发也变成白色或紫色。在 OpenCV 中叠加鬼火粒子、飘动烟雾等素材。结合 Live2D 或虚幻引擎 MetaHuman让真人表情驱动虚拟角色。使用 Stable Diffusion 的 img2img 技术把真人画面转换成二次元茄子鬼风格。这些方向可以逐步深入也能让同一个项目持续演化出更多玩法。7. 总结与下一步学习路线本文从一个“真人版茄子鬼”的视觉创意出发介绍了基于 OpenCV 和 MediaPipe 的人脸风格化滤镜实现方案。核心步骤包括用 MediaPipe FaceMesh 检测人脸关键点、用凸包生成遮罩、在 HSV 颜色空间完成紫色调色、再用高斯模糊实现边缘过渡和外发光。配套给出了静态图片、实时摄像头、批量处理三个可运行的 Python 脚本并覆盖了常见问题的排查方法。如果你想继续深入建议从下面几个方向开始学习 OpenCV 基础图像读写、颜色空间、形态学操作、视频处理。学习 MediaPipe 其他能力手势识别、姿态估计、自拍分割。学习深度学习风格迁移怎样把真人照片转换成动漫角色。学习实时视频编码与推流让处理后的画面可以直接用于直播。技术路线并不复杂关键是动手跑通一个最小 Demo然后再慢慢加功能。如果你在运行时遇到代码问题欢迎把环境信息、Python 版本和完整报错贴到评论区我会尽量帮你一起定位。