DHEIVER commited on
Commit
340e897
·
verified ·
1 Parent(s): a75511c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +39 -277
app.py CHANGED
@@ -8,17 +8,12 @@ import torch
8
  import torch.nn.functional as F
9
  import torchvision.transforms as transforms
10
  import logging
11
- import os
12
  from datetime import datetime
13
 
14
- # Configuração de logging
15
  logging.basicConfig(
16
  level=logging.INFO,
17
- format='%(asctime)s - %(levelname)s - %(message)s',
18
- handlers=[
19
- logging.FileHandler('iridology_analyzer.log'),
20
- logging.StreamHandler()
21
- ]
22
  )
23
 
24
  @dataclass
@@ -30,40 +25,6 @@ class IrisZone:
30
  color: Tuple[int, int, int]
31
  angle_start: float = 0
32
  angle_end: float = 360
33
-
34
- def __post_init__(self):
35
- """Validação dos parâmetros da zona"""
36
- if not 0 <= self.inner_ratio <= 1:
37
- raise ValueError("inner_ratio deve estar entre 0 e 1")
38
- if not 0 <= self.outer_ratio <= 1:
39
- raise ValueError("outer_ratio deve estar entre 0 e 1")
40
- if self.inner_ratio >= self.outer_ratio:
41
- raise ValueError("inner_ratio deve ser menor que outer_ratio")
42
-
43
- class ImageProcessor:
44
- """Classe para processamento básico de imagens"""
45
- @staticmethod
46
- def enhance_image(img: np.ndarray) -> np.ndarray:
47
- """Melhora a qualidade da imagem"""
48
- # Converter para LAB
49
- lab = cv2.cvtColor(img, cv2.COLOR_RGB2LAB)
50
- l, a, b = cv2.split(lab)
51
-
52
- # Aplicar CLAHE no canal L
53
- clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8,8))
54
- l = clahe.apply(l)
55
-
56
- # Merge canais
57
- lab = cv2.merge((l,a,b))
58
-
59
- # Converter de volta para RGB
60
- enhanced = cv2.cvtColor(lab, cv2.COLOR_LAB2RGB)
61
- return enhanced
62
-
63
- @staticmethod
64
- def reduce_noise(img: np.ndarray) -> np.ndarray:
65
- """Reduz ruído na imagem"""
66
- return cv2.fastNlMeansDenoisingColored(img, None, 10, 10, 7, 21)
67
 
68
  class IrisAnalyzer:
69
  """Classe principal para análise da íris"""
@@ -77,311 +38,112 @@ class IrisAnalyzer:
77
  IrisZone("Zona Endócrina", 0.15, 0.25, (0, 255, 255)),
78
  IrisZone("Zona Pupilar", 0, 0.15, (128, 128, 128))
79
  ]
80
- self.image_processor = ImageProcessor()
81
- logging.info("IrisAnalyzer inicializado com %d zonas", len(self.zones))
82
-
83
- def preprocess_image(self, img: np.ndarray) -> np.ndarray:
84
- """Pré-processa a imagem para análise"""
85
- try:
86
- # Melhorar qualidade
87
- enhanced = self.image_processor.enhance_image(img)
88
-
89
- # Reduzir ruído
90
- denoised = self.image_processor.reduce_noise(enhanced)
91
-
92
- # Converter para escala de cinza
93
- gray = cv2.cvtColor(denoised, cv2.COLOR_RGB2GRAY)
94
-
95
- # Equalização adaptativa
96
- clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
97
- preprocessed = clahe.apply(gray)
98
-
99
- logging.info("Pré-processamento de imagem concluído com sucesso")
100
- return preprocessed
101
- except Exception as e:
102
- logging.error("Erro no pré-processamento: %s", str(e))
103
- raise
104
 
105
  def detect_pupil(self, img: np.ndarray) -> Tuple[int, int, int]:
106
  """Detecta a pupila na imagem"""
107
  try:
