
简介面向Python开发者及计算机视觉爱好者的智能口红色号检测推荐系统完整工程基于Dlib人脸68点特征与face_recognition库完成人脸检测与唇部区域定位结合TensorFlow及colorsys色彩转换技术对嘴唇颜色进行提取并匹配相近色号适用于美妆电商、虚拟试妆、个性化推荐等场景。资源共84个文件包含10个Python源码、37个txt说明与数据、21张PNG图像、8个JSON配置、UI界面、PDF文献以及ipynb示例压缩包仅3.03MB目录结构清晰便于按需取用。目前已有464人学习下载。工程覆盖数据预处理与系统搭建两大模块具体包括唇部轮廓提取、蒙版创建、嘴唇区域划分、图片颜色提取、色号库比对与结果输出同时提供基于PyQt5和QCandyUi的图形界面附带完整数据集、训练模型与开发文档可直接运行或二次扩展也可作为毕业设计、课程项目的参考范例。 口红试色这件事线上买怕有色差线下专柜又没法一次性试遍所有品牌的热门色号。我一直在想能不能用深度学习直接分析人脸照片里的唇部颜色再把颜色映射到具体品牌的口红色号上。这个想法其实并不复杂核心就是把“口红色号检测推荐”拆成人脸关键点检测、唇部区域颜色提取、色号分类推荐三段来完成。这篇文章我直接把整个系统的搭建过程、关键代码逻辑、训练细节和踩过的坑都梳理一遍希望能给想做类似桌面级深度学习应用的朋友一个完整参考。改出口红推荐这个完整功能之前先把需求拆开来看。这个项目本质上要解决三件事第一从一张普通的人脸照片里准确找到嘴唇的位置第二把嘴唇区域的颜色信息提取出来转化成可计算的色彩特征第三把颜色特征映射到具体品牌的口红色号上并且能给出合理的推荐结果。这三个环节分别对应了Dlib的人脸关键点检测、颜色空间转换与特征提取、TensorFlow的分类模型训练最后由PyQt5把整个流程封装成一个可视化桌面应用。这套技术选型是经过反复比较后确定的。Dlib的68点人脸关键点检测模型非常成熟尤其对唇部区域的定位精度很高且推理速度快纯CPU环境也能跑得很流畅。TensorFlow则负责后端深度学习模型的训练和推理生态完善部署方便。PyQt5负责界面层C后端加Python绑定的方式让它性能和开发效率都不错做这种工具型桌面应用很合适。整个项目使用Python作为胶水语言把这三部分串起来逻辑清晰工程上也不会引入不必要的复杂度。1. 系统整体架构与设计思路1.1 为什么用Dlib定位嘴唇而不是直接训练目标检测模型很多人看到“检测嘴唇”第一反应是用YOLO或者SSD这类目标检测模型但在实际试过之后这个场景用Dlib的68点关键点检测方案要合理得多。关键点检测返回的是嘴唇轮廓的坐标点集合能精确定位到唇峰、唇角这些细节位置而目标检测返回的是矩形框上嘴唇和下嘴唇的分界、唇峰位置这些关键信息会丢失得很严重。这个项目里口红色号的判断高度依赖唇部颜色的准确提取。如果用矩形框裁剪会混入大量脸部皮肤和牙齿的颜色对后续的颜色特征提取造成严重干扰。Dlib的68点关键点模型中标号为48到67的20个点完整覆盖了嘴唇的内外轮廓通过连接这些点构建掩膜就能精确提取出纯嘴唇区域的像素信息。安装Dlib时可能遇到编译失败的问题。Dlib的安装包体积较大约100MB且安装时会自动编译C扩展耗时几分钟还依赖CMake和C编译环境。建议安装Visual Studio Build Tools包含C桌面开发组件后再安装或者使用预编译的whl文件能显著提升安装成功率。另外Dlib的模型文件如shape_predictor_68_face_landmarks.dat需要单独下载这是开源社区提供的预训练模型网上可以找到。1.2 颜色分析与色号映射的整体流程系统对唇部颜色处理的核心链路是人脸检测 → 关键点定位 → 唇部掩膜提取 → 颜色空间转换 → 颜色特征统计 → 分类模型推荐色号。链路里的每一步权重不同前两步是基础颜色特征统计和分类推荐是核心。颜色特征提取的关键点在于不能直接在RGB空间做简单的平均色计算。RGB空间对光照变化太敏感不同光源、色温下同一个口红色号测出的RGB值差异很大。我最终采用的方案是把唇部区域转换到LAB颜色空间L通道表示亮度A通道表示红绿色度B通道表示黄蓝色度。口红的颜色差异主要体现在A通道和B通道上L通道受光照影响最大亮度变化所以在特征提取时降低L通道的权重能有效提升模型对不同光照条件的鲁棒性。同时保留唇部中心区域像素点总数的60%左右的颜色统计值丢弃唇边模糊区域这样处理后的特征更集中。1.3 PyQt5应用的界面交互逻辑界面是给普通人用的不能要求用户理解算法原理所以交互逻辑必须足够直观。主界面设计为三个区域左侧是图片上传与预览区用户上传一张清晰的正脸照片后系统自动绘制出人脸关键点并在嘴唇位置叠加一个半透明色块直观显示检测到的唇部区域右侧是色号推荐区展示Top5推荐色号每个色号带有一个品牌色卡、色号名和匹配度百分比点击色号卡片可以查看推荐的妆容搭配参考底部是操作日志区实时显示检测过程中的步骤信息。考虑到后续扩展性界面里还加入了两个实用小功能肤色基调识别和“我的色号”收藏列表。肤色基调识别通过分析脸部非唇部区域的皮肤颜色判断用户是冷色调还是暖色调在推荐色号时根据肤色基调做二次排序冷皮用户优先推荐偏蓝调的口红暖皮用户优先推荐偏橘调的口红。这个细节虽然增加了开发量但实际使用体验提升非常明显。整个界面基于QStackedWidget做页面切换后续想增加虚拟试妆功能时也不用手动重构整体布局。2. 核心原理与关键细节解析2.1 Dlib人脸关键点定位的数学原理Dlib的人脸关键点检测使用基于梯度增强学习的回归树集成方法核心思路是逐级回归从粗到细地逼近每个关键点的精确位置。整个过程分两个阶段先用HOG特征检测人脸区域再把人脸区域归一化到固定尺寸然后使用一系列级联回归器预测关键点位置。每个回归器都基于像素差异特征进行判断即某个关键点在当前估计位置附近的某几个像素点之间的灰度值差这个差值对位置偏移方向具有指示性。通过训练数据模型学习了大量这样的弱分类器组合后能精确预测嘴唇的轮廓点位置。理解这个原理对使用很有帮助既然算法依赖灰度差那么输入照片的光照均匀度就直接影响检测精度。实际使用中背光、局部阴影严重的照片会导致唇部关键点定位偏移这一点需要在UI层面增加提示引导用户选择光线均匀的正面照片。68点模型的坐标序号是固定的0到16号是脸部轮廓线17到26号是眉毛27到35号是鼻子区域36到47号是眼睛区域48到67号是嘴唇区域。其中48到59号是外唇轮廓12个点60到67号是内唇轮廓8个点。编写代码时用如下方式提取嘴唇坐标点import dlib import numpy as np # 外唇轮廓: 48-59, 内唇轮廓: 60-67 LIPS_OUTER_POINTS list(range(48, 60)) LIPS_INNER_POINTS list(range(60, 68)) ALL_LIPS_POINTS LIPS_OUTER_POINTS LIPS_INNER_POINTS detector dlib.get_frontal_face_detector() predictor dlib.shape_predictor(shape_predictor_68_face_landmarks.dat) def extract_lips_points(gray_img): faces detector(gray_img, 1) if len(faces) 0: return None shape predictor(gray_img, faces[0]) coords np.zeros((68, 2), dtypenp.int32) for i in range(68): coords[i] (shape.part(i).x, shape.part(i).y) return coords[ALL_LIPS_POINTS]2.2 TensorFlow色号分类模型的训练策略色号分类模型本质上是一个图像分类任务但和普通物体分类有本质区别普通分类关注的是物体的结构特征猫有耳朵、飞机有机翼而口红色号分类关注的是颜色特征且不同色号之间的差异往往很细微比如豆沙色系的相邻色号肉眼几乎无法区分。基于这个特点训练阶段的策略做了三方面调整。第一使用轻量级网络结构最终选用MobileNetV2作为backbone在ImageNet上预训练后迁移学习。颜色特征不需要太深的网络提取高维语义信息浅层特征已经足够MobileNetV2的参数量远小于ResNet50推理速度快打包体积也小。第二输入图像上做专门的数据增强在HSV空间随机扰动色相H通道偏移量控制在±3度范围内和饱和度S通道缩放0.9~1.1倍模拟不同屏幕显示和光线条件下的颜色差异。第三定义合适的采样策略训练集中如果同一种色号的样本数差异很大训练时按类别进行加权采样让数量少的色号不被淹没。实际训练时数据集按色号类别划分每个类别至少50张标注图片总共覆盖约120个常见色号训练集、验证集、测试集按8:1:1划分。训练轮数设置20轮早期训练使用学习率0.001第10轮后衰减到0.0001。损失函数使用多分类交叉熵优化器选择Adam。其实在训练细节上最影响效果的往往不是模型结构而是数据标注质量。采集样本时同一支口红不同厚涂薄涂的颜色差异巨大。我在标注时强制要求每张图片标注涂抹厚度标签训练时把厚度作为辅助分类信息加入模型。这样推荐时能根据用户照片里唇色是厚涂还是薄涂来微调推荐结果比如自然裸妆感的薄涂唇色就不会优先推荐饱和度过高的正红色。2.3 PyQt5实时显示与线程管理PyQt5的GUI界面有一个容易踩的坑耗时操作如果在主线程执行界面会卡死表现为窗口无响应严重时整个应用崩溃。人脸检测和模型推理都是耗时操作单纯一张照片可能很快但如果后续加上摄像头实时检测帧处理耗时就不能忽视了。设计上采用QThread工作者线程配合信号槽机制。主线程负责界面渲染和用户交互后台线程执行人脸检测和模型推理通过pyqtSignal把检测结果传回主线程。这样既保证界面流畅也避免多个线程同时操作界面对象导致的时序问题。from PyQt5.QtCore import QThread, pyqtSignal class InferenceThread(QThread): result_ready pyqtSignal(dict) def __init__(self, image, model_pipeline, parentNone): super().__init__(parent) self.image image self.pipeline model_pipeline def run(self): result self.pipeline.process(self.image) self.result_ready.emit(result)3. 实操过程与核心环节实现3.1 环境配置与依赖版本避坑先说环境。Python推荐3.9或3.10版本TensorFlow在Python 3.11及以上版本存在兼容性问题Dlib在Windows上安装需要C编译环境PyQt5的安装难度最低。整个环境的依赖清单和稳定版本组合我已经整理进requirements.txt按文件一次安装即可。需要特别强调的是TensorFlow版本和CUDA/cuDNN的匹配关系非常严格GPU版本配置不正确会直接报类似“无法加载DLL”的错误。对大部分本地运行场景CPU版本其实够用。MobileNetV2模型在CPU上推理一张人脸照片的耗时约200到400毫秒完全可以接受。如果想用GPU加速建议严格对照TensorFlow官方版本表检查CUDA版本。依赖库推荐版本说明Python3.9或3.10避免3.11及以上版本tensorflow2.10或2.13CPU版即可满足需求dlib19.24.0需C编译环境或预编译whlPyQt55.15.9稳定版本opencv-python4.8.x图像IO与预处理numpy1.24.x数值计算3.2 数据集构建与色号标注流程数据集是这个项目里的重头戏也是决定成败的关键模型设计和参数调优做得再好数据不行全都白费。我采用了“公开数据自采数据”的混合方案公开部分使用约8000张带唇色标签的人脸图片自采部分用不同光线条件下拍摄的真人唇部照片补充约2000张重点关注在暗光、暖黄光、冷白光下的颜色偏移。自采部分的数据增强流程很关键增强通过程序自动完成。原始图片先按唇部关键点对齐裁剪缩放到224×224像素统一尺寸然后做三组随机增强第一组调整亮度系数0.8~1.2模拟不同环境光线第二组调整白平衡色温偏移±500K模拟不同光源色温第三组做轻微水平翻转和旋转±5度扩充样本多样性。增强后的数据集从约10000张扩展到了50000张显著降低模型过拟合风险。标注环节最考验耐心。120个色号每个色号需要确保正负样本数量均衡。设计了一个专门的小工具显示唇部裁剪图标注色号ID的同时记录唇部掩膜和中心点坐标。标注过程中要特别注意的一种情况是部分色号在不同肤色上的表现差异很大深肤色上的正红色和浅肤色上的砖红色在视觉上可能很接近。因此每张样本标注时还要同步记录肤色区间模型训练时把肤色信息也作为输入特征之一。3.3 模型训练评估与调优记录训练过程分两个阶段进行。第一阶段用ImageNet预训练的MobileNetV2冻结backbone只训练最后的全连接分类头学习率0.001训练10轮验证准确率在72%左右徘徊。这个阶段的作用是让分类头先适应色号分布的固有特征收敛速度快。第二阶段解冻backbone的后半部分用0.0001的学习率整体微调再训练10轮验证准确率提升到88%左右。训练过程中的loss曲线走势稳定没有明显过拟合迹象。测试集上的混淆矩阵显示最常见也是相对难解决的是相邻色号之间的误判比如豆沙色系里偏灰调和偏粉调的色号容易被混淆。针对这个问题我给模型加了一个后处理逻辑预测结果取Top3结合肤色检测结果从Top3里挑最合适的色号返回而不是直接返回置信度最高的那一个。这个微调之后用户在主观评价中认为推荐结果“合理可用”的比例从71%提升到了86%提升非常显著。训练完成后的模型转换为TensorFlow Lite格式进一步压缩体积从原来的约14MB压缩到约8MB推理速度提升约30%精度几乎没有损失。因为模型结构简单转换过程中没有遇到需要手工修正算子的麻烦问题。3.4 PyQt5界面功能实现细节界面层我重点讲两个容易出问题的地方。第一个是图片展示区域的交互逻辑。用户上传图片后要在同一个控件上完成三件事显示原始照片、绘制关键点标注、叠加唇色提取结果的可视化色块。这个叠加绘制过程如果在主线程同步绘制图片分辨率较高时会明显卡顿。我的做法是先用OpenCV完成所有绘制操作生成最终效果图再一次性传给QLabel显示不在界面控件上做逐层叠加。第二个是下拉框和超链接的问题。网络上有人在QComboBox的下拉框上遇到闪退问题实测在5.15.9版本上也会出现表现是点击下拉箭头时程序直接退出。排查后确认这是QComboBox的view容器在某些样式表配置下的兼容性bug。规避方案是样式表中不设置下拉框内部的滚动条样式如果遇到闪退改用按钮QPushButton搭配QMenu弹层的方式实现下拉选择。日志区还增加了富文本显示功能。处理进度用不同颜色区分步骤开始为灰色、执行中为蓝色、完成为绿色、报错为红色。点击日志里的图片路径超链接可以直接打开对应的原始图片方便排查问题。这个功能用QTextBrowser的anchorClicked信号配合QSslError处理实现开发过程中没有遇到特殊障碍。4. 常见问题与排查技巧实录4.1 Dlib安装失败的三种解决路径Dlib安装失败是几乎所有初次接触这个库的人都会碰到的问题。症状基本有两种一是安装过程中卡住不动最后报编译错误退出二是直接报“Microsoft Visual C 14.0 is required”提示缺少C编译器。针对这两种情况解决办法按可行性排序如下第一条路是安装VS Build Tools的C桌面开发组件后再安装这是微软官方推荐的路线但下载安装包约2GB耗时长第二条路是直接寻找与Python版本对应的dlib预编译whl文件安装可以跳过本地编译环节安装速度快且成功率极高第三条路是用conda从conda-forge频道安装conda会自动处理依赖关系不用手动安装编译工具。如果三条路都不顺利还有一种终极大法降低Python版本到3.7或3.8再用pip安装dlib基本不会报错。4.2 TensorFlow DLL加载失败分析热词里提到的“tensorflow dll diagnostic”是Windows环境下TensorFlow安装后最常见的报错现象是import tensorflow时报错提示某个DLL无法加载或者找不到指定的模块。这个问题90%的原因是缺少运行时依赖TensorFlow依赖Visual C Redistributable尤其是在Windows Server或精简版Windows系统上经常没有预装这个运行库。排查思路分三步走先安装最新的Visual C Redistributable包这个修复了绝大多数情况如果问题还在进一步确认Python架构版本TensorFlow要求64位Python32位Python会导致DLL加载失败最后检查Python路径中是否存在多个TensorFlow安装副本有时候不同虚拟环境之间的包混用会导致DLL冲突。需要单独说明的是验证TensorFlow GPU版本是否正常工作不能只看导入是否成功要实际执行一个简单矩阵运算并确认相关GPU库被加载。4.3 唇色提取偏色与推荐不准确问题当嘴唇区域颜色提取结果和肉眼观察明显不一致时问题几乎都出在图像处理前端。我遇到过三种典型情况白色LED灯下的照片整体偏冷提取出的唇色比实际颜色偏紫餐厅暖黄灯光下的照片整体偏暖唇色偏橘手机开启美颜滤镜后唇部颜色被柔和处理饱和度降低和真实色号差距很大。针对偏色问题需要在进入模型前的预处理阶段加入白平衡校正。基于灰度世界假设做白平衡假设图像中所有颜色的平均值接近灰色如果检测到整体色调有偏移就计算各通道均值把偏移量补偿回去。美颜照片问题在算法层面无法根治只能在UI层面添加提示文案建议用户上传无滤镜的原始照片。推荐准确率同样受评分逻辑影响。系统返回的匹配度分数并非模型分类概率的简单归一化而是融合了三个因素模型Top1的置信度权重0.5、唇色与色号库中各色号平均颜色的距离相似度权重0.3、肤色适配度权重0.2这个评分公式是在多次用户调研后调整出来的。4.4 PyQt5界面卡顿与内存泄漏排查界面一次性加载大量高清图片时内存占用激增甚至导致程序闪退的问题排查后发现根因是每张图片在显示前都转换为QPixmap对象而QPixmap的底层位图存储非常消耗内存大量图片没有及时释放导致内存持续增长。解决方案是引入QPixmap的缩放机制显示前先按显示区域大小等比例缩放图片再加载而不是加载原图后让控件自动缩放同时增加一个简单的LRU缓存限制最多保留最近20张处理过的图片超出部分手动清除底层数据。还有一个容易被忽略的点是QLabel设置图片时旧的QPixmap如果没有正确释放也会产生内存累积。在切换到新图片前先调用clear()方法清理旧内容。5. 扩展方向与后续优化空间这个项目完成后扩展方向其实很多。最自然的下一步是接入摄像头实时检测把静态照片换成动态视频流增加关键点跟踪逻辑后可以实现实时唇色分析。摄像头场景下挑战不同主要是帧率要求需要保持更高帧率、模糊帧处理运动过程中容易出模糊帧、以及不同角度下关键点定位稳定性。这些对Dlib来说难度不大64点模型在单人脸场景下跟踪稳定性很好。另一个值得考虑的方向是接入真实品牌色号库。当前系统的色号分类基于自建色号体系与品牌专柜口红色号之间没有一一对应的映射关系。可以按热门品牌的经典色号扩充数据集把模型输出层改为品牌色号ID就能实现“某个品牌的某个色号最适合你”这种更直接的推荐。这部分工作工程量大但技术难度不高主要是数据采集和标注的时间投入严格按流程操作基本没有技术风险。色号数据和模型都可以单独研究。如果想加入新的色号类别只需要准备该色号的训练图片并运行训练脚本程序里写好类别的注册逻辑新增色号不会影响已有功能。当前模型还属于静态推荐的范畴没有考虑季节、场合这些动态因素。后续可以把季节特征和场合标签加入训练特征让推荐系统从“什么颜色适合你”进化到“当前场景下什么颜色更适合”这也是这类系统下一步的主要演进方向。最后再分享一个实用的小经验这类桌面应用的模型文件和数据资源不要直接打包进代码目录单独放在应用的同级目录下首次启动时检查文件完整性缺失时给出明确提示。这样模型升级时不需要重新发布整个应用程序替换文件即可完成升级实际维护会方便很多。本文还有配套的精品资源点击获取