Spaces:
Sleeping
Sleeping
import gradio as gr | |
import cv2 | |
import numpy as np | |
from PIL import Image | |
from dataclasses import dataclass | |
from typing import Tuple, Dict, List | |
import torch | |
import torchvision.transforms as transforms | |
import logging | |
from datetime import datetime | |
# Configuração de logging | |
logging.basicConfig( | |
level=logging.INFO, | |
format='%(asctime)s - %(levelname)s - %(message)s' | |
) | |
class IrisZone: | |
"""Define características e atributos de uma zona da íris""" | |
name: str | |
inner_ratio: float | |
outer_ratio: float | |
color: Tuple[int, int, int] | |
description: str | |
related_systems: List[str] | |
indicators: Dict[str, List[str]] | |
class IrisAnalyzer: | |
"""Classe principal para análise da íris""" | |
def __init__(self): | |
self.zones = [ | |
IrisZone( | |
name="Zona Cerebral/Neural", | |
inner_ratio=0.85, | |
outer_ratio=1.0, | |
color=(255, 0, 0), | |
description="Sistema nervoso central e periférico", | |
related_systems=["Cérebro", "Medula", "Nervos"], | |
indicators={ | |
"baixa": [ | |
"Possível fadiga mental", | |
"Considerar níveis de estresse", | |
"Avaliar qualidade do sono" | |
], | |
"media": [ | |
"Estado neural adequado", | |
"Manter atividades mentais" | |
], | |
"alta": [ | |
"Boa vitalidade neural", | |
"Continuar práticas saudáveis" | |
] | |
} | |
), | |
IrisZone( | |
name="Zona Digestiva", | |
inner_ratio=0.7, | |
outer_ratio=0.85, | |
color=(0, 255, 0), | |
description="Sistema digestivo completo", | |
related_systems=["Estômago", "Intestinos", "Fígado"], | |
indicators={ | |
"baixa": [ | |
"Atenção à digestão", | |
"Avaliar alimentação", | |
"Observar sensibilidades" | |
], | |
"media": [ | |
"Digestão adequada", | |
"Manter dieta balanceada" | |
], | |
"alta": [ | |
"Boa saúde digestiva", | |
"Manter hábitos saudáveis" | |
] | |
} | |
), | |
IrisZone( | |
name="Zona Respiratória", | |
inner_ratio=0.55, | |
outer_ratio=0.7, | |
color=(0, 0, 255), | |
description="Sistema respiratório", | |
related_systems=["Pulmões", "Brônquios", "Vias aéreas"], | |
indicators={ | |
"baixa": [ | |
"Atenção respiratória", | |
"Considerar exercícios", | |
"Avaliar ambiente" | |
], | |
"media": [ | |
"Função respiratória adequada", | |
"Manter atividades aeróbicas" | |
], | |
"alta": [ | |
"Boa capacidade respiratória", | |
"Continuar práticas saudáveis" | |
] | |
} | |
), | |
IrisZone( | |
name="Zona Circulatória", | |
inner_ratio=0.4, | |
outer_ratio=0.55, | |
color=(255, 255, 0), | |
description="Sistema cardiovascular", | |
related_systems=["Coração", "Vasos", "Circulação"], | |
indicators={ | |
"baixa": [ | |
"Atenção circulatória", | |
"Considerar exercícios", | |
"Avaliar rotina" | |
], | |
"media": [ | |
"Circulação adequada", | |
"Manter atividade física" | |
], | |
"alta": [ | |
"Boa saúde circulatória", | |
"Manter hábitos ativos" | |
] | |
} | |
), | |
IrisZone( | |
name="Zona Linfática", | |
inner_ratio=0.25, | |
outer_ratio=0.4, | |
color=(255, 0, 255), | |
description="Sistema imunológico", | |
related_systems=["Linfonodos", "Imunidade", "Defesa"], | |
indicators={ | |
"baixa": [ | |
"Atenção imunológica", | |
"Considerar suporte", | |
"Avaliar estresse" | |
], | |
"media": [ | |
"Imunidade adequada", | |
"Manter cuidados básicos" | |
], | |
"alta": [ | |
"Boa resposta imune", | |
"Manter hábitos saudáveis" | |
] | |
} | |
), | |
IrisZone( | |
name="Zona Endócrina", | |
inner_ratio=0.15, | |
outer_ratio=0.25, | |
color=(0, 255, 255), | |
description="Sistema hormonal", | |
related_systems=["Glândulas", "Hormônios", "Metabolismo"], | |
indicators={ | |
"baixa": [ | |
"Atenção hormonal", | |
"Considerar ritmos", | |
"Avaliar rotina" | |
], | |
"media": [ | |
"Função hormonal adequada", | |
"Manter equilíbrio" | |
], | |
"alta": [ | |
"Bom equilíbrio hormonal", | |
"Manter hábitos regulares" | |
] | |
} | |
), | |
IrisZone( | |
name="Zona Pupilar", | |
inner_ratio=0, | |
outer_ratio=0.15, | |
color=(128, 128, 128), | |
description="Sistema nervoso autônomo", | |
related_systems=["SNA", "Reflexos", "Regulação"], | |
indicators={ | |
"baixa": [ | |
"Atenção autonômica", | |
"Considerar relaxamento", | |
"Avaliar estresse" | |
], | |
"media": [ | |
"Função autonômica adequada", | |
"Manter equilíbrio" | |
], | |
"alta": [ | |
"Boa regulação autonômica", | |
"Manter práticas saudáveis" | |
] | |
} | |
) | |
] | |
def preprocess_image(self, img: np.ndarray) -> np.ndarray: | |
"""Pré-processa a imagem para melhor análise""" | |
try: | |
# Converter para LAB | |
lab = cv2.cvtColor(img, cv2.COLOR_RGB2LAB) | |
l, a, b = cv2.split(lab) | |
# Aplicar CLAHE no canal L | |
clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8,8)) | |
l = clahe.apply(l) | |
# Mesclar canais | |
lab = cv2.merge((l,a,b)) | |
enhanced = cv2.cvtColor(lab, cv2.COLOR_LAB2RGB) | |
# Redução de ruído | |
denoised = cv2.fastNlMeansDenoisingColored(enhanced, None, 10, 10, 7, 21) | |
return denoised | |
except Exception as e: | |
logging.error(f"Erro no pré-processamento: {str(e)}") | |
return img | |
def detect_pupil(self, img: np.ndarray) -> Tuple[int, int, int]: | |
"""Detecta a pupila na imagem""" | |
try: | |
processed = self.preprocess_image(img) | |
gray = cv2.cvtColor(processed, cv2.COLOR_RGB2GRAY) | |
# Threshold adaptativo | |
blur = cv2.GaussianBlur(gray, (5,5), 0) | |
_, thresh = cv2.threshold(blur, 30, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) | |
# Operações morfológicas | |
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5)) | |
morph = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel) | |
# Encontrar contornos | |
contours, _ = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) | |
if not contours: | |
return None | |
# Encontrar o contorno mais circular | |
max_circularity = 0 | |
best_contour = None | |
for contour in contours: | |
area = cv2.contourArea(contour) | |
perimeter = cv2.arcLength(contour, True) | |
if perimeter == 0: | |
continue | |
circularity = 4 * np.pi * area / (perimeter * perimeter) | |
if circularity > max_circularity: | |
max_circularity = circularity | |
best_contour = contour | |
if best_contour is None: | |
return None | |
(x, y), radius = cv2.minEnclosingCircle(best_contour) | |
return (int(x), int(y), int(radius)) | |
except Exception as e: | |
logging.error(f"Erro na detecção da pupila: {str(e)}") | |
return None | |
def analyze_zone(self, img: np.ndarray, mask: np.ndarray, zone: IrisZone) -> Dict: | |
"""Analisa uma zona específica da íris""" | |
try: | |
# Extrair características | |
mean_color = cv2.mean(img, mask=mask) | |
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY) | |
zone_pixels = cv2.bitwise_and(gray, gray, mask=mask) | |
if np.sum(mask) > 0: | |
pixels = zone_pixels[mask > 0] | |
mean_intensity = np.mean(pixels) | |
std_dev = np.std(pixels) | |
# Determinar nível | |
if mean_intensity < 85: | |
nivel = "baixa" | |
elif mean_intensity < 170: | |
nivel = "media" | |
else: | |
nivel = "alta" | |
# Calcular confiança | |
confianca = "alta" if std_dev < 15 else "media" if std_dev < 30 else "baixa" | |
# Gerar análise | |
analysis = { | |
"nome": zone.name, | |
"descricao": zone.description, | |
"sistemas_relacionados": zone.related_systems, | |
"indicadores": zone.indicators[nivel], | |
"metricas": { | |
"intensidade": float(mean_intensity), | |
"variacao": float(std_dev), | |
"nivel": nivel, | |
"confianca": confianca | |
}, | |
"cores": { | |
"r": float(mean_color[0]), | |
"g": float(mean_color[1]), | |
"b": float(mean_color[2]) | |
} | |
} | |
return analysis | |
return {"erro": "Zona sem pixels válidos"} | |
except Exception as e: | |
logging.error(f"Erro na análise da zona {zone.name}: {str(e)}") | |
return {"erro": str(e)} | |
def analyze_iris(self, img: np.ndarray) -> Tuple[np.ndarray, Dict]: | |
"""Realiza a análise completa da íris""" | |
try: | |
output_img = img.copy() | |
results = { | |
"meta": { | |
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), | |
"versao": "1.0.0" | |
}, | |
"zonas": {}, | |
"resumo": {} | |
} | |
# Detectar pupila | |
pupil = self.detect_pupil(img) | |
if pupil is None: | |
return img, {"erro": "Não foi possível detectar a pupila"} | |
x, y, pupil_radius = pupil | |
iris_radius = pupil_radius * 4 | |
# Desenhar pupila | |
cv2.circle(output_img, (x, y), pupil_radius, (0, 0, 0), 2) | |
# Analisar cada zona | |
total_score = 0 | |
valid_zones = 0 | |
for zone in self.zones: | |
inner_r = int(iris_radius * zone.inner_ratio) | |
outer_r = int(iris_radius * zone.outer_ratio) | |
# Criar máscara | |
mask = np.zeros(img.shape[:2], dtype=np.uint8) | |
cv2.circle(mask, (x, y), outer_r, 255, -1) | |
cv2.circle(mask, (x, y), inner_r, 0, -1) | |
# Desenhar zona | |
cv2.circle(output_img, (x, y), outer_r, zone.color, 2) | |
# Analisar zona | |
analysis = self.analyze_zone(img, mask, zone) | |
results["zonas"][zone.name] = analysis | |
if "metricas" in analysis: | |
if analysis["metricas"]["nivel"] == "alta": | |
total_score += 1.0 | |
elif analysis["metricas"]["nivel"] == "media": | |
total_score += 0.5 | |
valid_zones += 1 | |
# Adicionar texto | |
text_x = x - iris_radius | |
text_y = y + outer_r | |
cv2.putText(output_img, zone.name, (text_x, text_y), | |
cv2.FONT_HERSHEY_SIMPLEX, 0.5, zone.color, 1) | |
# Calcular índice geral | |
if valid_zones > 0: | |
health_index = (total_score / valid_zones) * 100 | |
results["resumo"] = { | |
"indice_geral": f"{health_index:.1f}%", | |
"interpretacao": "Excelente" if health_index > 80 else | |
"Bom" if health_index > 60 else | |
"Regular" if health_index > 40 else | |
"Requer atenção" | |
} | |
return output_img, results | |
except Exception as e: | |
logging.error(f"Erro na análise da íris: {str(e)}") | |
return img, {"erro": str(e)} | |
def format_zone_report(zone_name: str, analysis: Dict) -> str: | |
"""Formata o relatório de uma zona específica""" | |
if "erro" in analysis: | |
return f"Erro na análise de {zone_name}: {analysis['erro']}" | |
report = f"""### {zone_name} | |
**Descrição:** {analysis.get('descricao', 'N/A')} | |
**Sistemas Relacionados:** | |
""" | |
for sistema in analysis.get('sistemas_relacionados', []): | |
report += f"- {sistema}\n" | |
report += "\n**Indicadores:**\n" | |
for indicador in analysis.get('indicadores', []): | |
report += f"- {indicador}\n" | |
if "metricas" in analysis: | |
report += f""" | |
**Métricas:** | |
- Nível: {analysis['metricas']['nivel'].title()} | |
- Confiança: {analysis['metricas']['confianca'].title()} | |
- Intensidade: {analysis['metricas']['intensidade']:.1f} | |
- Variação: {analysis['metricas']['variacao']:.1f} | |
""" | |
return report | |
def format_technical_metrics(analysis: Dict) -> str: | |
"""Formata as métricas técnicas de uma análise""" | |
metrics = """### Métricas Técnicas\n\n""" | |
if "metricas" in analysis: | |
metrics += f""" | |
- **Análise de Intensidade** | |
- Valor: {analysis['metricas']['intensidade']:.1f}/255 | |
- Interpretação: {analysis['metricas']['nivel'].title()} | |
- **Análise de Variação** | |
- Valor: {analysis['metricas']['variacao']:.1f} | |
- Confiança: {analysis['metricas']['confianca'].title()} | |
- **Cores (RGB)** | |
- R: {analysis['cores']['r']:.1f} | |
- G: {analysis['cores']['g']:.1f} | |
- B: {analysis['cores']['b']:.1f} | |
""" | |
return metrics | |
def process_image(img): | |
"""Processa a imagem e retorna todos os resultados formatados""" | |
if img is None: | |
return [None] * 6, gr.Warning("Por favor, carregue uma imagem.") | |
try: | |
analyzer = IrisAnalyzer() | |
output_img, results = analyzer.analyze_iris(np.array(img)) | |
if "erro" in results: | |
return [output_img] + [results["erro"]] * 5 | |
# 1. Resumo Geral | |
resumo = f"""## Resumo da Análise | |
🎯 **Índice Geral de Saúde:** {results['resumo'].get('indice_geral', 'N/A')} | |
📊 **Interpretação:** {results['resumo'].get('interpretacao', 'N/A')} | |
🕒 **Data da Análise:** {results['meta']['timestamp']} | |
---""" | |
# 2. Análise Detalhada | |
analise_detalhada = "## Análise Detalhada por Zona\n\n" | |
for zone_name, analysis in results['zonas'].items(): | |
analise_detalhada += format_zone_report(zone_name, analysis) + "\n---\n" | |
# 3. Recomendações | |
recomendacoes = "## Recomendações Personalizadas\n\n" | |
for zone_name, analysis in results['zonas'].items(): | |
if analysis.get('indicadores'): | |
recomendacoes += f"### {zone_name}\n" | |
for idx, rec in enumerate(analysis['indicadores'], 1): | |
recomendacoes += f"{idx}. {rec}\n" | |
recomendacoes += "\n" | |
# 4. Métricas Técnicas | |
metricas = "## Métricas e Indicadores\n\n" | |
for zone_name, analysis in results['zonas'].items(): | |
metricas += f"### {zone_name}\n" | |
metricas += format_technical_metrics(analysis) + "\n" | |
# 5. Observações Técnicas | |
observacoes = f"""## Informações Técnicas | |
📌 **Detalhes da Análise** | |
- Versão do Sistema: {results['meta']['versao']} | |
- Data/Hora: {results['meta']['timestamp']} | |
- Zonas Analisadas: {len(results['zonas'])} | |
⚠️ **Observações** | |
- Esta é uma análise educacional | |
- Não substitui avaliação médica | |
- Baseado na teoria de Jensen | |
""" | |
return output_img, resumo, analise_detalhada, recomendacoes, metricas, observacoes | |
except Exception as e: | |
logging.error(f"Erro no processamento: {str(e)}") | |
return [None] * 6, gr.Error(f"Erro no processamento: {str(e)}") | |
# Interface Gradio | |
with gr.Blocks(theme=gr.themes.Soft()) as iface: | |
gr.Markdown(""" | |
# 🔍 Analisador Avançado de Íris | |
## Sistema Educacional de Análise Iridológica | |
⚠️ Este é um sistema para fins educacionais. Não utilize para diagnósticos médicos. | |
""") | |
with gr.Tabs() as tabs: | |
# Aba de Análise | |
with gr.Tab("📸 Análise"): | |
with gr.Row(): | |
with gr.Column(scale=1): | |
input_image = gr.Image( | |
label="Upload da Imagem", | |
type="numpy", | |
sources=["upload", "clipboard"], | |
height=400 | |
) | |
analyze_btn = gr.Button("🔍 Analisar", variant="primary", size="lg") | |
with gr.Column(scale=1): | |
output_image = gr.Image(label="Resultado da Análise", height=400) | |
# Aba de Resultados | |
with gr.Tab("📊 Resultados"): | |
with gr.Tabs() as results_tabs: | |
with gr.Tab("📝 Resumo"): | |
resumo_text = gr.Markdown() | |
with gr.Tab("🔍 Análise Detalhada"): | |
analise_text = gr.Markdown() | |
with gr.Tab("💡 Recomendações"): | |
recomendacoes_text = gr.Markdown() | |
with gr.Tab("📈 Métricas"): | |
metricas_text = gr.Markdown() | |
with gr.Tab("ℹ️ Informações"): | |
observacoes_text = gr.Markdown() | |
# Aba de Ajuda | |
with gr.Tab("❓ Ajuda"): | |
gr.Markdown(""" | |
## Como Usar o Sistema | |
1. **Upload da Imagem** | |
- Use uma foto clara do olho | |
- Certifique-se que a íris está visível | |
- Evite reflexos e sombras | |
2. **Análise** | |
- Clique em "Analisar" | |
- Aguarde o processamento | |
- Revise os resultados nas abas | |
3. **Interpretação** | |
- Resumo: visão geral | |
- Análise: detalhes por zona | |
- Recomendações: sugestões | |
- Métricas: dados técnicos | |
## Zonas Analisadas | |
1. 🧠 **Zona Cerebral/Neural** | |
- Sistema nervoso | |
2. 🟢 **Zona Digestiva** | |
- Sistema digestivo | |
3. 🫁 **Zona Respiratória** | |
- Sistema respiratório | |
4. ❤️ **Zona Circulatória** | |
- Sistema cardiovascular | |
5. 🔵 **Zona Linfática** | |
- Sistema imunológico | |
6. 🟣 **Zona Endócrina** | |
- Sistema hormonal | |
7. ⚫ **Zona Pupilar** | |
- Sistema nervoso autônomo | |
## Observações | |
- Sistema educacional | |
- Não substitui diagnósticos | |
- Consulte profissionais de saúde | |
""") | |
# Configurar eventos | |
analyze_btn.click( | |
fn=process_image, | |
inputs=input_image, | |
outputs=[ | |
output_image, | |
resumo_text, | |
analise_text, | |
recomendacoes_text, | |
metricas_text, | |
observacoes_text | |
] | |
) | |
if __name__ == "__main__": | |
try: | |
iface.launch() | |
logging.info("Aplicação iniciada com sucesso") | |
except Exception as e: | |
logging.error(f"Erro ao iniciar a aplicação: {str(e)}") | |
raise |