DHEIVER commited on
Commit
34e10a8
·
verified ·
1 Parent(s): 82a1a13

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +412 -264
app.py CHANGED
@@ -5,13 +5,11 @@ from PIL import Image
5
  from dataclasses import dataclass
6
  from typing import Tuple, Dict, List
7
  import torch
8
- import torch.nn.functional as F
9
  import torchvision.transforms as transforms
10
  import logging
11
  from datetime import datetime
12
- import json
13
 
14
- # Configuração básica de logging
15
  logging.basicConfig(
16
  level=logging.INFO,
17
  format='%(asctime)s - %(levelname)s - %(message)s'
@@ -19,115 +17,14 @@ logging.basicConfig(
19
 
20
  @dataclass
21
  class IrisZone:
22
- """Classe para definir as características de uma zona da íris"""
23
  name: str
24
  inner_ratio: float
25
  outer_ratio: float
26
  color: Tuple[int, int, int]
27
  description: str
28
- indicators: Dict[str, str]
29
-
30
- def __post_init__(self):
31
- if not 0 <= self.inner_ratio <= 1:
32
- raise ValueError("inner_ratio deve estar entre 0 e 1")
33
- if not 0 <= self.outer_ratio <= 1:
34
- raise ValueError("outer_ratio deve estar entre 0 e 1")
35
- if self.inner_ratio >= self.outer_ratio:
36
- raise ValueError("inner_ratio deve ser menor que outer_ratio")
37
-
38
- class IrisAnalysis:
39
- """Classe para análise e interpretação dos resultados"""
40
-
41
- @staticmethod
42
- def get_zone_interpretation(zone_name: str, intensity: float, variation: float) -> Dict:
43
- """Interpretação detalhada para cada zona"""
44
- base_interpretations = {
45
- "Zona Cerebral/Neural": {
46
- "aspectos": "Sistema nervoso central e periférico",
47
- "sistemas": ["Cérebro", "Medula espinhal", "Nervos"],
48
- "baixa": {
49
- "indicacao": "Possível fadiga neural",
50
- "sugestoes": [
51
- "Considerar avaliação do sono",
52
- "Verificar níveis de estresse",
53
- "Avaliar demanda cognitiva"
54
- ]
55
- },
56
- "média": {
57
- "indicacao": "Condição neural moderada",
58
- "sugestoes": [
59
- "Manter boa higiene do sono",
60
- "Praticar atividades mentais"
61
- ]
62
- },
63
- "alta": {
64
- "indicacao": "Boa vitalidade neural",
65
- "sugestoes": [
66
- "Manter práticas saudáveis",
67
- "Continuar estimulação cognitiva"
68
- ]
69
- }
70
- },
71
- "Zona Digestiva": {
72
- "aspectos": "Sistema digestivo completo",
73
- "sistemas": ["Estômago", "Intestinos", "Fígado", "Pâncreas"],
74
- "baixa": {
75
- "indicacao": "Possível sensibilidade digestiva",
76
- "sugestoes": [
77
- "Avaliar hábitos alimentares",
78
- "Considerar diário alimentar",
79
- "Observar reações a alimentos"
80
- ]
81
- },
82
- "média": {
83
- "indicacao": "Sistema digestivo em equilíbrio moderado",
84
- "sugestoes": [
85
- "Manter alimentação balanceada",
86
- "Observar horários das refeições"
87
- ]
88
- },
89
- "alta": {
90
- "indicacao": "Boa condição digestiva",
91
- "sugestoes": [
92
- "Manter dieta equilibrada",
93
- "Continuar bons hábitos"
94
- ]
95
- }
96
- },
97
- # [Definições similares para outras zonas...]
98
- }
99
-
100
- # Determinar nível baseado na intensidade
101
- if intensity < 85:
102
- nivel = "baixa"
103
- confianca = "reduzida" if variation > 30 else "moderada"
104
- elif intensity < 170:
105
- nivel = "média"
106
- confianca = "moderada" if variation > 20 else "alta"
107
- else:
108
- nivel = "alta"
109
- confianca = "alta" if variation < 15 else "moderada"
110
-
111
- zone_info = base_interpretations.get(zone_name, {})
112
-
113
- return {
114
- "nome": zone_name,
115
- "aspectos_analisados": zone_info.get("aspectos", ""),
116
- "sistemas_relacionados": zone_info.get("sistemas", []),
117
- "interpretacao": zone_info.get(nivel, {}).get("indicacao", "Sem interpretação disponível"),
118
- "sugestoes": zone_info.get(nivel, {}).get("sugestoes", []),
119
- "metricas": {
120
- "intensidade": intensity,
121
- "variacao": variation,
122
- "nivel_geral": nivel,
123
- "confianca_analise": confianca,
124
- },
125
- "indicadores": {
126
- "intensidade_valor": f"{intensity:.1f}/255",
127
- "variacao_valor": f"{variation:.1f}%",
128
- "homogeneidade": "Baixa" if variation > 30 else "Média" if variation > 15 else "Alta"
129
- }
130
- }
131
 
132
  class IrisAnalyzer:
133
  """Classe principal para análise da íris"""
@@ -139,15 +36,167 @@ class IrisAnalyzer:
139
  outer_ratio=1.0,
140
  color=(255, 0, 0),
141
  description="Sistema nervoso central e periférico",
142
- indicators={"estresse": "alto", "energia": "moderada"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  ),
144
- # [Outras zonas definidas similarmente...]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
  ]
146
 
147
  def preprocess_image(self, img: np.ndarray) -> np.ndarray:
148
- """Pré-processamento da imagem"""
149
  try:
150
- # Converter para LAB para melhor contraste
151
  lab = cv2.cvtColor(img, cv2.COLOR_RGB2LAB)
152
  l, a, b = cv2.split(lab)
153
 
@@ -168,13 +217,12 @@ class IrisAnalyzer:
168
  return img
169
 
170
  def detect_pupil(self, img: np.ndarray) -> Tuple[int, int, int]:
171
- """Detecção avançada da pupila"""
172
  try:
173
- # Pré-processar imagem
174
  processed = self.preprocess_image(img)
175
  gray = cv2.cvtColor(processed, cv2.COLOR_RGB2GRAY)
176
 
177
- # Aplicar threshold adaptativo
178
  blur = cv2.GaussianBlur(gray, (5,5), 0)
179
  _, thresh = cv2.threshold(blur, 30, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
180
 
@@ -189,7 +237,7 @@ class IrisAnalyzer:
189
  return None
190
 
191
  # Encontrar o contorno mais circular
192
- best_circularity = 0
193
  best_contour = None
194
 
195
  for contour in contours:
@@ -197,16 +245,15 @@ class IrisAnalyzer:
197
  perimeter = cv2.arcLength(contour, True)
198
  if perimeter == 0:
199
  continue
200
-
201
- circularity = 4 * np.pi * area / (perimeter * perimeter)
202
 
203
- if circularity > best_circularity:
204
- best_circularity = circularity
 
205
  best_contour = contour
206
 
207
  if best_contour is None:
208
  return None
209
-
210
  (x, y), radius = cv2.minEnclosingCircle(best_contour)
211
  return (int(x), int(y), int(radius))
212
 
@@ -214,8 +261,8 @@ class IrisAnalyzer:
214
  logging.error(f"Erro na detecção da pupila: {str(e)}")
215
  return None
216
 
217
- def analyze_zone(self, img: np.ndarray, mask: np.ndarray, zone_name: str) -> Dict:
218
- """Análise detalhada de uma zona específica"""
219
  try:
220
  # Extrair características
221
  mean_color = cv2.mean(img, mask=mask)
@@ -227,86 +274,94 @@ class IrisAnalyzer:
227
  mean_intensity = np.mean(pixels)
228
  std_dev = np.std(pixels)
229
 
230
- # Calcular características adicionais
231
- percentiles = np.percentile(pixels, [25, 50, 75])
 
 
 
 
 
232
 
233
- # Gerar interpretação detalhada
234
- analysis = IrisAnalysis.get_zone_interpretation(
235
- zone_name, mean_intensity, std_dev
236
- )
237
 
238
- # Adicionar métricas estatísticas
239
- analysis["metricas_detalhadas"] = {
240
- "mediana": float(percentiles[1]),
241
- "quartil_inferior": float(percentiles[0]),
242
- "quartil_superior": float(percentiles[2]),
243
- "pixels_analisados": len(pixels),
244
- "variacao_cor": {
245
- "r": mean_color[0],
246
- "g": mean_color[1],
247
- "b": mean_color[2]
 
 
 
 
 
 
248
  }
249
  }
250
 
251
  return analysis
252
 
253
- return {"erro": "Zona sem pixels válidos para análise"}
254
 
255
  except Exception as e:
256
- logging.error(f"Erro na análise da zona {zone_name}: {str(e)}")
257
  return {"erro": str(e)}
258
 
259
  def analyze_iris(self, img: np.ndarray) -> Tuple[np.ndarray, Dict]:
260
- """Análise principal com relatório detalhado"""
261
  try:
262
  output_img = img.copy()
263
- detailed_results = {
264
  "meta": {
265
  "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
266
- "versao_analise": "1.0.0"
267
  },
268
- "resumo_geral": {},
269
  "zonas": {},
270
- "observacoes": []
271
  }
272
 
273
  # Detectar pupila
274
  pupil = self.detect_pupil(img)
275
  if pupil is None:
276
  return img, {"erro": "Não foi possível detectar a pupila"}
277
-
278
  x, y, pupil_radius = pupil
279
  iris_radius = pupil_radius * 4
280
 
281
- # Desenhar círculo da pupila
282
  cv2.circle(output_img, (x, y), pupil_radius, (0, 0, 0), 2)
283
 
284
  # Analisar cada zona
285
- overall_health_score = 0
286
- num_zones = len(self.zones)
287
 
288
  for zone in self.zones:
289
  inner_r = int(iris_radius * zone.inner_ratio)
290
  outer_r = int(iris_radius * zone.outer_ratio)
291
 
292
- # Criar máscara para a zona
293
  mask = np.zeros(img.shape[:2], dtype=np.uint8)
294
  cv2.circle(mask, (x, y), outer_r, 255, -1)
295
  cv2.circle(mask, (x, y), inner_r, 0, -1)
296
 
297
- # Desenhar círculos da zona
298
  cv2.circle(output_img, (x, y), outer_r, zone.color, 2)
299
 
300
  # Analisar zona
301
- analysis = self.analyze_zone(img, mask, zone.name)
302
- detailed_results["zonas"][zone.name] = analysis
303
 
304
- # Calcular score geral
305
  if "metricas" in analysis:
306
- if analysis["metricas"]["nivel_geral"] == "alta":
307
- overall_health_score += 1
308
- elif analysis["metricas"]["nivel_geral"] == "média":
309
- overall_health_score += 0.5
 
310
 
311
  # Adicionar texto
312
  text_x = x - iris_radius
@@ -314,142 +369,235 @@ class IrisAnalyzer:
314
  cv2.putText(output_img, zone.name, (text_x, text_y),
315
  cv2.FONT_HERSHEY_SIMPLEX, 0.5, zone.color, 1)
316
 
317
- # Calcular resumo geral
318
- health_percentage = (overall_health_score / num_zones) * 100
319
- detailed_results["resumo_geral"] = {
320
- "indice_geral": f"{health_percentage:.1f}%",
321
- "interpretacao": "Bom" if health_percentage > 75 else
322
- "Moderado" if health_percentage > 50 else
323
- "Requer atenção"
324
- }
 
 
325
 
326
- return output_img, detailed_results
327
 
328
  except Exception as e:
329
  logging.error(f"Erro na análise da íris: {str(e)}")
330
  return img, {"erro": str(e)}
331
 
332
- def format_results(results: Dict) -> str:
333
- """Formata os resultados para exibição"""
334
- if "erro" in results:
335
- return f"Erro na análise: {results['erro']}"
336
-
337
- formatted = "# Relatório de Análise da Íris\n\n"
338
 
339
- # Adicionar resumo geral
340
- if "resumo_geral" in results:
341
- formatted += "## Resumo Geral\n"
342
- formatted += f"- Índice Geral: {results['resumo_geral']['indice_geral']}\n"
343
- formatted += f"- Interpretação: {results['resumo_geral']['interpretacao']}\n\n"
 
 
 
344
 
345
- # Adicionar análise por zona
346
- if "zonas" in results:
347
- formatted += "## Análise por Zona\n\n"
348
- for zone_name, analysis in results["zonas"].items():
349
- formatted += f"### {zone_name}\n"
350
- formatted += f"- Aspectos Analisados: {analysis.get('aspectos_analisados', 'N/A')}\n"
351
- formatted += f"- Interpretação: {analysis.get('interpretacao', 'N/A')}\n"
352
-
353
- if "sugestoes" in analysis:
354
- formatted += "- Sugestões:\n"
355
- for sugestao in analysis["sugestoes"]:
356
- formatted += f" * {sugestao}\n"
357
-
358
- if "metricas" in analysis:
359
- formatted += f"- Nível Geral: {analysis['metricas']['nivel_geral']}\n"
360
- formatted += f"- Confiança da Análise: {analysis['metricas']['confianca_analise']}\n"
361
-
362
- formatted += "\n"
363
 
364
- # Adicionar timestamp
365
- if "meta" in results:
366
- formatted += f"\n---\nAnálise realizada em: {results['meta']['timestamp']}\n"
367
- formatted += f"Versão do sistema: {results['meta']['versao_analise']}\n"
 
 
 
 
 
 
 
 
 
368
 
369
- return formatted
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
370
 
371
  def process_image(img):
372
- """Função principal para processar imagem"""
373
  if img is None:
374
- return None, "Erro: Nenhuma imagem fornecida"
375
-
376
- analyzer = IrisAnalyzer()
377
- output_img, results = analyzer.analyze_iris(np.array(img))
378
- formatted_results = format_results(results)
379
 
380
- return output_img, formatted_results
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
381
 
382
  # Interface Gradio
383
  with gr.Blocks(theme=gr.themes.Soft()) as iface:
384
  gr.Markdown("""
385
  # 🔍 Analisador Avançado de Íris
386
- ### Sistema de análise baseado na teoria de Jensen
387
 
388
- ⚠️ **AVISO**: Esta é uma demonstração educacional. Não deve ser utilizada para diagnósticos médicos.
389
  """)
390
 
391
- with gr.Row():
392
- with gr.Column(scale=1):
393
- input_image = gr.Image(
394
- label="Upload da imagem do olho",
395
- type="numpy",
396
- sources=["upload", "clipboard"]
397
- )
398
-
399
- analyze_btn = gr.Button(
400
- "📸 Analisar Imagem",
401
- variant="primary"
402
- )
403
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
404
  gr.Markdown("""
405
- ### Instruções:
406
- 1. Faça upload de uma imagem clara do olho
407
- 2. Certifique-se que a íris está bem visível
408
- 3. Clique em "Analisar Imagem"
409
- 4. Revise o relatório detalhado
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
410
  """)
411
-
412
- with gr.Column(scale=1):
413
- output_image = gr.Image(label="Análise Visual")
414
- results_text = gr.Markdown(label="Relatório Detalhado")
415
-
416
- with gr.Row():
417
- gr.Markdown("""
418
- ### Legenda das Zonas:
419
- - 🔴 Zona Cerebral/Neural: Sistema nervoso
420
- - 🟢 Zona Digestiva: Sistema digestivo
421
- - 🔵 Zona Respiratória: Sistema respiratório
422
- - 🟡 Zona Circulatória: Sistema circulatório
423
- - 🟣 Zona Linfática: Sistema linfático
424
- - 🔰 Zona Endócrina: Sistema hormonal
425
- - ⚪ Zona Pupilar: Sistema nervoso autônomo
426
- """)
427
 
 
428
  analyze_btn.click(
429
  fn=process_image,
430
  inputs=input_image,
431
- outputs=[output_image, results_text]
 
 
 
 
 
 
 
432
  )
433
-
434
- gr.Markdown("""
435
- ---
436
- ### 📋 Sobre a Análise
437
-
438
- Este sistema realiza:
439
- - Detecção automática da pupila
440
- - Análise de 7 zonas principais da íris
441
- - Avaliação de padrões e texturas
442
- - Geração de relatório detalhado
443
-
444
- **Observações Importantes:**
445
- - A iridologia é uma prática alternativa
446
- - Os resultados são interpretativos
447
- - Consulte profissionais de saúde para diagnósticos
448
-
449
- ---
450
- """)
451
 
452
- # Configurações para execução
453
  if __name__ == "__main__":
454
  try:
455
  iface.launch()
 
5
  from dataclasses import dataclass
6
  from typing import Tuple, Dict, List
7
  import torch
 
8
  import torchvision.transforms as transforms
9
  import logging
10
  from datetime import datetime
 
11
 
12
+ # Configuração de logging
13
  logging.basicConfig(
14
  level=logging.INFO,
15
  format='%(asctime)s - %(levelname)s - %(message)s'
 
17
 
18
  @dataclass
19
  class IrisZone:
20
+ """Define características e atributos de uma zona da íris"""
21
  name: str
22
  inner_ratio: float
23
  outer_ratio: float
24
  color: Tuple[int, int, int]
25
  description: str
26
+ related_systems: List[str]
27
+ indicators: Dict[str, List[str]]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
  class IrisAnalyzer:
30
  """Classe principal para análise da íris"""
 
36
  outer_ratio=1.0,
37
  color=(255, 0, 0),
38
  description="Sistema nervoso central e periférico",
39
+ related_systems=["Cérebro", "Medula", "Nervos"],
40
+ indicators={
41
+ "baixa": [
42
+ "Possível fadiga mental",
43
+ "Considerar níveis de estresse",
44
+ "Avaliar qualidade do sono"
45
+ ],
46
+ "media": [
47
+ "Estado neural adequado",
48
+ "Manter atividades mentais"
49
+ ],
50
+ "alta": [
51
+ "Boa vitalidade neural",
52
+ "Continuar práticas saudáveis"
53
+ ]
54
+ }
55
+ ),
56
+ IrisZone(
57
+ name="Zona Digestiva",
58
+ inner_ratio=0.7,
59
+ outer_ratio=0.85,
60
+ color=(0, 255, 0),
61
+ description="Sistema digestivo completo",
62
+ related_systems=["Estômago", "Intestinos", "Fígado"],
63
+ indicators={
64
+ "baixa": [
65
+ "Atenção à digestão",
66
+ "Avaliar alimentação",
67
+ "Observar sensibilidades"
68
+ ],
69
+ "media": [
70
+ "Digestão adequada",
71
+ "Manter dieta balanceada"
72
+ ],
73
+ "alta": [
74
+ "Boa saúde digestiva",
75
+ "Manter hábitos saudáveis"
76
+ ]
77
+ }
78
+ ),
79
+ IrisZone(
80
+ name="Zona Respiratória",
81
+ inner_ratio=0.55,
82
+ outer_ratio=0.7,
83
+ color=(0, 0, 255),
84
+ description="Sistema respiratório",
85
+ related_systems=["Pulmões", "Brônquios", "Vias aéreas"],
86
+ indicators={
87
+ "baixa": [
88
+ "Atenção respiratória",
89
+ "Considerar exercícios",
90
+ "Avaliar ambiente"
91
+ ],
92
+ "media": [
93
+ "Função respiratória adequada",
94
+ "Manter atividades aeróbicas"
95
+ ],
96
+ "alta": [
97
+ "Boa capacidade respiratória",
98
+ "Continuar práticas saudáveis"
99
+ ]
100
+ }
101
+ ),
102
+ IrisZone(
103
+ name="Zona Circulatória",
104
+ inner_ratio=0.4,
105
+ outer_ratio=0.55,
106
+ color=(255, 255, 0),
107
+ description="Sistema cardiovascular",
108
+ related_systems=["Coração", "Vasos", "Circulação"],
109
+ indicators={
110
+ "baixa": [
111
+ "Atenção circulatória",
112
+ "Considerar exercícios",
113
+ "Avaliar rotina"
114
+ ],
115
+ "media": [
116
+ "Circulação adequada",
117
+ "Manter atividade física"
118
+ ],
119
+ "alta": [
120
+ "Boa saúde circulatória",
121
+ "Manter hábitos ativos"
122
+ ]
123
+ }
124
+ ),
125
+ IrisZone(
126
+ name="Zona Linfática",
127
+ inner_ratio=0.25,
128
+ outer_ratio=0.4,
129
+ color=(255, 0, 255),
130
+ description="Sistema imunológico",
131
+ related_systems=["Linfonodos", "Imunidade", "Defesa"],
132
+ indicators={
133
+ "baixa": [
134
+ "Atenção imunológica",
135
+ "Considerar suporte",
136
+ "Avaliar estresse"
137
+ ],
138
+ "media": [
139
+ "Imunidade adequada",
140
+ "Manter cuidados básicos"
141
+ ],
142
+ "alta": [
143
+ "Boa resposta imune",
144
+ "Manter hábitos saudáveis"
145
+ ]
146
+ }
147
+ ),
148
+ IrisZone(
149
+ name="Zona Endócrina",
150
+ inner_ratio=0.15,
151
+ outer_ratio=0.25,
152
+ color=(0, 255, 255),
153
+ description="Sistema hormonal",
154
+ related_systems=["Glândulas", "Hormônios", "Metabolismo"],
155
+ indicators={
156
+ "baixa": [
157
+ "Atenção hormonal",
158
+ "Considerar ritmos",
159
+ "Avaliar rotina"
160
+ ],
161
+ "media": [
162
+ "Função hormonal adequada",
163
+ "Manter equilíbrio"
164
+ ],
165
+ "alta": [
166
+ "Bom equilíbrio hormonal",
167
+ "Manter hábitos regulares"
168
+ ]
169
+ }
170
  ),
171
+ IrisZone(
172
+ name="Zona Pupilar",
173
+ inner_ratio=0,
174
+ outer_ratio=0.15,
175
+ color=(128, 128, 128),
176
+ description="Sistema nervoso autônomo",
177
+ related_systems=["SNA", "Reflexos", "Regulação"],
178
+ indicators={
179
+ "baixa": [
180
+ "Atenção autonômica",
181
+ "Considerar relaxamento",
182
+ "Avaliar estresse"
183
+ ],
184
+ "media": [
185
+ "Função autonômica adequada",
186
+ "Manter equilíbrio"
187
+ ],
188
+ "alta": [
189
+ "Boa regulação autonômica",
190
+ "Manter práticas saudáveis"
191
+ ]
192
+ }
193
+ )
194
  ]
195
 
196
  def preprocess_image(self, img: np.ndarray) -> np.ndarray:
197
+ """Pré-processa a imagem para melhor análise"""
198
  try:
199
+ # Converter para LAB
200
  lab = cv2.cvtColor(img, cv2.COLOR_RGB2LAB)
201
  l, a, b = cv2.split(lab)
202
 
 
217
  return img
218
 
219
  def detect_pupil(self, img: np.ndarray) -> Tuple[int, int, int]:
220
+ """Detecta a pupila na imagem"""
221
  try:
 
222
  processed = self.preprocess_image(img)
223
  gray = cv2.cvtColor(processed, cv2.COLOR_RGB2GRAY)
224
 
225
+ # Threshold adaptativo
226
  blur = cv2.GaussianBlur(gray, (5,5), 0)
227
  _, thresh = cv2.threshold(blur, 30, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
228
 
 
237
  return None
238
 
239
  # Encontrar o contorno mais circular
240
+ max_circularity = 0
241
  best_contour = None
242
 
243
  for contour in contours:
 
245
  perimeter = cv2.arcLength(contour, True)
246
  if perimeter == 0:
247
  continue
 
 
248
 
249
+ circularity = 4 * np.pi * area / (perimeter * perimeter)
250
+ if circularity > max_circularity:
251
+ max_circularity = circularity
252
  best_contour = contour
253
 
254
  if best_contour is None:
255
  return None
256
+
257
  (x, y), radius = cv2.minEnclosingCircle(best_contour)
258
  return (int(x), int(y), int(radius))
259
 
 
261
  logging.error(f"Erro na detecção da pupila: {str(e)}")
262
  return None
263
 
264
+ def analyze_zone(self, img: np.ndarray, mask: np.ndarray, zone: IrisZone) -> Dict:
265
+ """Analisa uma zona específica da íris"""
266
  try:
267
  # Extrair características
268
  mean_color = cv2.mean(img, mask=mask)
 
274
  mean_intensity = np.mean(pixels)
275
  std_dev = np.std(pixels)
276
 
277
+ # Determinar nível
278
+ if mean_intensity < 85:
279
+ nivel = "baixa"
280
+ elif mean_intensity < 170:
281
+ nivel = "media"
282
+ else:
283
+ nivel = "alta"
284
 
285
+ # Calcular confiança
286
+ confianca = "alta" if std_dev < 15 else "media" if std_dev < 30 else "baixa"
 
 
287
 
288
+ # Gerar análise
289
+ analysis = {
290
+ "nome": zone.name,
291
+ "descricao": zone.description,
292
+ "sistemas_relacionados": zone.related_systems,
293
+ "indicadores": zone.indicators[nivel],
294
+ "metricas": {
295
+ "intensidade": float(mean_intensity),
296
+ "variacao": float(std_dev),
297
+ "nivel": nivel,
298
+ "confianca": confianca
299
+ },
300
+ "cores": {
301
+ "r": float(mean_color[0]),
302
+ "g": float(mean_color[1]),
303
+ "b": float(mean_color[2])
304
  }
305
  }
306
 
307
  return analysis
308
 
309
+ return {"erro": "Zona sem pixels válidos"}
310
 
311
  except Exception as e:
312
+ logging.error(f"Erro na análise da zona {zone.name}: {str(e)}")
313
  return {"erro": str(e)}
314
 
315
  def analyze_iris(self, img: np.ndarray) -> Tuple[np.ndarray, Dict]:
316
+ """Realiza a análise completa da íris"""
317
  try:
318
  output_img = img.copy()
319
+ results = {
320
  "meta": {
321
  "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
322
+ "versao": "1.0.0"
323
  },
 
324
  "zonas": {},
325
+ "resumo": {}
326
  }
327
 
328
  # Detectar pupila
329
  pupil = self.detect_pupil(img)
330
  if pupil is None:
331
  return img, {"erro": "Não foi possível detectar a pupila"}
332
+
333
  x, y, pupil_radius = pupil
334
  iris_radius = pupil_radius * 4
335
 
336
+ # Desenhar pupila
337
  cv2.circle(output_img, (x, y), pupil_radius, (0, 0, 0), 2)
338
 
339
  # Analisar cada zona
340
+ total_score = 0
341
+ valid_zones = 0
342
 
343
  for zone in self.zones:
344
  inner_r = int(iris_radius * zone.inner_ratio)
345
  outer_r = int(iris_radius * zone.outer_ratio)
346
 
347
+ # Criar máscara
348
  mask = np.zeros(img.shape[:2], dtype=np.uint8)
349
  cv2.circle(mask, (x, y), outer_r, 255, -1)
350
  cv2.circle(mask, (x, y), inner_r, 0, -1)
351
 
352
+ # Desenhar zona
353
  cv2.circle(output_img, (x, y), outer_r, zone.color, 2)
354
 
355
  # Analisar zona
356
+ analysis = self.analyze_zone(img, mask, zone)
357
+ results["zonas"][zone.name] = analysis
358
 
 
359
  if "metricas" in analysis:
360
+ if analysis["metricas"]["nivel"] == "alta":
361
+ total_score += 1.0
362
+ elif analysis["metricas"]["nivel"] == "media":
363
+ total_score += 0.5
364
+ valid_zones += 1
365
 
366
  # Adicionar texto
367
  text_x = x - iris_radius
 
369
  cv2.putText(output_img, zone.name, (text_x, text_y),
370
  cv2.FONT_HERSHEY_SIMPLEX, 0.5, zone.color, 1)
371
 
372
+ # Calcular índice geral
373
+ if valid_zones > 0:
374
+ health_index = (total_score / valid_zones) * 100
375
+ results["resumo"] = {
376
+ "indice_geral": f"{health_index:.1f}%",
377
+ "interpretacao": "Excelente" if health_index > 80 else
378
+ "Bom" if health_index > 60 else
379
+ "Regular" if health_index > 40 else
380
+ "Requer atenção"
381
+ }
382
 
383
+ return output_img, results
384
 
385
  except Exception as e:
386
  logging.error(f"Erro na análise da íris: {str(e)}")
387
  return img, {"erro": str(e)}
388
 
389
+ def format_zone_report(zone_name: str, analysis: Dict) -> str:
390
+ """Formata o relatório de uma zona específica"""
391
+ if "erro" in analysis:
392
+ return f"Erro na análise de {zone_name}: {analysis['erro']}"
 
 
393
 
394
+ report = f"""### {zone_name}
395
+
396
+ **Descrição:** {analysis.get('descricao', 'N/A')}
397
+
398
+ **Sistemas Relacionados:**
399
+ """
400
+ for sistema in analysis.get('sistemas_relacionados', []):
401
+ report += f"- {sistema}\n"
402
 
403
+ report += "\n**Indicadores:**\n"
404
+ for indicador in analysis.get('indicadores', []):
405
+ report += f"- {indicador}\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
406
 
407
+ if "metricas" in analysis:
408
+ report += f"""
409
+ **Métricas:**
410
+ - Nível: {analysis['metricas']['nivel'].title()}
411
+ - Confiança: {analysis['metricas']['confianca'].title()}
412
+ - Intensidade: {analysis['metricas']['intensidade']:.1f}
413
+ - Variação: {analysis['metricas']['variacao']:.1f}
414
+ """
415
+ return report
416
+
417
+ def format_technical_metrics(analysis: Dict) -> str:
418
+ """Formata as métricas técnicas de uma análise"""
419
+ metrics = """### Métricas Técnicas\n\n"""
420
 
421
+ if "metricas" in analysis:
422
+ metrics += f"""
423
+ - **Análise de Intensidade**
424
+ - Valor: {analysis['metricas']['intensidade']:.1f}/255
425
+ - Interpretação: {analysis['metricas']['nivel'].title()}
426
+
427
+ - **Análise de Variação**
428
+ - Valor: {analysis['metricas']['variacao']:.1f}
429
+ - Confiança: {analysis['metricas']['confianca'].title()}
430
+
431
+ - **Cores (RGB)**
432
+ - R: {analysis['cores']['r']:.1f}
433
+ - G: {analysis['cores']['g']:.1f}
434
+ - B: {analysis['cores']['b']:.1f}
435
+ """
436
+ return metrics
437
 
438
  def process_image(img):
439
+ """Processa a imagem e retorna todos os resultados formatados"""
440
  if img is None:
441
+ return [None] * 6, gr.Warning("Por favor, carregue uma imagem.")
 
 
 
 
442
 
443
+ try:
444
+ analyzer = IrisAnalyzer()
445
+ output_img, results = analyzer.analyze_iris(np.array(img))
446
+
447
+ if "erro" in results:
448
+ return [output_img] + [results["erro"]] * 5
449
+
450
+ # 1. Resumo Geral
451
+ resumo = f"""## Resumo da Análise
452
+
453
+ 🎯 **Índice Geral de Saúde:** {results['resumo'].get('indice_geral', 'N/A')}
454
+ 📊 **Interpretação:** {results['resumo'].get('interpretacao', 'N/A')}
455
+ 🕒 **Data da Análise:** {results['meta']['timestamp']}
456
+
457
+ ---"""
458
+
459
+ # 2. Análise Detalhada
460
+ analise_detalhada = "## Análise Detalhada por Zona\n\n"
461
+ for zone_name, analysis in results['zonas'].items():
462
+ analise_detalhada += format_zone_report(zone_name, analysis) + "\n---\n"
463
+
464
+ # 3. Recomendações
465
+ recomendacoes = "## Recomendações Personalizadas\n\n"
466
+ for zone_name, analysis in results['zonas'].items():
467
+ if analysis.get('indicadores'):
468
+ recomendacoes += f"### {zone_name}\n"
469
+ for idx, rec in enumerate(analysis['indicadores'], 1):
470
+ recomendacoes += f"{idx}. {rec}\n"
471
+ recomendacoes += "\n"
472
+
473
+ # 4. Métricas Técnicas
474
+ metricas = "## Métricas e Indicadores\n\n"
475
+ for zone_name, analysis in results['zonas'].items():
476
+ metricas += f"### {zone_name}\n"
477
+ metricas += format_technical_metrics(analysis) + "\n"
478
+
479
+ # 5. Observações Técnicas
480
+ observacoes = f"""## Informações Técnicas
481
+
482
+ 📌 **Detalhes da Análise**
483
+ - Versão do Sistema: {results['meta']['versao']}
484
+ - Data/Hora: {results['meta']['timestamp']}
485
+ - Zonas Analisadas: {len(results['zonas'])}
486
+
487
+ ⚠️ **Observações**
488
+ - Esta é uma análise educacional
489
+ - Não substitui avaliação médica
490
+ - Baseado na teoria de Jensen
491
+ """
492
+
493
+ return output_img, resumo, analise_detalhada, recomendacoes, metricas, observacoes
494
+
495
+ except Exception as e:
496
+ logging.error(f"Erro no processamento: {str(e)}")
497
+ return [None] * 6, gr.Error(f"Erro no processamento: {str(e)}")
498
 
499
  # Interface Gradio
500
  with gr.Blocks(theme=gr.themes.Soft()) as iface:
501
  gr.Markdown("""
502
  # 🔍 Analisador Avançado de Íris
503
+ ## Sistema Educacional de Análise Iridológica
504
 
505
+ ⚠️ Este é um sistema para fins educacionais. Não utilize para diagnósticos médicos.
506
  """)
507
 
508
+ with gr.Tabs() as tabs:
509
+ # Aba de Análise
510
+ with gr.Tab("📸 Análise"):
511
+ with gr.Row():
512
+ with gr.Column(scale=1):
513
+ input_image = gr.Image(
514
+ label="Upload da Imagem",
515
+ type="numpy",
516
+ sources=["upload", "clipboard"],
517
+ height=400
518
+ )
519
+ analyze_btn = gr.Button("🔍 Analisar", variant="primary", size="lg")
520
+
521
+ with gr.Column(scale=1):
522
+ output_image = gr.Image(label="Resultado da Análise", height=400)
523
+
524
+ # Aba de Resultados
525
+ with gr.Tab("📊 Resultados"):
526
+ with gr.Tabs() as results_tabs:
527
+ with gr.Tab("📝 Resumo"):
528
+ resumo_text = gr.Markdown()
529
+
530
+ with gr.Tab("🔍 Análise Detalhada"):
531
+ analise_text = gr.Markdown()
532
+
533
+ with gr.Tab("💡 Recomendações"):
534
+ recomendacoes_text = gr.Markdown()
535
+
536
+ with gr.Tab("📈 Métricas"):
537
+ metricas_text = gr.Markdown()
538
+
539
+ with gr.Tab("ℹ️ Informações"):
540
+ observacoes_text = gr.Markdown()
541
+
542
+ # Aba de Ajuda
543
+ with gr.Tab("❓ Ajuda"):
544
  gr.Markdown("""
545
+ ## Como Usar o Sistema
546
+
547
+ 1. **Upload da Imagem**
548
+ - Use uma foto clara do olho
549
+ - Certifique-se que a íris está visível
550
+ - Evite reflexos e sombras
551
+
552
+ 2. **Análise**
553
+ - Clique em "Analisar"
554
+ - Aguarde o processamento
555
+ - Revise os resultados nas abas
556
+
557
+ 3. **Interpretação**
558
+ - Resumo: visão geral
559
+ - Análise: detalhes por zona
560
+ - Recomendações: sugestões
561
+ - Métricas: dados técnicos
562
+
563
+ ## Zonas Analisadas
564
+
565
+ 1. 🧠 **Zona Cerebral/Neural**
566
+ - Sistema nervoso
567
+ 2. 🟢 **Zona Digestiva**
568
+ - Sistema digestivo
569
+ 3. 🫁 **Zona Respiratória**
570
+ - Sistema respiratório
571
+ 4. ❤️ **Zona Circulatória**
572
+ - Sistema cardiovascular
573
+ 5. 🔵 **Zona Linfática**
574
+ - Sistema imunológico
575
+ 6. 🟣 **Zona Endócrina**
576
+ - Sistema hormonal
577
+ 7. ⚫ **Zona Pupilar**
578
+ - Sistema nervoso autônomo
579
+
580
+ ## Observações
581
+
582
+ - Sistema educacional
583
+ - Não substitui diagnósticos
584
+ - Consulte profissionais de saúde
585
  """)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
586
 
587
+ # Configurar eventos
588
  analyze_btn.click(
589
  fn=process_image,
590
  inputs=input_image,
591
+ outputs=[
592
+ output_image,
593
+ resumo_text,
594
+ analise_text,
595
+ recomendacoes_text,
596
+ metricas_text,
597
+ observacoes_text
598
+ ]
599
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
600
 
 
601
  if __name__ == "__main__":
602
  try:
603
  iface.launch()