andevs commited on
Commit
427b224
·
verified ·
1 Parent(s): 095e492

Create skin_analyzer.py

Browse files
Files changed (1) hide show
  1. models/skin_analyzer.py +184 -0
models/skin_analyzer.py ADDED
@@ -0,0 +1,184 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import cv2
3
+ from typing import List, Dict, Tuple
4
+ import torch
5
+ import torch.nn as nn
6
+ import torchvision.transforms as transforms
7
+ from PIL import Image
8
+
9
+ class SkinConditionClassifier(nn.Module):
10
+ """
11
+ Neural network for skin condition classification
12
+ """
13
+ def __init__(self, num_classes=23):
14
+ super(SkinConditionClassifier, self).__init__()
15
+ self.features = nn.Sequential(
16
+ nn.Conv2d(3, 64, kernel_size=3, padding=1),
17
+ nn.ReLU(inplace=True),
18
+ nn.Conv2d(64, 64, kernel_size=3, padding=1),
19
+ nn.ReLU(inplace=True),
20
+ nn.MaxPool2d(kernel_size=2, stride=2),
21
+
22
+ nn.Conv2d(64, 128, kernel_size=3, padding=1),
23
+ nn.ReLU(inplace=True),
24
+ nn.Conv2d(128, 128, kernel_size=3, padding=1),
25
+ nn.ReLU(inplace=True),
26
+ nn.MaxPool2d(kernel_size=2, stride=2),
27
+
28
+ nn.Conv2d(128, 256, kernel_size=3, padding=1),
29
+ nn.ReLU(inplace=True),
30
+ nn.Conv2d(256, 256, kernel_size=3, padding=1),
31
+ nn.ReLU(inplace=True),
32
+ nn.Conv2d(256, 256, kernel_size=3, padding=1),
33
+ nn.ReLU(inplace=True),
34
+ nn.MaxPool2d(kernel_size=2, stride=2),
35
+ )
36
+
37
+ self.classifier = nn.Sequential(
38
+ nn.AdaptiveAvgPool2d((6, 6)),
39
+ nn.Flatten(),
40
+ nn.Linear(256 * 6 * 6, 4096),
41
+ nn.ReLU(inplace=True),
42
+ nn.Dropout(),
43
+ nn.Linear(4096, 4096),
44
+ nn.ReLU(inplace=True),
45
+ nn.Dropout(),
46
+ nn.Linear(4096, num_classes),
47
+ )
48
+
49
+ def forward(self, x):
50
+ x = self.features(x)
51
+ x = self.classifier(x)
52
+ return x
53
+
54
+ class SkinAnalyzer:
55
+ def __init__(self, model_path: str = None):
56
+ self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
57
+ self.model = SkinConditionClassifier(num_classes=23)
58
+
59
+ if model_path and torch.cuda.is_available():
60
+ self.model.load_state_dict(torch.load(model_path))
61
+ elif model_path:
62
+ self.model.load_state_dict(torch.load(model_path, map_location='cpu'))
63
+
64
+ self.model = self.model.to(self.device)
65
+ self.model.eval()
66
+
67
+ self.transform = transforms.Compose([
68
+ transforms.Resize((224, 224)),
69
+ transforms.ToTensor(),
70
+ transforms.Normalize(mean=[0.485, 0.456, 0.406],
71
+ std=[0.229, 0.224, 0.225])
72
+ ])
73
+
74
+ self.condition_names = [
75
+ 'blackheads', 'whiteheads', 'papules', 'pustules', 'cystic_acne',
76
+ 'nodules', 'acne_scars', 'hyperpigmentation', 'hypopigmentation',
77
+ 'oily_skin', 'dry_skin', 'combination_skin', 'sensitive_skin',
78
+ 'rosacea', 'eczema', 'seborrheic_dermatitis', 'milia',
79
+ 'keratosis_pilaris', 'folliculitis', 'sunburn_uv_damage',
80
+ 'fine_lines', 'uneven_texture', 'enlarged_pores'
81
+ ]
82
+
83
+ def analyze(self, image: np.ndarray) -> List[Dict]:
84
+ """
85
+ Analyze skin conditions in image
86
+ """
87
+ # Preprocess image
88
+ pil_image = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
89
+ input_tensor = self.transform(pil_image).unsqueeze(0).to(self.device)
90
+
91
+ # Run inference
92
+ with torch.no_grad():
93
+ outputs = self.model(input_tensor)
94
+ probabilities = torch.softmax(outputs, dim=1)[0]
95
+
96
+ # Get top predictions
97
+ top_probs, top_indices = torch.topk(probabilities, 5)
98
+
99
+ results = []
100
+ for prob, idx in zip(top_probs, top_indices):
101
+ if prob > 0.1: # Only include if confidence > 10%
102
+ condition = self.condition_names[idx]
103
+
104
+ # Determine severity based on probability
105
+ if prob > 0.8:
106
+ severity = 'severe'
107
+ elif prob > 0.5:
108
+ severity = 'moderate'
109
+ else:
110
+ severity = 'mild'
111
+
112
+ results.append({
113
+ 'condition': condition,
114
+ 'confidence': float(prob) * 100,
115
+ 'severity': severity
116
+ })
117
+
118
+ return results
119
+
120
+ def analyze_regions(self, image: np.ndarray, regions: Dict) -> Dict:
121
+ """
122
+ Analyze specific face regions
123
+ """
124
+ results = {}
125
+ h, w, _ = image.shape
126
+
127
+ for region_name, (x, y, width, height) in regions.items():
128
+ # Extract region
129
+ region_img = image[y:y+height, x:x+width]
130
+ if region_img.size == 0:
131
+ continue
132
+
133
+ # Analyze region
134
+ region_results = self.analyze(region_img)
135
+ results[region_name] = region_results
136
+
137
+ return results
138
+
139
+ def get_severity_score(self, condition: str, confidence: float) -> str:
140
+ """
141
+ Get severity level based on condition and confidence
142
+ """
143
+ # Define severity thresholds per condition
144
+ severe_conditions = ['cystic_acne', 'nodules', 'rosacea', 'eczema']
145
+ moderate_conditions = ['papules', 'pustules', 'hyperpigmentation']
146
+
147
+ if condition in severe_conditions:
148
+ return 'severe'
149
+ elif condition in moderate_conditions:
150
+ return 'moderate' if confidence > 50 else 'mild'
151
+ else:
152
+ if confidence > 80:
153
+ return 'moderate'
154
+ elif confidence > 50:
155
+ return 'mild'
156
+ else:
157
+ return 'mild'
158
+
159
+ def get_condition_info(self, condition: str) -> Dict:
160
+ """
161
+ Get detailed information about a condition
162
+ """
163
+ condition_info = {
164
+ 'blackheads': {
165
+ 'name': 'Blackheads',
166
+ 'description': 'Open comedones with oxidized sebum',
167
+ 'treatments': ['Salicylic acid', 'Retinoids', 'Clay masks'],
168
+ 'avoid': ['Comedogenic products', 'Heavy oils']
169
+ },
170
+ 'whiteheads': {
171
+ 'name': 'Whiteheads',
172
+ 'description': 'Closed comedones under skin surface',
173
+ 'treatments': ['Benzoyl peroxide', 'Retinoids', 'Chemical exfoliation'],
174
+ 'avoid': ['Pore-clogging makeup', 'Petroleum-based products']
175
+ },
176
+ # Add all 23 conditions...
177
+ }
178
+
179
+ return condition_info.get(condition, {
180
+ 'name': condition.replace('_', ' ').title(),
181
+ 'description': 'Skin condition detected by AI analysis',
182
+ 'treatments': ['Consult a dermatologist for proper treatment'],
183
+ 'avoid': ['Self-diagnosis', 'Aggressive treatment']
184
+ })