热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

你和你的女神之间,差了一个OpenCV口红色号识别器,android开发环境的搭建步骤

MeanC((int)(Mean_Rcount),(int)(Mean_Gcount),(int)(Mean_Bcount))returnMe番茄的颜色提取到了,那

MeanC=((int)(Mean_R/count),(int)(Mean_G/count),(int)(Mean_B/count))
return Me

番茄的颜色提取到了,那么和什么做比对呢?

当然是口红的数据,文摘菌这儿用到了 5 个品牌,分别是圣罗兰、香奈儿可可小姐、迪奥、美宝莲、纪梵希,共 17 个系列,271 个口红色号。

数据集是一个嵌套的字典数据结构,存为 json 串的形式,里面记录了每个口红品牌系列下不同口红色号的颜色 id、名称、和 16 进制颜色值。

lipstick.json部分数据集展示如下:

{“brands”:[{“name”:“圣罗兰”,“series”:
[{“name”:“莹亮纯魅唇膏”,“lipsticks”:
[{“color”:"#D62352",“id”:“49”,“name”:“撩骚”},
{“color”:"#DC4B41",“id”:“14”,“name”:“一见倾心”},
{“color”:"#B22146",“id”:“05”,“name”:“浮生若梦”},

数据集中存储的 RGB 颜色是 16 进制的字符串形式,需要将其转换成 RGB 值,比较两个颜色相近与否。

实际上是比较 RGB 三个分量维度上的误差,最小的口红输出对应的品牌、系列、色号和 id。

代码如下:

import json
import getcolor
import numpy as np
import lipcolor

#filename = ‘temp.txt’
##write the temp data to file##
def WtoFile(filename,RGB_temp):
num=len(RGB_temp)
with open(filename,‘w’) as f:
for i in range(num):
s = str(RGB_temp[i]).replace(’[’,’’).replace(’]’,’’)
f.write(s)
f.write("\n")

#operate the data #
##save the brand&series&color id&color name to sum_list##
##covert the color #D62352 to RGB_array##
##caculate the RGB difference to RGB_temp and write the value to file##
def data_operate():
with open(‘lipstick.json’, ‘r’, encoding=‘utf-8’) as f:
ret_dic = json.load(f)
#print(ret_dic[‘brands’])
#print(type(ret_dic)) #
#print(ret_dic[‘brands’][0][‘name’])
b_num=len(ret_dic[‘brands’])
#print(b_num)#brands number

s_list=[]
#series brands#
for i in range(len(ret_dic[‘brands’])):
s_num=len(ret_dic[‘brands’][i][‘series’])
s_list.append(s_num)
#print("{0} has {1} series".format((ret_dic[‘brands’][i][‘name’]),(s_list[i])))

#the lipstick color of every brands every series#
#the first loop calculate the total color numbers
sum=0
for b1 in range(b_num):
for s1 in range(s_list[b1]):
brand_name=ret_dic[‘brands’][b1][‘name’]
lip_name=ret_dic[‘brands’][b1][‘series’][s1][‘name’]
color_num=len(ret_dic[‘brands’][b1][‘series’][s1][‘lipsticks’])
sum+=color_num#calculate the total color numbers

#the second loop save the message to a list#
sum_list=np.zeros((sum,4), dtype=(str,8))
value_array=np.zeros((sum,6), dtype=int)
i=0
for b2 in range(b_num):
for s2 in range(s_list[b2]):
brand_name=ret_dic[‘brands’][b2][‘name’]
#print(type(brand_name))
lip_name=ret_dic[‘brands’][b2][‘series’][s2][‘name’]
color_num=len(ret_dic[‘brands’][b2][‘series’][s2][‘lipsticks’])
for c in range(color_num):
color_value=ret_dic[‘brands’][b2][‘series’][s2][‘lipsticks’][c][‘color’]
color_name=ret_dic[‘brands’][b2][‘series’][s2][‘lipsticks’][c][‘name’]
color_id=ret_dic[‘brands’][b2][‘series’][s2][‘lipsticks’][c][‘id’]
#print("{0} series {1} has {2} colors,color {3}:{4}".format(brand_name,lip_name,color_num,c+1,color_name))
sum_list[i][0]=brand_name
sum_list[i][1]=lip_name
sum_list[i][2]=color_id
sum_list[i][3]=color_name
#value_array[i]=value_array[i][1]
#convert “#D62352” to [13 6 2 3 5 2]#
for l in range(6):
temp=color_value[l+1]
if(temp>=&#39;A’and temp<=‘F’):
temp1=ord(temp)-ord(‘A’)+10
else:
temp1=ord(temp)-ord(‘0’)
value_array[i][l]=temp1
i+=1

#the third loop covert value_array to RGB_array#
RGB_array=np.zeros((sum,3), dtype=int)
for i in range(sum):
RGB_array[i][0]=value_array[i][0]*16+value_array[i][1]
RGB_array[i][1]=value_array[i][2]*16+value_array[i][3]
RGB_array[i][2]=value_array[i][4]*16+value_array[i][5]

#calculate the similar and save to RGB_temp
#RGB_temp=np.zeros((sum,1), dtype=int)
RGB_temp=np.zeros((sum,1), dtype=float)
for i in range(sum):
R=RGB_array[i][0]
G=RGB_array[i][1]
B=RGB_array[i][2]
RGB_temp[i]=abs(get[0]-R)+abs(get[1]*3/4-G)+abs(get[2]-B)
RGB_temp.tolist();#covert array to list
#print(RGB_temp)
filename=“temp.txt”
WtoFile(filename,RGB_temp)
#sort the RGB_temp#
result=sorted(range(len(RGB_temp)), key=lambda k: RGB_temp[k])
#print(result)
#output the three max prob of the lipsticks#
print(“The first three possible lipstick brand and color id&name are as follows:”)
for i in range(3):
idex=result[i]
print(sum_list[idex])
print(“The first three possible lipstick brand RGB value are as follows:”)
for i in range(3):
idex=result[i]
R=RGB_array[idex][0]
G=RGB_array[idex][1]
B=RGB_array[idex][2]
tuple=(R,G,B)
print(tuple)

if name == ‘main’:
#image = getcolor.Image.open(inputpath)
#image = image.convert(‘RGB’)
#get=getcolor.get_dominant_color(image)#tuple #get=(231, 213, 211)
list=[]
color_dir=“output”
count=lipcolor.load_color(color_dir,list)
get=lipcolor.Mean_color(count,list)
print(“the extracted RGB value of the color is {0}”.format(get))
#operate the data#
data_operat

输出最有可能吻合番茄颜色的前三个口红的信息,然后在 Spyder 中的运行结果:

可以看到最有可能的三个口红品牌色号的 RGB 值与番茄的 RGB 值是非常接近的。

提取到的番茄颜色:

‘迪奥’ ‘烈艳蓝金唇膏’ ‘080’ &#39;微笑正红’的颜色:

‘圣罗兰’ ‘纯口红’ ‘56’ &#39;橙红织锦’的颜色:

‘纪梵希’ ‘高定香榭天鹅绒唇’ ‘325’ &#39;圣水红’的颜色:

我已经眼花缭乱,三个颜色……有区别吗?!以后不如准备统一叫它们,番茄色!

不过,这也正说明了,刚刚的提取&对比方法可行!

既然可以识别番茄的颜色,那么,可以识别人像中的口红色号吗?

#####进入正题!人像口红色号识别

接下来,我们需要做的是输入一张人像图片,可以自动识别其中的嘴唇区域,并提取出嘴唇区域中的一部分做为颜色提取的源图像。

这里就要用到 CV 的人脸识别了,还好 Dlib 库又帮助我们减轻一大部分的工作量。

Dlib 中有自带的 68 个人脸的识别器,可以得到人脸部位包括眉毛、眼睛、鼻梁、面部轮廓和嘴唇区域的具体点的位置,到这儿,我以为很轻松就可以截到嘴唇区域了,结果有点尴尬…

我们首


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享


先找到了一张小姐姐的照片:

截取到的嘴唇区域如下:

很明显的看到上下嘴唇黑色的区域也截取到了,这对后续的提色有影响,所以不得不回到最初的 68 个检测点来思考人生。

标记的 68 个人脸检测点如上图所示,而嘴唇部位是从第 49 个标记点开始的(数组的话,下标是 48)。

为了尽可能的截取到均匀成色的嘴唇片段,刚开始是想从第 50 个标记点对角线截取到第 56 个标记点,而这不可避免的会截取到上下嘴唇之间的缝隙,这儿的阴影也会影响后续的颜色提取准确度。

考虑到下嘴唇比上嘴唇宽,所以截取到下嘴唇中间的两个小正方形区域:

人脸识别和截取嘴唇区域的代码如下:

import numpy as np
import cv2
import dlib
from PIL import Image

def crop(source,pos):

x1=pos[2][0]
y1=pos[2][1]
x2=pos[1][0]
y2=pos[1][1]
d=abs(x2-x1)
region = source[(int)(y1-d*0.75):y2,x1:x2]


save the image

cv2.imwrite(“output/Mouth1.jpg”, region)

x1=pos[1][0]
y1=pos[1][1]
x2=pos[0][0]
y2=pos[0][1]
d=abs(x1-x2)
region = source[y1-d:y2,x1:x2]


save the image

cv2.imwrite(“output/Mouth2.jpg”, region)

def detect_mouth(img,pos):
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = cv2.equalizeHist(gray)
detector = dlib.get_frontal_face_detector()
#use the predictor 
predictor = dlib.shape_predictor(‘shape_predictor_68_face_landmarks.dat’)
dets = detector(img, 1)
print(“Number of faces detected: {}”.format(len(dets)))
for a in dets:
cv2.rectangle(img,(a.left(),a.top()),(a.right(),a.bottom()),(255,0,0))
#point_list=[]#save the mouth point to point_list[]#
#Extract 68 feature points of the face and crop the lip image#
for index, face in enumerate(dets):
print(‘face {}; left {}; top {}; right {}; bottom {}’.format(index, face.left(), face.top(), face.right(), face.bottom()))
shape = predictor(gray, face)
for i, pt in enumerate(shape.parts()):
#print(‘Part {}: {}’.format(i, pt))
#print(i)
pt_pos = (pt.x, pt.y)
if i>=48 and i<=67:
cv2.circle(img, pt_pos, 2, (255, 0, 0), 1)
if i>=56 and i<=58:
#print(pt_pos)
pos[i-56][0]=pt.x
pos[i-56][1]=pt.y
#cv2.circle(img, pt_pos, 2, (255, 0, 0), 1)
return img

if name == “main”:
img = cv2.imread(“test3.png”)
#copy the input image for the later crop#
img_clOne= np.copy(img)
cv2.imwrite(“input/source.jpg”,img_clone)
#save the lip position to pos array#
pos=np.zeros((3,2), dtype=int)
result=detect_mouth(img,pos)
cv2.imwrite(“input/source2.jpg”,result)
#crop the lip areas#
source = cv2.imread(“input/source.jpg”)
crop(source,pos)


show the result

cv2.imshow(‘FaceDetect’,result)
cv2.waitKey(0)
cv2.destroyAllWindow

既然已经截取到嘴唇的小矩形图像了,接下来的工作就和前面一样了,在数据库中对比每个 RGB 值输出最小误差对应的口红信息,而这儿也有难到我。

单纯的比对 RGB 分量对口红色号来说并不适用,有可能每个分量相差很小,而叠加起来的颜色和提取到的颜色并不相似,在颜色的比对上需要手动调参。

几经波折,最后输出的结果还是可以接受的,上图人像中涂的口红色号,感兴趣的读者可以查下正好是下面输出排名第一的口红信息。

#####误差分析

对于我们测试的图片信息,标记了嘴唇区域的特征点,我们提取到的 RGB 值(156,59,103)颜色如下所示:

可以看到和图片的颜色已经十分接近了,而数据集合 lipstick.json 中这种口红存储的 16 进制颜色值为 #842C71,对应的颜色如下:

明显看到数据集存储的颜色和实际照片的颜色是有些许误差的,而在本文算法实现过程中,又不可避免的有以下误差:


  • 嘴唇区域截取不可避免会截取到皮肤中的一部分颜色,虽然算法已经将那种可能降到最低。
  • 颜色提取上,虽然截取多个嘴唇图片求平均值,但是本身的提取算法还是和实际值稍有偏差。
  • RGB 颜色相似度比对的算法也不够精确。
  • 最最重要的是,照片必须是原图,而且光线要自然,加了滤镜的图是怎么也不可能识别出来的。

以上种种,使得让计算机快速高效地识别不同的口红色号还是有困难的,原来计算机有时候也会很直男。

#####实时人像口红色号预测

看到这儿,可能很多读者朋友想实时地试一下能不能让计算机判断自己的口红色号,这对于 OpenCV 这一强大的图形操作库来说,不是什么问题。

它可以打开你的摄像头,读取每一帧的图片,结合前文提到的人脸识别代码,可以实时地截取到嘴唇区域的图片,然后交给计算机预测,从此再也不怕女朋友的灵魂拷问!


最后,附上打开摄像头的代码,快叫女朋友过来试下吧!

#coding=utf8
import cv2
import time
print(‘Press Esc to exit’)
imgWindow = cv2.namedWindow(‘FaceDetect’, cv2.WINDOW_NORMAL)
import sys
import os
import dlib
import glob
import numpy
from skimage import io
def detect_face():
capInput = cv2.VideoCapture(0)
#nextCaptureTime = time.time()
faces = []
feas = []
if not capInput.isOpened(): print(‘Capture failed because of camera’)
while 1:
ret, img = capInput.read()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = cv2.equalizeHist(gray)
time=0
eTime = time.time() + 0.1
detector = dlib.get_frontal_face_detector() 
predictor = dlib.shape_predictor(‘shape_predictor_68_face_landmarks.dat’)
dets = detector(gray, 1)
print(“Number of faces detected: {}”.format(len(dets)))
for a in dets:
cv2.rectangle(img,(a.left(),a.top()),(a.right(),a.bottom()),(255,0,0))
for index, face in enumerate(dets):
print(‘face {}; left {}; top {}; right {}; bottom {}’.format(index, face.left(), face.top(), face.right(), face.bottom()))
shape = predictor(gray, face)
(“Number of faces detected: {}”.format(len(dets)))
for a in dets:
cv2.rectangle(img,(a.left(),a.top()),(a.right(),a.bottom()),(255,0,0))
for index, face in enumerate(dets):
print(‘face {}; left {}; top {}; right {}; bottom {}’.format(index, face.left(), face.top(), face.right(), face.bottom()))
shape = predictor(gray, face)


推荐阅读
  • IjustinheritedsomewebpageswhichusesMooTools.IneverusedMooTools.NowIneedtoaddsomef ... [详细]
  • Day2列表、字典、集合操作详解
    本文详细介绍了列表、字典、集合的操作方法,包括定义列表、访问列表元素、字符串操作、字典操作、集合操作、文件操作、字符编码与转码等内容。内容详实,适合初学者参考。 ... [详细]
  • 欢乐的票圈重构之旅——RecyclerView的头尾布局增加
    项目重构的Git地址:https:github.comrazerdpFriendCircletreemain-dev项目同步更新的文集:http:www.jianshu.comno ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • Python瓦片图下载、合并、绘图、标记的代码示例
    本文提供了Python瓦片图下载、合并、绘图、标记的代码示例,包括下载代码、多线程下载、图像处理等功能。通过参考geoserver,使用PIL、cv2、numpy、gdal、osr等库实现了瓦片图的下载、合并、绘图和标记功能。代码示例详细介绍了各个功能的实现方法,供读者参考使用。 ... [详细]
  • 标题: ... [详细]
  • 摘要: 在测试数据中,生成中文姓名是一个常见的需求。本文介绍了使用C#编写的随机生成中文姓名的方法,并分享了相关代码。作者欢迎读者提出意见和建议。 ... [详细]
  • 本文讨论了Kotlin中扩展函数的一些惯用用法以及其合理性。作者认为在某些情况下,定义扩展函数没有意义,但官方的编码约定支持这种方式。文章还介绍了在类之外定义扩展函数的具体用法,并讨论了避免使用扩展函数的边缘情况。作者提出了对于扩展函数的合理性的质疑,并给出了自己的反驳。最后,文章强调了在编写Kotlin代码时可以自由地使用扩展函数的重要性。 ... [详细]
  • 本文介绍了机器学习手册中关于日期和时区操作的重要性以及其在实际应用中的作用。文章以一个故事为背景,描述了学童们面对老先生的教导时的反应,以及上官如在这个过程中的表现。同时,文章也提到了顾慎为对上官如的恨意以及他们之间的矛盾源于早年的结局。最后,文章强调了日期和时区操作在机器学习中的重要性,并指出了其在实际应用中的作用和意义。 ... [详细]
  • 这篇文章主要介绍了Python拼接字符串的七种方式,包括使用%、format()、join()、f-string等方法。每种方法都有其特点和限制,通过本文的介绍可以帮助读者更好地理解和运用字符串拼接的技巧。 ... [详细]
author-avatar
航19830_811
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有