這篇文章主要介紹“怎么用github寫(xiě)個(gè)口紅色號(hào)識(shí)別器”,在日常操作中,相信很多人在怎么用github寫(xiě)個(gè)口紅色號(hào)識(shí)別器問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”怎么用github寫(xiě)個(gè)口紅色號(hào)識(shí)別器”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!
成都創(chuàng)新互聯(lián)公司堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:網(wǎng)站建設(shè)、成都網(wǎng)站制作、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿(mǎn)足客戶(hù)于互聯(lián)網(wǎng)時(shí)代的賓縣網(wǎng)站設(shè)計(jì)、移動(dòng)媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!
來(lái)自 Github 的口紅色號(hào)宇宙
要想識(shí)別口紅色號(hào),先得讓機(jī)器知道到底都有哪些顏色。
聽(tīng)柜姐介紹,紅色系有:“草莓紅、鐵銹紅、楓葉紅...”,其他還有“豆沙色、吃土色、番茄色...”
世界觀(guān)還未建立完全就要開(kāi)始土崩瓦解,這看著有區(qū)別嗎?“豆沙色最為百搭,橘調(diào)的番茄色比較顯白...”眼前的黑不是黑,你說(shuō)的紅是什么紅?
還好,在萬(wàn)能的 Github 上找到了一個(gè)寶藏?cái)?shù)據(jù)庫(kù)“口紅顏色可視化”,這個(gè)數(shù)據(jù)庫(kù)堪比口紅的色號(hào)宇宙,不僅囊括了當(dāng)前最主流品牌的各種系列色號(hào),還很良心的在色盤(pán)上排列了出來(lái)。
這個(gè)數(shù)據(jù)集是一個(gè)嵌套的字典數(shù)據(jù)結(jié)構(gòu),存為 json 串的形式,里面記錄了每個(gè)口紅品牌系列下不同口紅色號(hào)的顏色 id、名稱(chēng)、和 16 進(jìn)制顏色值。
直!男!救!星!有木有!
口紅色號(hào)可視化鏈接:
https://github.com/Ovilia/lipstick
不過(guò)看著這密密麻麻的顏色,真心佩服各大口紅品牌的文案高手,是怎么樣區(qū)別每一個(gè)看不出區(qū)別的顏色,并且還要分別取名字的。
傻傻分不清的我對(duì) 5 個(gè)品牌的不同系列做了一下統(tǒng)計(jì)和色號(hào)錄入,于是,剩下的就交給計(jì)算機(jī)啦。
先用番茄做個(gè)實(shí)驗(yàn)?
既然有了如此完備的色號(hào)數(shù)據(jù)庫(kù),那么文摘菌就有了一個(gè)討巧的方法:要想找到合適的色號(hào),可以直接截取顏色,然后在數(shù)據(jù)庫(kù)中進(jìn)行比對(duì)。
這個(gè)方法非常好操作,在上唇色之前,我們不如先拿別的紅色物品來(lái)練手。
比如,這里有一只番茄圖片,你看這個(gè)番茄它又大又圓:
在其中截取了成色均勻、無(wú)高亮的矩形圖片:
提取這張純色圖片的 RGB 值在技術(shù)上是可行的,getcolor.py 代碼如下:
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]): # 轉(zhuǎn)為HSV標(biāo)準(zhǔn) 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
為了減少誤差,需要裁剪多個(gè)不同位置的圖片,保存在本地的一個(gè)文件夾中,讀取文件,提取顏色,求平均值,得到的番茄最終的 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
番茄的顏色提取到了,那么和什么做比對(duì)呢?
當(dāng)然是口紅的數(shù)據(jù),文摘菌這兒用到了 5 個(gè)品牌,分別是圣羅蘭、香奈兒可可小姐、迪奧、美寶蓮、紀(jì)梵希,共 17 個(gè)系列,271 個(gè)口紅色號(hào)。
數(shù)據(jù)集是一個(gè)嵌套的字典數(shù)據(jù)結(jié)構(gòu),存為 json 串的形式,里面記錄了每個(gè)口紅品牌系列下不同口紅色號(hào)的顏色 id、名稱(chēng)、和 16 進(jìn)制顏色值。
lipstick.json部分?jǐn)?shù)據(jù)集展示如下:
{"brands":[{"name":"圣羅蘭","series": [{"name":"瑩亮純魅唇膏","lipsticks": [{"color":"#D62352","id":"49","name":"撩騷"}, {"color":"#DC4B41","id":"14","name":"一見(jiàn)傾心"}, {"color":"#B22146","id":"05","name":"浮生若夢(mèng)"},
數(shù)據(jù)集中存儲(chǔ)的 RGB 顏色是 16 進(jìn)制的字符串形式,需要將其轉(zhuǎn)換成 RGB 值,比較兩個(gè)顏色相近與否。
實(shí)際上是比較 RGB 三個(gè)分量維度上的誤差,最小的口紅輸出對(duì)應(yīng)的品牌、系列、色號(hào)和 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>='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
輸出最有可能吻合番茄顏色的前三個(gè)口紅的信息,然后在 Spyder 中的運(yùn)行結(jié)果:
可以看到最有可能的三個(gè)口紅品牌色號(hào)的 RGB 值與番茄的 RGB 值是非常接近的。
提取到的番茄顏色:
'迪奧' '烈艷藍(lán)金唇膏' '080' '微笑正紅’的顏色:
'圣羅蘭' '純口紅' '56' '橙紅織錦'的顏色:
'紀(jì)梵希' '高定香榭天鵝絨唇' '325' '圣水紅'的顏色:
我已經(jīng)眼花繚亂,三個(gè)顏色……有區(qū)別嗎?!以后不如準(zhǔn)備統(tǒng)一叫它們,番茄色!
不過(guò),這也正說(shuō)明了,剛剛的提取&對(duì)比方法可行!
既然可以識(shí)別番茄的顏色,那么,可以識(shí)別人像中的口紅色號(hào)嗎?
進(jìn)入正題!人像口紅色號(hào)識(shí)別
接下來(lái),我們需要做的是輸入一張人像圖片,可以自動(dòng)識(shí)別其中的嘴唇區(qū)域,并提取出嘴唇區(qū)域中的一部分做為顏色提取的源圖像。
這里就要用到 CV 的人臉識(shí)別了,還好 Dlib 庫(kù)又幫助我們減輕一大部分的工作量。
Dlib 中有自帶的 68 個(gè)人臉的識(shí)別器,可以得到人臉部位包括眉毛、眼睛、鼻梁、面部輪廓和嘴唇區(qū)域的具體點(diǎn)的位置,到這兒,我以為很輕松就可以截到嘴唇區(qū)域了,結(jié)果有點(diǎn)尷尬.........
我們首先找到了一張小姐姐的照片:
截取到的嘴唇區(qū)域如下:
很明顯的看到上下嘴唇黑色的區(qū)域也截取到了,這對(duì)后續(xù)的提色有影響,所以不得不回到最初的 68 個(gè)檢測(cè)點(diǎn)來(lái)思考人生。
圣羅蘭官網(wǎng) #842C71 口紅
標(biāo)記的 68 個(gè)人臉檢測(cè)點(diǎn)如上圖所示,而嘴唇部位是從第 49 個(gè)標(biāo)記點(diǎn)開(kāi)始的(數(shù)組的話(huà),下標(biāo)是 48)。
為了盡可能的截取到均勻成色的嘴唇片段,剛開(kāi)始是想從第 50 個(gè)標(biāo)記點(diǎn)對(duì)角線(xiàn)截取到第 56 個(gè)標(biāo)記點(diǎn),而這不可避免的會(huì)截取到上下嘴唇之間的縫隙,這兒的陰影也會(huì)影響后續(xù)的顏色提取準(zhǔn)確度。
考慮到下嘴唇比上嘴唇寬,所以截取到下嘴唇中間的兩個(gè)小正方形區(qū)域:
人臉識(shí)別和截取嘴唇區(qū)域的代碼如下:
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/Mouth2.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/Mouth3.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
既然已經(jīng)截取到嘴唇的小矩形圖像了,接下來(lái)的工作就和前面一樣了,在數(shù)據(jù)庫(kù)中對(duì)比每個(gè) RGB 值輸出最小誤差對(duì)應(yīng)的口紅信息,而這兒也有難到我。
單純的比對(duì) RGB 分量對(duì)口紅色號(hào)來(lái)說(shuō)并不適用,有可能每個(gè)分量相差很小,而疊加起來(lái)的顏色和提取到的顏色并不相似,在顏色的比對(duì)上需要手動(dòng)調(diào)參。
幾經(jīng)波折,最后輸出的結(jié)果還是可以接受的,上圖人像中涂的口紅色號(hào),感興趣的讀者可以查下正好是下面輸出排名第一的口紅信息。
誤差分析
對(duì)于我們測(cè)試的圖片信息,標(biāo)記了嘴唇區(qū)域的特征點(diǎn),我們提取到的 RGB 值(156,59,103)顏色如下所示:
可以看到和圖片的顏色已經(jīng)十分接近了,而數(shù)據(jù)集合 lipstick.json 中這種口紅存儲(chǔ)的 16 進(jìn)制顏色值為 #842C71,對(duì)應(yīng)的顏色如下:
明顯看到數(shù)據(jù)集存儲(chǔ)的顏色和實(shí)際照片的顏色是有些許誤差的,而在本文算法實(shí)現(xiàn)過(guò)程中,又不可避免的有以下誤差:
嘴唇區(qū)域截取不可避免會(huì)截取到皮膚中的一部分顏色,雖然算法已經(jīng)將那種可能降到最低。
顏色提取上,雖然截取多個(gè)嘴唇圖片求平均值,但是本身的提取算法還是和實(shí)際值稍有偏差。
RGB 顏色相似度比對(duì)的算法也不夠精確。
最最重要的是,照片必須是原圖,而且光線(xiàn)要自然,加了濾鏡的圖是怎么也不可能識(shí)別出來(lái)的。
以上種種,使得讓計(jì)算機(jī)快速高效地識(shí)別不同的口紅色號(hào)還是有困難的,原來(lái)計(jì)算機(jī)有時(shí)候也會(huì)很直男。
實(shí)時(shí)人像口紅色號(hào)預(yù)測(cè)
看到這兒,可能很多讀者朋友想實(shí)時(shí)地試一下能不能讓計(jì)算機(jī)判斷自己的口紅色號(hào),這對(duì)于 OpenCV 這一強(qiáng)大的圖形操作庫(kù)來(lái)說(shuō),不是什么問(wèn)題。
它可以打開(kāi)你的攝像頭,讀取每一幀的圖片,結(jié)合前文提到的人臉識(shí)別代碼,可以實(shí)時(shí)地截取到嘴唇區(qū)域的圖片,然后交給計(jì)算機(jī)預(yù)測(cè),從此再也不怕女朋友的靈魂拷問(wèn)!
最后,附上打開(kāi)攝像頭的代碼,快叫女朋友過(guò)來(lái)試下吧!
#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()
到此,關(guān)于“怎么用github寫(xiě)個(gè)口紅色號(hào)識(shí)別器”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!