File size: 8,711 Bytes
9536830
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
from fastai.vision.all import *
import gradio as gr
import pathlib
import cv2
import dlib
import numpy as np
import mediapipe as mp
from imutils import face_utils
from PIL import Image
import time
from dotenv import load_dotenv
import os

load_dotenv()

colorDict = eval(os.getenv('color-dict'))
makeup_recommendations = eval(os.getenv('makeup_recommendations'))

plt = platform.system()
if plt == 'Windows': pathlib.PosixPath = pathlib.WindowsPath

def rgb_to_bgr(rgb_color):
    r, g, b = rgb_color
    return (b, g, r)

image_path = None
lipstick_shade = None
foundation_color = None
powder_color = None

# Function to get makeup recommendations
def get_makeup_recommendation(skin_tone):
    global lipstick_shade, foundation_color, powder_color
    if skin_tone in makeup_recommendations:
        lipstick_shade = makeup_recommendations[skin_tone]['Lipstick Shade']
        foundation_color = makeup_recommendations[skin_tone]['Foundation Shade']
        powder_color = makeup_recommendations[skin_tone]['Powder Shade']
        return makeup_recommendations[skin_tone]
    return {'Foundation Shade': '', 'Lipstick Shade': '', 'Powder Shade': '', 'Brands': {}}


# Function to save the uploaded image
def save_uploaded_image(img):
    global image_path
    image_path = "uploaded_image_"+str(round(time.time() * 1000))+".png"
    img.save(image_path)
    return image_path

# Load the trained model
learn = load_learner('export.pkl')

# Prediction and recommendation function
def classify_and_recommend(img):
    # Save the uploaded image
    img_path = save_uploaded_image(img)
    print(f"Image saved to {img_path}")

    # Perform classification and get recommendations
    pred, _, probs = learn.predict(img)
    result = {learn.dls.vocab[i]: float(probs[i]) for i in range(len(probs))}
    top_pred = pred
    recommendation = get_makeup_recommendation(top_pred)
    return result, recommendation


# Load the pre-trained facial landmark detector model
predictor_path = "shape_predictor_68_face_landmarks.dat"
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor(predictor_path)

# Define lip landmarks
LIP_POINTS = list(range(48, 61))

def apply_lipstick(image):
    # Convert PIL image to OpenCV format
    lipstick_color = rgb_to_bgr(colorDict[lipstick_shade])
    image_cv = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)

    # Detect faces in the image
    faces = detector(image_cv, 1)
    if len(faces) == 0:
        return image  # No faces detected, return the original image

    for face in faces:
        # Get the facial landmarks
        shape = predictor(image_cv, face)
        shape = face_utils.shape_to_np(shape)

        # Get the lip region points
        lips = shape[LIP_POINTS]

        # Create a mask for the lips
        mask = np.zeros(image_cv.shape[:2], dtype=np.uint8)
        cv2.fillPoly(mask, [lips], 255)

        # Create a colored overlay
        overlay = np.zeros_like(image_cv, dtype=np.uint8)
        overlay[:] = lipstick_color

        # Isolate the lip region from the original image
        lip_area = cv2.bitwise_and(overlay, overlay, mask=mask)

        # Invert the lip mask
        inv_mask = cv2.bitwise_not(mask)

        # Apply the inverted mask to the original image to remove the lip region
        no_lip_area = cv2.bitwise_and(image_cv, image_cv, mask=inv_mask)

        # Combine the lip area with the rest of the image
        image_cv = cv2.addWeighted(no_lip_area, 1, lip_area, 0.6, 0)

    # Convert back to PIL format
    return Image.fromarray(cv2.cvtColor(image_cv, cv2.COLOR_BGR2RGB))

mp_face_detection = mp.solutions.face_detection
mp_face_mesh = mp.solutions.face_mesh

