poc-elc-ai / src / color_analysis.py
color_analysis.py
Raw
import sys
import base64

import cv2
import ast
from collections import Counter
from sklearn.cluster import KMeans
import numpy as np
import pandas as pd
import pickle as cPickle
import face_cropper


def extract_face_images(image):
    face_model = face_cropper.FaceCropper(min_face_detector_confidence=0.5, face_detector_model_selection=0,
                                          landmark_detector_static_image_mode=True,
                                          min_landmark_detector_confidence=0.5)
    face_image, hair_image, eyes = face_model.get_head_segments(image)
    return face_image, hair_image, eyes


def palette_perc(k_cluster):
    n_pixels = len(k_cluster.labels_)
    counter = Counter(k_cluster.labels_)  # count how many pixels per cluster
    perc = {}
    for i in counter:
        perc[i] = np.round(counter[i] / n_pixels, 2)
    perc = dict(sorted(perc.items()))

    palette = pd.DataFrame()
    for i in range(0, 5):
        add = pd.DataFrame({"color": str(list(k_cluster.cluster_centers_[i])), "perc": perc[i]}, index=[0])
        palette = pd.concat([palette, add], axis=0, ignore_index=True)
    palette.color = palette.color.apply(lambda x: ast.literal_eval(x))

    for i in range(0, len(palette)):
        color_list = palette.color[i]
        j2 = list(filter(lambda x: x >= 230, color_list))
        if len(j2) == 3:
            palette = palette.drop(i, axis=0)
    palette = palette.reset_index(drop=True)
    return palette


def resize_image(img):
    wanted_width = 500
    height, width, _ = img.shape
    aspect_ratio = width / height
    wanted_height = int(wanted_width / aspect_ratio)
    resized_img = cv2.resize(img, (wanted_width, wanted_height))
    return resized_img


def find_color_palette(img):
    img = resize_image(img)
    clt = KMeans(n_clusters=5, n_init=10)
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    clt_1 = clt.fit(img.reshape(-1, 3))
    palette = palette_perc(clt_1)
    selected_color = (palette[palette.perc == palette.perc.max()].reset_index(drop=True)).loc[0, "color"]
    return selected_color


def color_season(image):
    try:
        face_image, hair_image, eyes = extract_face_images(image)
    except:
        return ""
    hair_color = find_color_palette(hair_image)
    skin_color = find_color_palette(face_image)
    eye_color = find_color_palette(eyes)

    with open('./color_palette_classifier.pkl', 'rb') as file_id:
        classifier = cPickle.load(file_id)

    personal_colors = pd.DataFrame({"hair_r": hair_color[0], "hair_g": hair_color[1], "hair_b": hair_color[2],
                                    "eye_r": eye_color[0], "eye_g": eye_color[1], "eye_b": eye_color[2],
                                    "skin_r": skin_color[0], "skin_g": skin_color[1], "skin_b": skin_color[2]},
                                   index=[0])
    selected_palette = classifier.predict(personal_colors)
    return selected_palette[0].replace("_", " ")


def color_analysis(im_b64):
    im_bytes = base64.b64decode(im_b64)
    im_arr = np.frombuffer(im_bytes, dtype=np.uint8)  # im_arr is one-dim Numpy array
    image = cv2.imdecode(im_arr, flags=cv2.IMREAD_COLOR)
    color_theme = color_season(image)

    if color_theme == "soft spring":
        color_theme = "light spring"
    if color_theme == "clear summer":
        color_theme = "soft summer"
    if color_theme == "clear autumn":
        color_theme = "deep autumn"
    if color_theme == "clear winter":
        color_theme = "deep winter"
    if color_theme == "soft winter":
        color_theme = "clear winter"
    return color_theme


if __name__ == "__main__":
    im_b64 = sys.argv[1]
    print(color_analysis(im_b64))