requirements.txt
Browse filestorch
torchvision
transformers
huggingface_hub
Pillow
opencv-python # For image processing and pattern recognition
matplotlib # For color and pattern analysis
gradio # Interface for uploading and analyzing files
scikit-learn # For additional analysis of colors, themes
app.py
ADDED
@@ -0,0 +1,216 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch
|
2 |
+
import cv2
|
3 |
+
from PIL import Image
|
4 |
+
import numpy as np
|
5 |
+
import matplotlib.pyplot as plt
|
6 |
+
from transformers import pipeline
|
7 |
+
import gradio as gr
|
8 |
+
from sklearn.cluster import KMeans
|
9 |
+
from colorsys import rgb_to_hsv
|
10 |
+
from huggingface_hub import InferenceClient # Import InferenceClient for API calls
|
11 |
+
|
12 |
+
# Initialize the emotion detection pipeline for text (if any text is included in assets)
|
13 |
+
emotion_classifier = pipeline("text-classification", model="j-hartmann/emotion-english-distilroberta-base", return_all_scores=True)
|
14 |
+
|
15 |
+
# Initialize the Hugging Face API client with your Space model ID
|
16 |
+
client = InferenceClient("nehapasricha94/LLaVA-image-analysis")
|
17 |
+
|
18 |
+
# Function to analyze colors in an image
|
19 |
+
def analyze_colors(image):
|
20 |
+
try:
|
21 |
+
# Ensure the image is in RGB format
|
22 |
+
if image.mode != "RGB":
|
23 |
+
image = image.convert("RGB")
|
24 |
+
|
25 |
+
# Resize the image for faster processing
|
26 |
+
image = image.resize((150, 150))
|
27 |
+
|
28 |
+
# Convert to numpy array
|
29 |
+
img_array = np.array(image)
|
30 |
+
|
31 |
+
# Reshape image to be a list of pixels
|
32 |
+
pixels = img_array.reshape((-1, 3))
|
33 |
+
|
34 |
+
kmeans = KMeans(n_clusters=5, random_state=0)
|
35 |
+
kmeans.fit(pixels)
|
36 |
+
dominant_colors = kmeans.cluster_centers_
|
37 |
+
|
38 |
+
# Plot the colors for visualization
|
39 |
+
plt.figure(figsize=(8, 6))
|
40 |
+
plt.imshow([dominant_colors.astype(int)])
|
41 |
+
plt.axis('off')
|
42 |
+
plt.show()
|
43 |
+
|
44 |
+
return dominant_colors
|
45 |
+
|
46 |
+
except Exception as e:
|
47 |
+
print(f"Error in analyze_colors: {e}")
|
48 |
+
return None
|
49 |
+
|
50 |
+
|
51 |
+
# Function to analyze emotions based on color (hue, brightness, saturation) and stress with weights
|
52 |
+
def color_emotion_analysis(dominant_colors):
|
53 |
+
try:
|
54 |
+
emotions = []
|
55 |
+
stress_levels = []
|
56 |
+
|
57 |
+
# Weight coefficients for each factor
|
58 |
+
brightness_weight = 0.5
|
59 |
+
hue_weight = 0.3
|
60 |
+
saturation_weight = 0.2
|
61 |
+
|
62 |
+
for color in dominant_colors:
|
63 |
+
# Normalize RGB values to 0-1 range
|
64 |
+
r, g, b = color / 255.0
|
65 |
+
|
66 |
+
# Convert RGB to HSV
|
67 |
+
h, s, v = rgb_to_hsv(r, g, b) # Hue, Saturation, Value (brightness)
|
68 |
+
|
69 |
+
# Calculate weighted emotion and stress levels
|
70 |
+
weighted_brightness = v * brightness_weight
|
71 |
+
weighted_hue = h * hue_weight
|
72 |
+
weighted_saturation = s * saturation_weight
|
73 |
+
|
74 |
+
# Combine weighted factors
|
75 |
+
score = weighted_brightness + weighted_hue + weighted_saturation
|
76 |
+
|
77 |
+
# Analyze emotion and stress based on combined score
|
78 |
+
if score < 0.3: # Lower combined score, less rigid "high stress"
|
79 |
+
emotions.append("Sadness")
|
80 |
+
stress_levels.append("Moderate-High Stress")
|
81 |
+
elif 0.3 <= score < 0.5:
|
82 |
+
emotions.append("Neutral")
|
83 |
+
stress_levels.append("Moderate Stress")
|
84 |
+
elif 0.5 <= score < 0.7:
|
85 |
+
emotions.append("Okay")
|
86 |
+
stress_levels.append("Low Stress")
|
87 |
+
elif 0.7 <= score < 0.85:
|
88 |
+
emotions.append("Happiness")
|
89 |
+
stress_levels.append("Very Low Stress")
|
90 |
+
else:
|
91 |
+
emotions.append("Very Happy")
|
92 |
+
stress_levels.append("No Stress")
|
93 |
+
|
94 |
+
return emotions, stress_levels
|
95 |
+
|
96 |
+
except Exception as e:
|
97 |
+
print(f"Error in color_emotion_analysis: {e}")
|
98 |
+
return ["Error analyzing emotions"], ["Error analyzing stress levels"]
|
99 |
+
|
100 |
+
|
101 |
+
# Function to analyze patterns and shapes using OpenCV
|
102 |
+
def analyze_patterns(image):
|
103 |
+
try:
|
104 |
+
# Convert to grayscale for edge detection
|
105 |
+
gray_image = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2GRAY)
|
106 |
+
edges = cv2.Canny(gray_image, 100, 200)
|
107 |
+
|
108 |
+
# Calculate the number of edges (chaos metric)
|
109 |
+
num_edges = np.sum(edges > 0)
|
110 |
+
|
111 |
+
if num_edges > 10000: # Arbitrary threshold for "chaos"
|
112 |
+
return "Chaotic patterns - possibly distress", 0.8 # Assigning 0.8 stress for chaotic patterns
|
113 |
+
else:
|
114 |
+
return "Orderly patterns - possibly calm", 0.2 # Assigning 0.2 stress for calm patterns
|
115 |
+
except Exception as e:
|
116 |
+
print(f"Error in analyze_patterns: {e}")
|
117 |
+
return "Error analyzing patterns", 0.5 # Assigning neutral weight for errors
|
118 |
+
|
119 |
+
|
120 |
+
# Function to compute overall results by combining color and pattern analyses
|
121 |
+
def compute_overall_result(color_emotions, stress_levels, pattern_analysis, pattern_stress):
|
122 |
+
try:
|
123 |
+
# Assigning weightage to different factors
|
124 |
+
color_emotion_weight = 0.5 # 50% for color-based emotions and stress
|
125 |
+
pattern_weight = 0.5 # 50% for pattern analysis
|
126 |
+
|
127 |
+
# Determine the most common emotion from colors
|
128 |
+
dominant_emotion = max(set(color_emotions), key=color_emotions.count)
|
129 |
+
|
130 |
+
# Average stress level from color analysis (converting text stress levels to numeric)
|
131 |
+
stress_mapping = {
|
132 |
+
"No Stress": 0.1,
|
133 |
+
"Very Low Stress": 0.3,
|
134 |
+
"Low Stress": 0.5,
|
135 |
+
"Moderate Stress": 0.7,
|
136 |
+
"Moderate-High Stress": 0.9,
|
137 |
+
}
|
138 |
+
color_stress_numeric = [stress_mapping[stress] for stress in stress_levels if stress in stress_mapping]
|
139 |
+
avg_color_stress = np.mean(color_stress_numeric) if color_stress_numeric else 0.5 # Default to 0.5 if no valid data
|
140 |
+
|
141 |
+
# Compute the overall stress by combining color stress and pattern stress
|
142 |
+
overall_stress = (avg_color_stress * color_emotion_weight) + (pattern_stress * pattern_weight)
|
143 |
+
|
144 |
+
# Determine overall result based on combined factors
|
145 |
+
if overall_stress < 0.3:
|
146 |
+
overall_emotion = "Calm and Relaxed"
|
147 |
+
elif 0.3 <= overall_stress < 0.6:
|
148 |
+
overall_emotion = "Neutral Mood"
|
149 |
+
elif 0.6 <= overall_stress < 0.8:
|
150 |
+
overall_emotion = "Slightly Stressed"
|
151 |
+
else:
|
152 |
+
overall_emotion = "Highly Stressed"
|
153 |
+
|
154 |
+
return f"Overall emotion: {overall_emotion} (Dominant Color Emotion: {dominant_emotion}, Pattern Analysis: {pattern_analysis})"
|
155 |
+
|
156 |
+
except Exception as e:
|
157 |
+
return f"Error computing overall result: {str(e)}"
|
158 |
+
|
159 |
+
|
160 |
+
# Function to analyze emotions from a given text (if applicable)
|
161 |
+
def analyze_emotion_from_text(text):
|
162 |
+
try:
|
163 |
+
# Using the local emotion classifier
|
164 |
+
emotion_scores = emotion_classifier(text)
|
165 |
+
dominant_emotion = max(emotion_scores, key=lambda x: x['score'])
|
166 |
+
return f"Detected emotion from text: {dominant_emotion['label']} with score: {dominant_emotion['score']:.2f}"
|
167 |
+
except Exception as e:
|
168 |
+
print(f"Error analyzing emotion from text: {e}")
|
169 |
+
return "Error analyzing text emotion"
|
170 |
+
|
171 |
+
|
172 |
+
# Main function to process image and analyze emotional expression
|
173 |
+
def analyze_emotion_from_image(image):
|
174 |
+
print(f"Color emotions: abc")
|
175 |
+
try:
|
176 |
+
# Ensure the input image is a PIL image
|
177 |
+
print(f"Initial input type: {type(image)}")
|
178 |
+
if isinstance(image, dict) and "path" in image:
|
179 |
+
image = Image.open(requests.get(image["path"], stream=True).raw)
|
180 |
+
print("Loaded image from URL.")
|
181 |
+
elif isinstance(image, np.ndarray):
|
182 |
+
image = Image.fromarray(image)
|
183 |
+
print("Converted image from NumPy array.")
|
184 |
+
|
185 |
+
print(f"Image size: {image.size}, mode: {image.mode}")
|
186 |
+
|
187 |
+
# Analyze colors
|
188 |
+
dominant_colors = analyze_colors(image)
|
189 |
+
if dominant_colors is None:
|
190 |
+
return "Error analyzing colors"
|
191 |
+
|
192 |
+
color_emotions, stress_levels = color_emotion_analysis(dominant_colors)
|
193 |
+
print(f"Color emotions: {color_emotions}, Stress levels: {stress_levels}")
|
194 |
+
|
195 |
+
# Analyze patterns
|
196 |
+
pattern_analysis, pattern_stress = analyze_patterns(image)
|
197 |
+
print(f"Pattern analysis: {pattern_analysis}, Pattern stress: {pattern_stress}")
|
198 |
+
|
199 |
+
# Compute overall result
|
200 |
+
overall_result = compute_overall_result(color_emotions, stress_levels, pattern_analysis, pattern_stress)
|
201 |
+
|
202 |
+
return overall_result
|
203 |
+
except Exception as e:
|
204 |
+
print(f"Error processing image: {str(e)}")
|
205 |
+
return f"Error processing image: {str(e)}"
|
206 |
+
|
207 |
+
|
208 |
+
|
209 |
+
|
210 |
+
|
211 |
+
# Gradio interface to upload image files and perform analysis
|
212 |
+
iface = gr.Interface(fn=analyze_emotion_from_image, inputs="image", outputs="text")
|
213 |
+
|
214 |
+
# Launch the interface
|
215 |
+
if __name__ == "__main__":
|
216 |
+
iface.launch()
|