108
- preprocessed = self.preprocess_image(img)
109
-
110
- # Threshold adaptativo
111
- _, thresh = cv2.threshold(preprocessed, 30, 255,
112
- cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
113
-
114
- # Operações morfológicas
115
- kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
116
- morph = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
117
 
118
- # Encontrar contornos
119
- contours, _ = cv2.findContours(morph, cv2.RETR_EXTERNAL,
120
- cv2.CHAIN_APPROX_SIMPLE)
121
 
122
  if not contours:
123
- logging.warning("Nenhum contorno encontrado na imagem")
124
  return None
125
 
126
- # Encontrar o contorno mais circular
127
- max_circularity = 0
128
  best_contour = None
129
 
130
  for contour in contours:
131
  area = cv2.contourArea(contour)
132
- perimeter = cv2.arcLength(contour, True)
133
-
134
- if perimeter == 0:
135
- continue
136
-
137
- circularity = 4 * np.pi * area / (perimeter * perimeter)
138
-
139
- if circularity > max_circularity:
140
- max_circularity = circularity
141
  best_contour = contour
142
 
143
  if best_contour is None:
144
- logging.warning("Nenhum contorno circular encontrado")
145
  return None
146
 
147
- # Ajustar círculo
148
  (x, y), radius = cv2.minEnclosingCircle(best_contour)
149
- logging.info("Pupila detectada em (x=%d, y=%d) com raio=%d",
150
- int(x), int(y), int(radius))
151
  return (int(x), int(y), int(radius))
152
 
153
  except Exception as e:
154
- logging.error("Erro na detecção da pupila: %s", str(e))
155
- raise
156
-
157
- def analyze_zone(self, img: np.ndarray, mask: np.ndarray) -> Dict:
158
- """Analisa características de uma zona específica"""
159
- try:
160
- # Extrair características da região
161
- mean_color = cv2.mean(img, mask=mask)
162
-
163
- # Calcular textura
164
- gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
165
- zone_pixels = cv2.bitwise_and(gray, gray, mask=mask)
166
-
167
- if np.sum(mask) > 0:
168
- std_dev = np.std(zone_pixels[mask > 0])
169
- mean_intensity = np.mean(zone_pixels[mask > 0])
170
-
171
- # Calcular características adicionais
172
- non_zero = zone_pixels[mask > 0]
173
- percentiles = np.percentile(non_zero, [25, 50, 75])
174
-
175
- analysis = {
176
- 'mean_intensity': mean_intensity,
177
- 'std_dev': std_dev,
178
- 'color_variation': mean_color[:3],
179
- 'quartiles': percentiles.tolist(),
180
- 'pixel_count': len(non_zero)
181
- }
182
- else:
183
- analysis = {
184
- 'mean_intensity': 0,
185
- 'std_dev': 0,
186
- 'color_variation': (0,0,0),
187
- 'quartiles': [0,0,0],
188
- 'pixel_count': 0
189
- }
190
-
191
- return analysis
192
-
193
- except Exception as e:
194
- logging.error("Erro na análise da zona: %s", str(e))
195
- raise
196
-
197
- def interpret_zone(self, analysis: Dict) -> str:
198
- """Interpreta os resultados da análise de uma zona"""
199
- try:
200
- intensity = analysis['mean_intensity']
201
- variation = analysis['std_dev']
202
-
203
- # Classificação básica
204
- if intensity < 85:
205
- base_condition = "Possível área de atenção"
206
- confidence = "baixa" if variation > 30 else "média"
207
- elif intensity < 170:
208
- base_condition = "Área moderada"
209
- confidence = "média" if variation > 20 else "alta"
210
- else:
211
- base_condition = "Área normal"
212
- confidence = "alta" if variation < 15 else "média"
213
-
214
- # Adicionar detalhes estatísticos
215
- detail = (f"(Intensidade: {intensity:.1f}, "
216
- f"Variação: {variation:.1f}, "
217
- f"Confiança: {confidence})")
218
-
219
- return f"{base_condition} {detail}"
220
-
221
- except Exception as e:
222
- logging.error("Erro na interpretação da zona: %s", str(e))
223
- raise
224
 
225
  def analyze_iris(self, img: np.ndarray) -> Tuple[np.ndarray, Dict]:
226
  """Análise principal da íris"""
227
  try:
228
- # Criar cópia para desenho
229
  output_img = img.copy()
230
  results = {}
231
 
232
- # Detectar pupila
233
  pupil = self.detect_pupil(img)
234
  if pupil is None:
235
  return img, {"Erro": "Não foi possível detectar a pupila"}
236
 
237
  x, y, pupil_radius = pupil
238
-
239
- # Estimar raio da íris
240
  iris_radius = pupil_radius * 4
241
 
242
- # Desenhar círculo da pupila
243
  cv2.circle(output_img, (x, y), pupil_radius, (0, 0, 0), 2)
244
 
245
- # Analisar cada zona
246
  for zone in self.zones:
247
  inner_r = int(iris_radius * zone.inner_ratio)
248
  outer_r = int(iris_radius * zone.outer_ratio)
249
 
250
- # Criar máscara para a zona
 
 
251
  mask = np.zeros(img.shape[:2], dtype=np.uint8)
252
  cv2.circle(mask, (x, y), outer_r, 255, -1)
253
  cv2.circle(mask, (x, y), inner_r, 0, -1)
254
 
255
- # Desenhar círculos da zona
256
- cv2.circle(output_img, (x, y), outer_r, zone.color, 2)
257
-
258
- # Analisar zona
259
- analysis = self.analyze_zone(img, mask)
260
- interpretation = self.interpret_zone(analysis)
261
- results[zone.name] = interpretation
262
 
263
- # Adicionar texto
264
- text_x = x - iris_radius
265
- text_y = y + outer_r
266
- cv2.putText(output_img, zone.name, (text_x, text_y),
267
  cv2.FONT_HERSHEY_SIMPLEX, 0.5, zone.color, 1)
268
 
269
- logging.info("Análise completa realizada com sucesso")
270
  return output_img, results
271
 
272
  except Exception as e:
273
- logging.error("Erro na análise da íris: %s", str(e))
274
- return img, {"Erro": f"Erro na análise: {str(e)}"}
275
 
276
  def process_image(img):
277
- """Função principal para processar imagem via Gradio"""
278
- try:
279
- analyzer = IrisAnalyzer()
280
- return analyzer.analyze_iris(np.array(img))
281
- except Exception as e:
282
- logging.error("Erro no processamento da imagem: %s", str(e))
283
- return img, {"Erro": str(e)}
284
 
285
- # Interface Gradio atualizada
286
  with gr.Blocks(theme=gr.themes.Soft()) as iface:
287
  gr.Markdown("""
288
- # 🔍 Analisador Avançado de Íris
289
- ### Baseado na teoria de Jensen para análise de zonas da íris
290
-
291
- ⚠️ **AVISO**: Esta é uma demonstração educacional. Não use para diagnósticos médicos.
292
  """)
293
 
294
  with gr.Row():
295
- with gr.Column(scale=1):
296
- # Corrigido o componente Image removendo o parâmetro 'tool'
297
  input_image = gr.Image(
298
- label="Carregue a imagem do olho",
299
  type="numpy",
300
- height=300,
301
- sources=["upload", "clipboard"] # Especifica as fontes de entrada permitidas
302
  )
303
 
304
- analyze_btn = gr.Button(
305
- "📸 Analisar Imagem",
306
- variant="primary",
307
- scale=1
308
- )
309
-
310
- gr.Markdown("""
311
- ### Como usar:
312
- 1. Faça upload de uma imagem clara do olho
313
- 2. Certifique-se que a íris está bem visível
314
- 3. Clique em "Analisar Imagem"
315
- 4. Veja os resultados à direita
316
- """)
317
 
318
- with gr.Column(scale=1):
319
- output_image = gr.Image(
320
- label="Análise Visual",
321
- height=300
322
- )
323
-
324
- with gr.Accordion("📊 Resultados Detalhados", open=True):
325
- results = gr.JSON(label="")
326
-
327
- with gr.Row():
328
- gr.Markdown("""
329
- ### Legenda das Zonas:
330
- - 🔴 Zona Cerebral/Neural
331
- - 🟢 Zona Digestiva
332
- - 🔵 Zona Respiratória
333
- - 🟡 Zona Circulatória
334
- - 🟣 Zona Linfática
335
- - 🔰 Zona Endócrina
336
- - ⚪ Zona Pupilar
337
- """)
338
 
339
- # Configurar o fluxo de análise
340
  analyze_btn.click(
341
  fn=process_image,
342
  inputs=input_image,
343
- outputs=[output_image, results],
344
  )
345
-
346
- gr.Markdown("""
347
- ---
348
- ### ℹ️ Informações Importantes
349
-
350
- Este aplicativo utiliza técnicas avançadas de processamento de imagem para:
351
- - Detectar automaticamente a pupila
352
- - Segmentar as zonas da íris
353
- - Analisar padrões de cor e textura
354
- - Gerar relatório detalhado por zona
355
-
356
- **Recursos Técnicos:**
357
- - Processamento de imagem adaptativo
358
- - Detecção automática de pupila
359
- - Análise de textura e padrões
360
- - Sistema de logging para rastreamento
361
- - Tratamento de erros robusto
362
-
363
- **Lembre-se**: A iridologia é considerada uma prática alternativa e não é reconhecida
364
- pela medicina convencional como método válido de diagnóstico.
365
- """)
366
-
367
- # Configuração de logging
368
- logging.basicConfig(
369
- level=logging.INFO,
370
- format='%(asctime)s - %(levelname)s - %(message)s',
371
- handlers=[
372
- logging.StreamHandler()
373
- ]
374
- )
375
 
376
  if __name__ == "__main__":
377
- try:
378
- iface.launch(
379
- share=True,
380
- server_name="0.0.0.0",
381
- server_port=7860,
382
- enable_queue=True
383
- )
384
- logging.info("Aplicação iniciada com sucesso")
385
- except Exception as e:
386
- logging.error(f"Erro ao iniciar a aplicação: {str(e)}")
387
- raise
 
8
  import torch.nn.functional as F
9
  import torchvision.transforms as transforms
10
  import logging
 
11
  from datetime import datetime
12
 
13
+ # Configuração básica de logging
14
  logging.basicConfig(
15
  level=logging.INFO,
16
+ format='%(asctime)s - %(levelname)s - %(message)s'
 
 
 
 
17
  )
18
 
19
  @dataclass
 
25
  color: Tuple[int, int, int]
26
  angle_start: float = 0
27
  angle_end: float = 360
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
  class IrisAnalyzer:
30
  """Classe principal para análise da íris"""
 
38
  IrisZone("Zona Endócrina", 0.15, 0.25, (0, 255, 255)),
39
  IrisZone("Zona Pupilar", 0, 0.15, (128, 128, 128))
40
  ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
 
42
  def detect_pupil(self, img: np.ndarray) -> Tuple[int, int, int]:
43
  """Detecta a pupila na imagem"""
44
  try:
45
+ gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
46
+ blur = cv2.GaussianBlur(gray, (5,5), 0)
47
+ _, thresh = cv2.threshold(blur, 30, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
 
 
 
 
 
 
48
 
49
+ contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
 
 
50
 
51
  if not contours:
 
52
  return None
53
 
54
+ # Encontrar o maior contorno circular
55
+ max_area = 0
56
  best_contour = None
57
 
58
  for contour in contours:
59
  area = cv2.contourArea(contour)
60
+ if area > max_area:
61
+ max_area = area
 
 
 
 
 
 
 
62
  best_contour = contour
63
 
64
  if best_contour is None:
 
65
  return None
66
 
 
67
  (x, y), radius = cv2.minEnclosingCircle(best_contour)
 
 
68
  return (int(x), int(y), int(radius))
69
 
70
  except Exception as e:
71
+ logging.error(f"Erro na detecção da pupila: {str(e)}")
72
+ return None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
 
74
  def analyze_iris(self, img: np.ndarray) -> Tuple[np.ndarray, Dict]:
75
  """Análise principal da íris"""
76
  try:
 
77
  output_img = img.copy()
78
  results = {}
79
 
 
80
  pupil = self.detect_pupil(img)
81
  if pupil is None:
82
  return img, {"Erro": "Não foi possível detectar a pupila"}
83
 
84
  x, y, pupil_radius = pupil
 
 
85
  iris_radius = pupil_radius * 4
86
 
 
87
  cv2.circle(output_img, (x, y), pupil_radius, (0, 0, 0), 2)
88
 
 
89
  for zone in self.zones:
90
  inner_r = int(iris_radius * zone.inner_ratio)
91
  outer_r = int(iris_radius * zone.outer_ratio)
92
 
93
+ cv2.circle(output_img, (x, y), outer_r, zone.color, 2)
94
+
95
+ # Análise simplificada da zona
96
  mask = np.zeros(img.shape[:2], dtype=np.uint8)
97
  cv2.circle(mask, (x, y), outer_r, 255, -1)
98
  cv2.circle(mask, (x, y), inner_r, 0, -1)
99
 
100
+ mean_color = cv2.mean(img, mask=mask)
101
+ results[zone.name] = f"Intensidade média: {mean_color[0]:.1f}"
 
 
 
 
 
102
 
103
+ # Adicionar rótulo
104
+ cv2.putText(output_img, zone.name,
105
+ (x - iris_radius, y + outer_r),
 
106
  cv2.FONT_HERSHEY_SIMPLEX, 0.5, zone.color, 1)
107
 
 
108
  return output_img, results
109
 
110
  except Exception as e:
111
+ logging.error(f"Erro na análise: {str(e)}")
112
+ return img, {"Erro": str(e)}
113
 
114
  def process_image(img):
115
+ """Função principal para processar imagem"""
116
+ if img is None:
117
+ return None, {"Erro": "Nenhuma imagem fornecida"}
118
+ analyzer = IrisAnalyzer()
119
+ return analyzer.analyze_iris(np.array(img))
 
 
120
 
121
+ # Interface Gradio
122
  with gr.Blocks(theme=gr.themes.Soft()) as iface:
123
  gr.Markdown("""
124
+ # 🔍 Analisador de Íris
125
+ ### Análise de zonas da íris baseada na teoria de Jensen
 
 
126
  """)
127
 
128
  with gr.Row():
129
+ with gr.Column():
 
130
  input_image = gr.Image(
131
+ label="Upload da imagem do olho",
132
  type="numpy",
133
+ sources=["upload", "clipboard"]
 
134
  )
135
 
136
+ analyze_btn = gr.Button("📸 Analisar", variant="primary")
 
 
 
 
 
 
 
 
 
 
 
 
137
 
138
+ with gr.Column():
139
+ output_image = gr.Image(label="Análise Visual")
140
+ results = gr.JSON(label="Resultados")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
 
 
142
  analyze_btn.click(
143
  fn=process_image,
144
  inputs=input_image,
145
+ outputs=[output_image, results]
146
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
 
148
  if __name__ == "__main__":
149
+ iface.launch()