def apply_color(image_pil, color, alpha):

    color = rgb_to_bgr(colorDict[color])

    """Applies a specified color to the face in the image."""
    # Convert PIL image to OpenCV format
    image_cv = cv2.cvtColor(np.array(image_pil), cv2.COLOR_RGB2BGR)

    # Convert the image to RGB
    image_rgb = cv2.cvtColor(image_cv, cv2.COLOR_BGR2RGB)

    # Initialize face detection and face mesh
    with mp_face_detection.FaceDetection(min_detection_confidence=0.5) as face_detection, \
         mp_face_mesh.FaceMesh(static_image_mode=True, max_num_faces=1, min_detection_confidence=0.5) as face_mesh:
        
        # Detect faces in the image
        detection_results = face_detection.process(image_rgb)

        if detection_results.detections:
            for detection in detection_results.detections:
                # Get face landmarks
                mesh_results = face_mesh.process(image_rgb)
                if mesh_results.multi_face_landmarks:
                    for face_landmarks in mesh_results.multi_face_landmarks:
                        # Create a mask for the face
                        mask = np.zeros_like(image_cv, dtype=np.uint8)
                        ih, iw, _ = image_cv.shape
                        for landmark in face_landmarks.landmark:
                            x = int(landmark.x * iw)
                            y = int(landmark.y * ih)
                            cv2.circle(mask, (x, y), 1, (255, 255, 255), -1)

                        hull = cv2.convexHull(np.array([(int(landmark.x * iw), int(landmark.y * ih)) for landmark in face_landmarks.landmark]))
                        cv2.fillConvexPoly(mask, hull, (255, 255, 255))

                        # Create a color image
                        color_image = np.full_like(image_cv, color, dtype=np.uint8)  # Apply the specified color

                        # Blend the color with the face region using the mask
                        blended = cv2.addWeighted(image_cv, 1 - alpha, color_image, alpha, 0)

                        # Combine the original image with the blended color image using the mask
                        image_cv = np.where(mask == np.array([255, 255, 255]), blended, image_cv)

    # Convert the result back to PIL format
    result_image_pil = Image.fromarray(cv2.cvtColor(image_cv, cv2.COLOR_BGR2RGB))
    return result_image_pil

def apply_makeup():
    # Load your input image
    print(image_path)
    input_image = Image.open(image_path)
    foundation_alpha = 0.05  # Transparency factor for foundation
    powder_alpha = 0.05  # Transparency factor for powder

    output_image_path = "output_image_" + str(round(time.time() * 1000)) + ".jpg"

    # Apply lipstick, foundation, and powder to the input image
    output_image = apply_lipstick(input_image)
    output_image = apply_color(output_image, foundation_color, foundation_alpha)
    output_image = apply_color(output_image, powder_color, powder_alpha)

    # Save or display the output image
    output_image.save(output_image_path)
    
    return output_image_path

# Add a logo and a welcome message
logo = "https://i.pinimg.com/736x/f8/34/cc/f834ccc788207ae147ab37d2085f6903.jpg"  # Replace with your logo URL
welcome_message = """

# Skin Tone Classification and Makeup Recommendations

Upload an image to classify your skin tone and receive personalized makeup recommendations. Find the perfect foundation, lipstick, and powder shades from your favorite brands!

"""

# Gradio interface
with gr.Blocks() as demo:
    gr.Markdown("""

    # Welcome to the Makeup Recommendation and Application Tool

    Upload an image to receive personalized makeup recommendations and see how the makeup looks on you!

    """)
    
    with gr.Row():
        with gr.Column():
            gr.Markdown("## Upload and Classify")
            upload_image = gr.Image(type="pil", label="Upload Image")
            classify_btn = gr.Button("Submit")
            result_label = gr.Label(num_top_classes=3, label='Classification Results')
            recommendation_json = gr.JSON(label='Makeup Recommendations')
            
            classify_btn.click(fn=classify_and_recommend, inputs=upload_image, outputs=[result_label, recommendation_json])
        
        with gr.Column():
            gr.Markdown("## View Edited Image")
            img = gr.Image(label="Edited Image")
            show_image_btn = gr.Button("Show Edited Image")
            show_image_btn.click(fn=apply_makeup, inputs=[], outputs=img)

    gr.Markdown("""

    ### Instructions:

    1. **Upload an Image:** Choose a clear image of your face.

    2. **Submit for Classification:** Click 'Submit' to receive makeup recommendations.

    3. **View Edited Image:** Click 'Show Edited Image' to see the applied makeup.

    """)
    
demo.launch(debug=True, share=True)