Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -1,607 +1,272 @@
|
|
1 |
import gradio as gr
|
2 |
import cv2
|
3 |
import numpy as np
|
4 |
-
from PIL import Image
|
5 |
from dataclasses import dataclass
|
6 |
-
from typing import
|
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'
|
16 |
-
)
|
17 |
-
|
18 |
@dataclass
|
19 |
class IrisZone:
|
20 |
-
"""Define características e atributos de uma zona da íris"""
|
21 |
name: str
|
22 |
-
|
23 |
-
outer_ratio: float
|
24 |
color: Tuple[int, int, int]
|
25 |
-
|
26 |
-
|
27 |
-
indicators: Dict[str, List[str]]
|
28 |
|
29 |
class IrisAnalyzer:
|
30 |
-
"""Classe principal para análise da íris"""
|
31 |
def __init__(self):
|
32 |
self.zones = [
|
33 |
IrisZone(
|
34 |
name="Zona Cerebral/Neural",
|
35 |
-
|
36 |
-
outer_ratio=1.0,
|
37 |
color=(255, 0, 0),
|
38 |
-
|
39 |
-
related_systems=["Cérebro", "Medula", "Nervos"],
|
40 |
-
indicators={
|
41 |
"baixa": [
|
42 |
-
"Possível fadiga
|
43 |
-
"
|
44 |
-
"
|
|
|
45 |
],
|
46 |
-
"media": [
|
47 |
-
|
48 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
],
|
50 |
-
"
|
51 |
-
|
52 |
-
"Continuar práticas saudáveis"
|
53 |
-
]
|
54 |
}
|
55 |
),
|
56 |
IrisZone(
|
57 |
name="Zona Digestiva",
|
58 |
-
|
59 |
-
outer_ratio=0.85,
|
60 |
color=(0, 255, 0),
|
61 |
-
|
62 |
-
related_systems=["Estômago", "Intestinos", "Fígado"],
|
63 |
-
indicators={
|
64 |
"baixa": [
|
65 |
-
"
|
66 |
-
"
|
67 |
-
"
|
|
|
68 |
],
|
69 |
-
"media": [
|
70 |
-
|
71 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
72 |
],
|
73 |
-
"
|
74 |
-
|
75 |
-
"Manter hábitos saudáveis"
|
76 |
-
]
|
77 |
}
|
78 |
),
|
79 |
IrisZone(
|
80 |
name="Zona Respiratória",
|
81 |
-
|
82 |
-
outer_ratio=0.7,
|
83 |
color=(0, 0, 255),
|
84 |
-
|
85 |
-
related_systems=["Pulmões", "Brônquios", "Vias aéreas"],
|
86 |
-
indicators={
|
87 |
"baixa": [
|
88 |
-
"
|
89 |
-
"
|
90 |
-
"
|
|
|
91 |
],
|
92 |
-
"media": [
|
93 |
-
|
94 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
95 |
],
|
96 |
-
"
|
97 |
-
|
98 |
-
"Continuar práticas saudáveis"
|
99 |
-
]
|
100 |
}
|
101 |
),
|
102 |
IrisZone(
|
103 |
name="Zona Circulatória",
|
104 |
-
|
105 |
-
outer_ratio=0.55,
|
106 |
color=(255, 255, 0),
|
107 |
-
|
108 |
-
related_systems=["Coração", "Vasos", "Circulação"],
|
109 |
-
indicators={
|
110 |
"baixa": [
|
111 |
-
"
|
112 |
-
"
|
113 |
-
"
|
|
|
114 |
],
|
115 |
-
"media": [
|
116 |
-
|
117 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
118 |
],
|
119 |
-
"
|
120 |
-
|
121 |
-
"Manter hábitos ativos"
|
122 |
-
]
|
123 |
}
|
124 |
),
|
125 |
IrisZone(
|
126 |
name="Zona Linfática",
|
127 |
-
|
128 |
-
outer_ratio=0.4,
|
129 |
color=(255, 0, 255),
|
130 |
-
|
131 |
-
related_systems=["Linfonodos", "Imunidade", "Defesa"],
|
132 |
-
indicators={
|
133 |
"baixa": [
|
134 |
-
"
|
135 |
-
"
|
136 |
-
"
|
|
|
137 |
],
|
138 |
-
"media": [
|
139 |
-
|
140 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
141 |
],
|
142 |
-
"
|
143 |
-
|
144 |
-
"Manter hábitos saudáveis"
|
145 |
-
]
|
146 |
}
|
147 |
),
|
148 |
IrisZone(
|
149 |
name="Zona Endócrina",
|
150 |
-
|
151 |
-
outer_ratio=0.25,
|
152 |
color=(0, 255, 255),
|
153 |
-
|
154 |
-
related_systems=["Glândulas", "Hormônios", "Metabolismo"],
|
155 |
-
indicators={
|
156 |
"baixa": [
|
157 |
-
"
|
158 |
-
"
|
159 |
-
"
|
|
|
160 |
],
|
161 |
-
"media": [
|
162 |
-
|
163 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
164 |
],
|
165 |
-
"
|
166 |
-
|
167 |
-
"Manter hábitos regulares"
|
168 |
-
]
|
169 |
}
|
170 |
),
|
171 |
IrisZone(
|
172 |
name="Zona Pupilar",
|
173 |
-
|
174 |
-
outer_ratio=0.15,
|
175 |
color=(128, 128, 128),
|
176 |
-
|
177 |
-
related_systems=["SNA", "Reflexos", "Regulação"],
|
178 |
-
indicators={
|
179 |
"baixa": [
|
180 |
-
"
|
181 |
-
"
|
182 |
-
"
|
|
|
183 |
],
|
184 |
-
"media": [
|
185 |
-
|
186 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
187 |
],
|
188 |
-
"
|
189 |
-
|
190 |
-
"Manter práticas saudáveis"
|
191 |
-
]
|
192 |
}
|
193 |
)
|
194 |
]
|
195 |
|
196 |
-
def
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
# Redução de ruído
|
212 |
-
denoised = cv2.fastNlMeansDenoisingColored(enhanced, None, 10, 10, 7, 21)
|
213 |
-
|
214 |
-
return denoised
|
215 |
-
except Exception as e:
|
216 |
-
logging.error(f"Erro no pré-processamento: {str(e)}")
|
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 |
-
|
229 |
-
# Operações morfológicas
|
230 |
-
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
|
231 |
-
morph = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
|
232 |
-
|
233 |
-
# Encontrar contornos
|
234 |
-
contours, _ = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
235 |
-
|
236 |
-
if not contours:
|
237 |
-
return None
|
238 |
-
|
239 |
-
# Encontrar o contorno mais circular
|
240 |
-
max_circularity = 0
|
241 |
-
best_contour = None
|
242 |
-
|
243 |
-
for contour in contours:
|
244 |
-
area = cv2.contourArea(contour)
|
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 |
-
(
|
258 |
-
|
|
|
259 |
|
260 |
-
|
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)
|
269 |
-
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
|
270 |
-
zone_pixels = cv2.bitwise_and(gray, gray, mask=mask)
|
271 |
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
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 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
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 |
-
#
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
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
|
368 |
-
text_y = y + outer_r
|
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
|
442 |
|
443 |
-
|
444 |
-
|
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 |
-
|
509 |
-
|
510 |
-
|
511 |
-
|
512 |
-
|
513 |
-
|
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 |
-
|
543 |
-
|
544 |
-
|
545 |
-
|
546 |
-
|
547 |
-
|
548 |
-
|
549 |
-
|
550 |
-
|
551 |
-
|
552 |
-
|
553 |
-
|
554 |
-
|
555 |
-
|
556 |
-
|
557 |
-
|
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 |
-
|
603 |
-
iface.launch()
|
604 |
-
logging.info("Aplicação iniciada com sucesso")
|
605 |
-
except Exception as e:
|
606 |
-
logging.error(f"Erro ao iniciar a aplicação: {str(e)}")
|
607 |
-
raise
|
|
|
1 |
import gradio as gr
|
2 |
import cv2
|
3 |
import numpy as np
|
|
|
4 |
from dataclasses import dataclass
|
5 |
+
from typing import Dict, List, Tuple
|
|
|
|
|
|
|
6 |
from datetime import datetime
|
7 |
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
@dataclass
|
9 |
class IrisZone:
|
|
|
10 |
name: str
|
11 |
+
ratio: Tuple[float, float] # (inner, outer)
|
|
|
12 |
color: Tuple[int, int, int]
|
13 |
+
conditions: Dict[str, List[str]] # Detailed health conditions
|
14 |
+
recommendations: Dict[str, List[str]]
|
|
|
15 |
|
16 |
class IrisAnalyzer:
|
|
|
17 |
def __init__(self):
|
18 |
self.zones = [
|
19 |
IrisZone(
|
20 |
name="Zona Cerebral/Neural",
|
21 |
+
ratio=(0.85, 1.0),
|
|
|
22 |
color=(255, 0, 0),
|
23 |
+
conditions={
|
|
|
|
|
24 |
"baixa": [
|
25 |
+
"Possível fadiga neural crônica",
|
26 |
+
"Indicadores de estresse prolongado",
|
27 |
+
"Sinais de insônia ou distúrbios do sono",
|
28 |
+
"Possível déficit de vitamina B12"
|
29 |
],
|
30 |
+
"media": ["Estado neural estável", "Função cognitiva normal"],
|
31 |
+
"alta": ["Excelente saúde neural", "Ótima resposta cognitiva"]
|
32 |
+
},
|
33 |
+
recommendations={
|
34 |
+
"baixa": [
|
35 |
+
"Suplementação de vitamina B12",
|
36 |
+
"Técnicas de meditação diária",
|
37 |
+
"Melhorar qualidade do sono",
|
38 |
+
"Reduzir exposição a telas"
|
39 |
],
|
40 |
+
"media": ["Manter rotina de sono", "Exercícios mentais regulares"],
|
41 |
+
"alta": ["Manter práticas atuais", "Exercícios de mindfulness"]
|
|
|
|
|
42 |
}
|
43 |
),
|
44 |
IrisZone(
|
45 |
name="Zona Digestiva",
|
46 |
+
ratio=(0.7, 0.85),
|
|
|
47 |
color=(0, 255, 0),
|
48 |
+
conditions={
|
|
|
|
|
49 |
"baixa": [
|
50 |
+
"Possível inflamação intestinal",
|
51 |
+
"Sinais de má absorção",
|
52 |
+
"Indicadores de disbiose",
|
53 |
+
"Possível deficiência enzimática"
|
54 |
],
|
55 |
+
"media": ["Digestão funcional", "Absorção adequada"],
|
56 |
+
"alta": ["Excelente saúde digestiva", "Ótima absorção"]
|
57 |
+
},
|
58 |
+
recommendations={
|
59 |
+
"baixa": [
|
60 |
+
"Probióticos específicos",
|
61 |
+
"Enzimas digestivas",
|
62 |
+
"Dieta anti-inflamatória",
|
63 |
+
"Eliminar alimentos processados"
|
64 |
],
|
65 |
+
"media": ["Manter dieta balanceada", "Hidratação adequada"],
|
66 |
+
"alta": ["Manter dieta atual", "Rotina alimentar saudável"]
|
|
|
|
|
67 |
}
|
68 |
),
|
69 |
IrisZone(
|
70 |
name="Zona Respiratória",
|
71 |
+
ratio=(0.55, 0.7),
|
|
|
72 |
color=(0, 0, 255),
|
73 |
+
conditions={
|
|
|
|
|
74 |
"baixa": [
|
75 |
+
"Possível comprometimento respiratório",
|
76 |
+
"Sinais de baixa oxigenação",
|
77 |
+
"Indicadores de congestão brônquica",
|
78 |
+
"Possível sensibilidade respiratória"
|
79 |
],
|
80 |
+
"media": ["Função respiratória adequada", "Oxigenação normal"],
|
81 |
+
"alta": ["Excelente capacidade respiratória", "Ótima oxigenação"]
|
82 |
+
},
|
83 |
+
recommendations={
|
84 |
+
"baixa": [
|
85 |
+
"Exercícios respiratórios diários",
|
86 |
+
"Avaliar qualidade do ar",
|
87 |
+
"Considerar atividades aeróbicas",
|
88 |
+
"Técnicas de respiração profunda"
|
89 |
],
|
90 |
+
"media": ["Manter exercícios regulares", "Praticar respiração consciente"],
|
91 |
+
"alta": ["Continuar práticas saudáveis", "Manter atividades aeróbicas"]
|
|
|
|
|
92 |
}
|
93 |
),
|
94 |
IrisZone(
|
95 |
name="Zona Circulatória",
|
96 |
+
ratio=(0.4, 0.55),
|
|
|
97 |
color=(255, 255, 0),
|
98 |
+
conditions={
|
|
|
|
|
99 |
"baixa": [
|
100 |
+
"Possível circulação periférica reduzida",
|
101 |
+
"Indicadores de estagnação sanguínea",
|
102 |
+
"Sinais de baixo fluxo sanguíneo",
|
103 |
+
"Possível deficiência de ferro"
|
104 |
],
|
105 |
+
"media": ["Circulação adequada", "Fluxo sanguíneo normal"],
|
106 |
+
"alta": ["Excelente circulação", "Ótimo fluxo sanguíneo"]
|
107 |
+
},
|
108 |
+
recommendations={
|
109 |
+
"baixa": [
|
110 |
+
"Aumentar atividade física",
|
111 |
+
"Considerar suplementação de ferro",
|
112 |
+
"Massagens circulatórias",
|
113 |
+
"Hidratação adequada"
|
114 |
],
|
115 |
+
"media": ["Manter exercícios regulares", "Alimentação rica em ferro"],
|
116 |
+
"alta": ["Manter rotina atual", "Continuar exercícios"]
|
|
|
|
|
117 |
}
|
118 |
),
|
119 |
IrisZone(
|
120 |
name="Zona Linfática",
|
121 |
+
ratio=(0.25, 0.4),
|
|
|
122 |
color=(255, 0, 255),
|
123 |
+
conditions={
|
|
|
|
|
124 |
"baixa": [
|
125 |
+
"Sistema linfático congestionado",
|
126 |
+
"Possível retenção de líquidos",
|
127 |
+
"Indicadores de toxicidade",
|
128 |
+
"Baixa resposta imunológica"
|
129 |
],
|
130 |
+
"media": ["Sistema linfático funcional", "Drenagem adequada"],
|
131 |
+
"alta": ["Excelente drenagem linfática", "Ótima desintoxicação"]
|
132 |
+
},
|
133 |
+
recommendations={
|
134 |
+
"baixa": [
|
135 |
+
"Drenagem linfática regular",
|
136 |
+
"Aumentar consumo de água",
|
137 |
+
"Exercícios específicos",
|
138 |
+
"Dieta desintoxicante"
|
139 |
],
|
140 |
+
"media": ["Manter hidratação", "Exercícios leves regulares"],
|
141 |
+
"alta": ["Manter hábitos atuais", "Continuar atividades físicas"]
|
|
|
|
|
142 |
}
|
143 |
),
|
144 |
IrisZone(
|
145 |
name="Zona Endócrina",
|
146 |
+
ratio=(0.15, 0.25),
|
|
|
147 |
color=(0, 255, 255),
|
148 |
+
conditions={
|
|
|
|
|
149 |
"baixa": [
|
150 |
+
"Possível desequilíbrio hormonal",
|
151 |
+
"Sinais de estresse adrenal",
|
152 |
+
"Indicadores de fadiga endócrina",
|
153 |
+
"Possível disfunção tireoidiana"
|
154 |
],
|
155 |
+
"media": ["Sistema endócrino estável", "Função hormonal adequada"],
|
156 |
+
"alta": ["Excelente equilíbrio hormonal", "Ótima função endócrina"]
|
157 |
+
},
|
158 |
+
recommendations={
|
159 |
+
"baixa": [
|
160 |
+
"Gestão do estresse",
|
161 |
+
"Suporte adrenal natural",
|
162 |
+
"Regular ciclo sono-vigília",
|
163 |
+
"Alimentação rica em iodo"
|
164 |
],
|
165 |
+
"media": ["Manter rotina regular", "Cuidar do sono"],
|
166 |
+
"alta": ["Manter equilíbrio atual", "Continuar boas práticas"]
|
|
|
|
|
167 |
}
|
168 |
),
|
169 |
IrisZone(
|
170 |
name="Zona Pupilar",
|
171 |
+
ratio=(0, 0.15),
|
|
|
172 |
color=(128, 128, 128),
|
173 |
+
conditions={
|
|
|
|
|
174 |
"baixa": [
|
175 |
+
"Sistema nervoso autônomo sobrecarregado",
|
176 |
+
"Possível desequilíbrio simpático/parassimpático",
|
177 |
+
"Indicadores de estresse crônico",
|
178 |
+
"Sinais de fadiga autonômica"
|
179 |
],
|
180 |
+
"media": ["SNA equilibrado", "Resposta autonômica normal"],
|
181 |
+
"alta": ["Excelente regulação autonômica", "Ótimo equilíbrio do SNA"]
|
182 |
+
},
|
183 |
+
recommendations={
|
184 |
+
"baixa": [
|
185 |
+
"Técnicas de relaxamento",
|
186 |
+
"Práticas de mindfulness",
|
187 |
+
"Regular rotina diária",
|
188 |
+
"Exercícios de respiração"
|
189 |
],
|
190 |
+
"media": ["Manter práticas relaxantes", "Continuar boa rotina"],
|
191 |
+
"alta": ["Manter equilíbrio atual", "Continuar práticas saudáveis"]
|
|
|
|
|
192 |
}
|
193 |
)
|
194 |
]
|
195 |
|
196 |
+
def analyze_iris(self, image: np.ndarray) -> Dict:
|
197 |
+
gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
|
198 |
+
center = (image.shape[1]//2, image.shape[0]//2)
|
199 |
+
radius = min(image.shape[:2])//4
|
200 |
+
|
201 |
+
results = {
|
202 |
+
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
203 |
+
"analysis": {},
|
204 |
+
"recommendations": []
|
205 |
+
}
|
206 |
+
|
207 |
+
for zone in self.zones:
|
208 |
+
inner_r = int(radius * zone.ratio[0])
|
209 |
+
outer_r = int(radius * zone.ratio[1])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
210 |
|
211 |
+
mask = np.zeros(gray.shape, dtype=np.uint8)
|
212 |
+
cv2.circle(mask, center, outer_r, 255, -1)
|
213 |
+
cv2.circle(mask, center, inner_r, 0, -1)
|
214 |
|
215 |
+
zone_intensity = cv2.mean(gray, mask=mask)[0]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
216 |
|
217 |
+
# Análise detalhada baseada na intensidade
|
218 |
+
if zone_intensity < 85:
|
219 |
+
level = "baixa"
|
220 |
+
elif zone_intensity < 170:
|
221 |
+
level = "media"
|
222 |
+
else:
|
223 |
+
level = "alta"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
224 |
|
225 |
+
results["analysis"][zone.name] = {
|
226 |
+
"conditions": zone.conditions[level],
|
227 |
+
"recommendations": zone.recommendations[level],
|
228 |
+
"intensity": float(zone_intensity),
|
229 |
+
"status": level
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
230 |
}
|
231 |
|
232 |
+
# Marcar zona na imagem
|
233 |
+
cv2.circle(image, center, outer_r, zone.color, 2)
|
234 |
+
cv2.putText(image, zone.name,
|
235 |
+
(center[0]-outer_r, center[1]+outer_r),
|
236 |
+
cv2.FONT_HERSHEY_SIMPLEX, 0.5, zone.color, 1)
|
237 |
+
|
238 |
+
return image, results
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
239 |
|
240 |
def process_image(img):
|
|
|
241 |
if img is None:
|
242 |
+
return None, "Favor carregar uma imagem."
|
243 |
|
244 |
+
analyzer = IrisAnalyzer()
|
245 |
+
processed_img, results = analyzer.analyze_iris(img)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
246 |
|
247 |
+
report = "# Análise Detalhada da Íris\n\n"
|
248 |
+
for zone_name, analysis in results["analysis"].items():
|
249 |
+
report += f"## {zone_name}\n\n"
|
250 |
+
report += "### Condições Identificadas:\n"
|
251 |
+
for condition in analysis["conditions"]:
|
252 |
+
report += f"- {condition}\n"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
253 |
|
254 |
+
report += "\n### Recomendações:\n"
|
255 |
+
for rec in analysis["recommendations"]:
|
256 |
+
report += f"- {rec}\n\n"
|
257 |
+
|
258 |
+
return processed_img, report
|
259 |
+
|
260 |
+
interface = gr.Interface(
|
261 |
+
fn=process_image,
|
262 |
+
inputs=gr.Image(type="numpy"),
|
263 |
+
outputs=[
|
264 |
+
gr.Image(label="Análise Visual"),
|
265 |
+
gr.Markdown(label="Relatório Detalhado")
|
266 |
+
],
|
267 |
+
title="Análise Iridológica Detalhada",
|
268 |
+
description="⚠️ Sistema apenas para fins educacionais. Não substitui diagnóstico médico."
|
269 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
270 |
|
271 |
if __name__ == "__main__":
|
272 |
+
interface.launch()
|
|
|
|
|
|
|
|
|
|