![640?wx_fmt=1](https://img-blog.csdnimg.cn/img_convert/bdf7c116d08c6270a13a89cfd6d634e5.png)
![640?wx_fmt=jpeg](https://img-blog.csdnimg.cn/img_convert/98f2c09045d436481bb1f3d618f9845b.png)
![640?wx_fmt=gif](https://img-blog.csdnimg.cn/img_convert/de1ae0494acbb4ed4f2a799ba87ab76a.gif)
![640?wx_fmt=gif](https://img-blog.csdnimg.cn/img_convert/c914a4ce22c685ca7d1aea988cdc3e40.gif)
![640?wx_fmt=jpeg](https://img-blog.csdnimg.cn/img_convert/57bb0e637e01f457e06fda9b15e90395.png)
![640?wx_fmt=png](https://img-blog.csdnimg.cn/img_convert/53ded63869434ea0015b3aef809c6e37.png)
![640?wx_fmt=png](https://img-blog.csdnimg.cn/img_convert/ac07590c6888348e95e6f5c3e1094a12.png)
来自Github的口红色号宇宙
![640?wx_fmt=gif](https://img-blog.csdnimg.cn/img_convert/5a10d050735c8eba02a884b9a2d4ec0b.gif)
![640?wx_fmt=png](https://img-blog.csdnimg.cn/img_convert/90c0a8db49ac272ddd98b28335961ce8.png)
https://github.com/Ovilia/lipstick
![640?wx_fmt=png](https://img-blog.csdnimg.cn/img_convert/1d08638c761481a7f90da369a1d98bc3.png)
傻傻分不清的文摘菌对5个品牌的不同系列做了一下统计和色号录入,于是,剩下的就交给计算机啦。
先用番茄做个实验?
![640?wx_fmt=jpeg](https://img-blog.csdnimg.cn/img_convert/fcb4eaa43dbd6146d12fd6879ef66010.png)
文摘菌在其中截取了成色均匀、无高亮的矩形图片:
![640?wx_fmt=jpeg](https://img-blog.csdnimg.cn/img_convert/e4eb9ef4bf4e3ad5f3eaf3cd1ac171f3.png)
import colorsys
import PIL.Image as Image
def get_dominant_color(image):
max_score = 0.0001
dominant_color = None
for count,(r,g,b) in image.getcolors(image.size[0]*image.size[1]):
# 转为HSV标准
saturation = colorsys.rgb_to_hsv(r/255.0, g/255.0, b/255.0)[1]
y = min(abs(r*2104+g*4130+b*802+4096+131072)>>13,235)
y = (y-16.0)/(235-16)
#忽略高亮色
if y > 0.9:
continue
score = (saturation+0.1)*count
if score > max_score:
max_score = score
dominant_color = (r,g,b)
return dominant_color
为了减少误差,需要裁剪多个不同位置的图片,保存在本地的一个文件夹中,读取文件,提取颜色,求平均值,得到的番茄最终的RGB颜色,代码如下:
import os
import getcolor
from os.path import join as pjoin
from scipy import misc
def load_color(color_dir,list):
count = 0
for dir in os.listdir(color_dir):
img_dir = pjoin(color_dir, dir)
image = getcolor.Image.open(img_dir)
image = image.convert('RGB')
get=getcolor.get_dominant_color(image)
list.append(get)
count = count+1
#print(person_dir)
#print(count)
return count
def Mean_color(count,list):
Mean_R=Mean_G=Mean_B=0
for i in range(count):
tuple=list[i]
Mean_R+=tuple[0]
Mean_G+=tuple[1]
Mean_B+=tuple[2]
MeanC=((int)(Mean_R/count),(int)(Mean_G/count),(int)(Mean_B/count))
return Me
番茄的颜色提取到了,那么和什么做比对呢?
{"brands":[{"name":"圣罗兰","series":
[{"name":"莹亮纯魅唇膏","lipsticks":
[{"color":"#D62352","id":"49","name":"撩骚"},
{"color":"#DC4B41","id":"14","name":"一见倾心"},
{"color":"#B22146","id":"05","name":"浮生若梦"},
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)) # <class 'dict'>
#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>='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中的运行结果:
![640?wx_fmt=png](https://img-blog.csdnimg.cn/img_convert/233e9f060a697011e3f8bc168f548d64.png)
可以看到最有可能的三个口红品牌色号的RGB值与番茄的RGB值是非常接近的:
![640?wx_fmt=png](https://img-blog.csdnimg.cn/img_convert/5a0918c3ddaac059da1c877cb1ba31dc.png)
![640?wx_fmt=png](https://img-blog.csdnimg.cn/img_convert/22656d70f2d4268c52a53cdbc4af446f.png)
![640?wx_fmt=png](https://img-blog.csdnimg.cn/img_convert/93a0a854aa54a8b175b0fe7b66ed6869.png)
![640?wx_fmt=png](https://img-blog.csdnimg.cn/img_convert/626af41364fb2e319abcfc866c823301.png)
![640?wx_fmt=png](https://img-blog.csdnimg.cn/img_convert/10444fc6e6653c24154a81378752501f.png)
![640?wx_fmt=jpeg](https://img-blog.csdnimg.cn/img_convert/a7ae77ef1e9e680e8b656bbd4e988230.png)
![640?wx_fmt=jpeg](https://img-blog.csdnimg.cn/img_convert/05c5c2baeb277c1c26396b26262004e3.png)
![640?wx_fmt=jpeg](https://img-blog.csdnimg.cn/img_convert/d4a9fff50315286a480d359f9b7928ab.png)
圣罗兰官网#842C71口红
![640?wx_fmt=jpeg](https://img-blog.csdnimg.cn/img_convert/5931307c60ad3b7b232c4bbf0d30f2c0.png)
![640?wx_fmt=jpeg](https://img-blog.csdnimg.cn/img_convert/3d8a960664a7ec071f6163437775a751.png)
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分量对口红色号来说并不适用,有可能每个分量相差很小,而叠加起来的颜色和提取到的颜色并不相似,在颜色的比对上需要手动调参。
![640?wx_fmt=png](https://img-blog.csdnimg.cn/img_convert/2566fab3b63f1cea94a29a1b5f72f174.png)
误差分析
![640?wx_fmt=jpeg](https://img-blog.csdnimg.cn/img_convert/67fe0f3c214f4ad7832b159386052db3.png)
对于我们测试的图片信息,文摘菌标记了嘴唇区域的特征点,我们提取到的RGB值(156,59,103)颜色如下所示:
![640?wx_fmt=png](https://img-blog.csdnimg.cn/img_convert/51eda4a0d19e257a217d67138e8670e4.png)
可以看到和图片的颜色已经十分接近了,而数据集合lipstick.json中这种口红存储的16进制颜色值为#842C71,对应的颜色如下:
![640?wx_fmt=png](https://img-blog.csdnimg.cn/img_convert/a90d40a57aa21e53bc3af95e3d4e72e5.png)
- 嘴唇区域截取不可避免会截取到皮肤中的一部分颜色,虽然算法已经将那种可能降到最低;
- 颜色提取上,虽然截取多个嘴唇图片求平均值,但是本身的提取算法还是和实际值稍有偏差;
- RGB颜色相似度比对的算法也不够精确;
- 最最重要的是,照片必须是原图,而且光线要自然,加了滤镜的图是怎么也不可能识别出来的。
文末福利:实时人像口红色号预测
![640?wx_fmt=gif](https://img-blog.csdnimg.cn/img_convert/eb5060a66bc4c99ed4e2267d9af8f8e2.gif)
#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)
for i, pt in enumerate(shape.parts()):
#print('Part {}: {}'.format(i, pt))
pt_pos = (pt.x, pt.y)
cv2.circle(img, pt_pos, 2, (255, 0, 0), 1)
cv2.imshow('FaceDetect',img)
if cv2.waitKey(1) & 0xFF == 27: break
capInput.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
detect_face()
好啦,佳期如梦,双星良夜,在这个充满爱意的日子里,定位好女神常用的口红色号,和那个她来场华丽的邂逅吧!
![https://image.ipaiban.com/upload-ueditor-image-20180820-1534742744952070338.jpeg 640?wx_fmt=jpeg](https://img-blog.csdnimg.cn/img_convert/6757c24926bb51e0a4d37c8c168802d7.png)
CDA 课程咨询丨史老师
联系电话:18080942131![502750988653783233.jpg 640?wx_fmt=jpeg](https://img-blog.csdnimg.cn/img_convert/d174d8effe1f5f035f1e4f580252e8fe.png)