조수연

알고리즘 업데이트 1, read me 수정

# Find your Personal Color
자가진단 서비스와 openCV를 활용한 퍼스널 컬러 찾아주는 React 기반의 웹 서비스
# Find your Personal Color
## 요약
자가진단 설문와 openCV를 활용한 퍼스널 컬러 찾아주는 React 기반의 웹 서비스
## 상세
###1. 서비스
기존에 있는 퍼스널 컬러 진단 서비스는 대부분 사용자 이미지를 분석하고 퍼스널 컬러를 찾아주거나, 자가진단 설문을 통해 퍼스널 컬러를 알려주는 두 형태 중 한가지 형태로 진행되는 경우가 많았습니다. 저희는 두가지 서비스 모두를 구현하여 사용자들이 좀 더 정확한 퍼스널 컬러를 확인할 수 있도록 했습니다.
### 2. front
### 3. back
# 전체 서비스
// 전체 서비스 동작 이미지//
# 알고리즘
💻마더 프로젝트에서 가져온 알고리즘을 수정 및 개선하였습니다.💻
유저 이미지의 피부 사진을 가져와 평균 색깔을 추출합니다. 이를 토대로 이미지 RGB 값을 Lab 색 공간을 변환합니다. Lab b 값(푸른색의 정도)을 웜톤, 쿨톤의 스탠다드 값과의 거리를 계산하여 웜톤과 쿨톤을 구별합니다.
// 알고리즘 이미지//
원본 알고리즘은 눈썹과 눈동자도 계산하여 가중치를 곱한 후, 계절을 구별하도록 하였는데, 이는 저희가 생각한 limit 정확도보다 떨어져서 계절 구별은 이미지 분석이 아닌 자가진단 설문에서만 구현했습니다.
또한, 원본 알고리즘은 웜톤과 쿨톤의 스탠다드 값을 연예인들의 이미지를 학습시켜 평균치를 구했는데, 본래 이미지를 통해서 확인하는 퍼스널 컬러는 조명, 화이트 밸런스, 화장 여부 등에 의해 영향을 많이 받기 때문에 이 부분을 수정하였습니다. 퍼스널 컬러 대표 색 이미지들의 Lab b값을 training시켜, 그 평균치를 스탠다드 값으로 업데이트 하였습니다.
# 빌드 방법
......
#!/usr/bin/env python
# coding: utf-8
# In[72]:
# 평균 색상 추출
import cv2
import numpy as np
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from skimage import io
from itertools import compress
# tone 구별
from scipy.spatial import distance
import copy
import math
import operator
# main함수
from colormath.color_objects import LabColor, sRGBColor, HSVColor
from colormath.color_conversions import convert_color
# color extract 클래스
class DominantColors:
CLUSTERS = None
IMAGE = None
COLORS = None
LABELS = None
def __init__(self, image, clusters=3):
self.CLUSTERS = clusters
img = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
self.IMAGE = img.reshape((img.shape[0] * img.shape[1], 3))
#using k-means to cluster pixels
kmeans = KMeans(n_clusters = self.CLUSTERS)
kmeans.fit(self.IMAGE)
#the cluster centers are our dominant colors.
self.COLORS = kmeans.cluster_centers_
self.LABELS = kmeans.labels_
def rgb_to_hex(self, rgb):
return '#%02x%02x%02x' % (int(rgb[0]), int(rgb[1]), int(rgb[2]))
# Return a list in order of color that appeared most often.
def getHistogram(self):
numLabels = np.arange(0, self.CLUSTERS+1)
#create frequency count tables
(hist, _) = np.histogram(self.LABELS, bins = numLabels)
hist = hist.astype("float")
hist /= hist.sum()
colors = self.COLORS
#descending order sorting as per frequency count
colors = colors[(-hist).argsort()]
hist = hist[(-hist).argsort()]
for i in range(self.CLUSTERS):
colors[i] = colors[i].astype(int)
# Blue mask 제거
fil = [colors[i][2] < 250 and colors[i][0] > 10 for i in range(self.CLUSTERS)]
colors = list(compress(colors, fil))
return colors, hist
def plotHistogram(self):
colors, hist = self.getHistogram()
#creating empty chart
chart = np.zeros((50, 500, 3), np.uint8)
start = 0
#creating color rectangles
for i in range(len(colors)):
end = start + hist[i] * 500
r,g,b = colors[i]
#using cv2.rectangle to plot colors
cv2.rectangle(chart, (int(start), 0), (int(end), 50), (r,g,b), -1)
start = end
#display chart
plt.figure()
plt.axis("off")
plt.imshow(chart)
plt.show()
return colors
#tone analysis 함수
def is_warm(lab_b, a):
'''
파라미터 lab_b = [skin_b, hair_b, eye_b]
a = 가중치 [skin, hair, eye]
질의색상 lab_b값에서 warm의 lab_b, cool의 lab_b값 간의 거리를
각각 계산하여 warm이 가까우면 1, 반대 경우 0 리턴
'''
# standard of skin, eyebrow, eye (눈썹, 눈동자는 0으로)
warm_b_std = [38.022000000000006, 0, 0]
cool_b_std = [17, 0, 0]
warm_dist = 0
cool_dist = 0
body_part = ['skin', 'eyebrow', 'eye']
for i in range(1):
warm_dist += abs(lab_b[i] - warm_b_std[i]) * a[i]
print(body_part[i],"의 warm 기준값과의 거리")
print(abs(lab_b[i] - warm_b_std[i]))
cool_dist += abs(lab_b[i] - cool_b_std[i]) * a[i]
print(body_part[i],"의 cool 기준값과의 거리")
print(abs(lab_b[i] - cool_b_std[i]))
if(warm_dist <= cool_dist):
return 1 #warm
else:
return 0 #cool
# 이미지 자르는 함수
def trimming (img):
x = 100;
y = 100;
w = 100;
h = 100;
img_trim = img[y:y+h, x:x+w]
return img_trim
# 원래 main
def analysis(imgpath):
#######################################
# Face detection #
#######################################
img=cv2.imread(imgpath)
h,w,c=img.shape
if((h>500) and (w>500)):
img = trimming(img) # 이미지가 너무 크면 잘라서 확인
face = [img, img,
img, img,
img, img]
#######################################
# Get Dominant Colors #
#######################################
temp = []
clusters = 4
for f in face:
dc = DominantColors(f, clusters)
face_part_color, _ = dc.getHistogram()
#dc.plotHistogram()
temp.append(np.array(face_part_color[0]))
cheek1 = np.mean([temp[0], temp[1]], axis=0)
cheek2 = np.mean([temp[2], temp[3]], axis=0)
cheek3 = np.mean([temp[4], temp[5]], axis=0)
Lab_b, hsv_s = [], []
color = [cheek1, cheek2, cheek3]
for i in range(3):
rgb = sRGBColor(color[i][0], color[i][1], color[i][2], is_upscaled=True)
lab = convert_color(rgb, LabColor, through_rgb_type=sRGBColor)
hsv = convert_color(rgb, HSVColor, through_rgb_type=sRGBColor)
Lab_b.append(float(format(lab.lab_b,".2f")))
hsv_s.append(float(format(hsv.hsv_s,".2f"))*100)
Lab_b[1]=0
Lab_b[2]=0
print('Lab_b[skin]',Lab_b[0])
#######################################
# Personal color Analysis #
#######################################
Lab_weight = [100, 0, 0]
hsv_weight = [10, 0, 0]
if(is_warm(Lab_b, Lab_weight)):
tone = '웜톤(warm)'
else:
tone = '쿨톤(cool)'
# Print Result
print('{}의 퍼스널 컬러는 {}입니다.'.format(imgpath, tone))
def main():
analysis('color_data\warm_spring.png')
if __name__ == '__main__':
main()
# In[ ]:
No preview for this file type
cool
14
19
24
13
6
11
28
22
14
19
17
warm
46.47
35.13
29.34
36.69
29.44
25.49
29.32
36.6
45.54
21.43
21.52
23.25
86
\ No newline at end of file