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 torch.nn.functional as F | |
import torchvision.transforms as transforms | |
import logging | |
from datetime import datetime | |
import json | |
# Configuração básica de logging | |
logging.basicConfig( | |
level=logging.INFO, | |
format='%(asctime)s - %(levelname)s - %(message)s' | |
) | |
class IrisZone: | |
"""Classe para definir as características de uma zona da íris""" | |
name: str | |
inner_ratio: float | |
outer_ratio: float | |
color: Tuple[int, int, int] | |
description: str | |
indicators: Dict[str, str] | |
def __post_init__(self): | |
if not 0 <= self.inner_ratio <= 1: | |
raise ValueError("inner_ratio deve estar entre 0 e 1") | |
if not 0 <= self.outer_ratio <= 1: | |
raise ValueError("outer_ratio deve estar entre 0 e 1") | |
if self.inner_ratio >= self.outer_ratio: | |
raise ValueError("inner_ratio deve ser menor que outer_ratio") | |
class IrisAnalysis: | |
"""Classe para análise e interpretação dos resultados""" | |
def get_zone_interpretation(zone_name: str, intensity: float, variation: float) -> Dict: | |
"""Interpretação detalhada para cada zona""" | |
base_interpretations = { | |
"Zona Cerebral/Neural": { | |
"aspectos": "Sistema nervoso central e periférico", | |
"sistemas": ["Cérebro", "Medula espinhal", "Nervos"], | |
"baixa": { | |
"indicacao": "Possível fadiga neural", | |
"sugestoes": [ | |
"Considerar avaliação do sono", | |
"Verificar níveis de estresse", | |
"Avaliar demanda cognitiva" | |
] | |
}, | |
"média": { | |
"indicacao": "Condição neural moderada", | |
"sugestoes": [ | |
"Manter boa higiene do sono", | |
"Praticar atividades mentais" | |
] | |
}, | |
"alta": { | |
"indicacao": "Boa vitalidade neural", | |
"sugestoes": [ | |
"Manter práticas saudáveis", | |
"Continuar estimulação cognitiva" | |
] | |
} | |
}, | |
"Zona Digestiva": { | |
"aspectos": "Sistema digestivo completo", | |
"sistemas": ["Estômago", "Intestinos", "Fígado", "Pâncreas"], | |
"baixa": { | |
"indicacao": "Possível sensibilidade digestiva", | |
"sugestoes": [ | |
"Avaliar hábitos alimentares", | |
"Considerar diário alimentar", | |
"Observar reações a alimentos" | |
] | |
}, | |
"média": { | |
"indicacao": "Sistema digestivo em equilíbrio moderado", | |
"sugestoes": [ | |
"Manter alimentação balanceada", | |
"Observar horários das refeições" | |
] | |
}, | |
"alta": { | |
"indicacao": "Boa condição digestiva", | |
"sugestoes": [ | |
"Manter dieta equilibrada", | |
"Continuar bons hábitos" | |
] | |
} | |
}, | |
# [Definições similares para outras zonas...] | |
} | |
# Determinar nível baseado na intensidade | |
if intensity < 85: | |
nivel = "baixa" | |
confianca = "reduzida" if variation > 30 else "moderada" | |
elif intensity < 170: | |
nivel = "média" | |
confianca = "moderada" if variation > 20 else "alta" | |
else: | |
nivel = "alta" | |
confianca = "alta" if variation < 15 else "moderada" | |
zone_info = base_interpretations.get(zone_name, {}) | |
return { | |
"nome": zone_name, | |
"aspectos_analisados": zone_info.get("aspectos", ""), | |
"sistemas_relacionados": zone_info.get("sistemas", []), | |
"interpretacao": zone_info.get(nivel, {}).get("indicacao", "Sem interpretação disponível"), | |
"sugestoes": zone_info.get(nivel, {}).get("sugestoes", []), | |
"metricas": { | |
"intensidade": intensity, | |
"variacao": variation, | |
"nivel_geral": nivel, | |
"confianca_analise": confianca, | |
}, | |
"indicadores": { | |
"intensidade_valor": f"{intensity:.1f}/255", | |
"variacao_valor": f"{variation:.1f}%", | |
"homogeneidade": "Baixa" if variation > 30 else "Média" if variation > 15 else "Alta" | |
} | |
} | |
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", | |
indicators={"estresse": "alto", "energia": "moderada"} | |
), | |
# [Outras zonas definidas similarmente...] | |
] | |
def preprocess_image(self, img: np.ndarray) -> np.ndarray: | |
"""Pré-processamento da imagem""" | |
try: | |
# Converter para LAB para melhor contraste | |
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]: | |
"""Detecção avançada da pupila""" | |
try: | |
# Pré-processar imagem | |
processed = self.preprocess_image(img) | |
gray = cv2.cvtColor(processed, cv2.COLOR_RGB2GRAY) | |
# Aplicar 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 | |
best_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 > best_circularity: | |
best_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_name: str) -> Dict: | |
"""Análise detalhada de uma zona específica""" | |
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) | |
# Calcular características adicionais | |
percentiles = np.percentile(pixels, [25, 50, 75]) | |
# Gerar interpretação detalhada | |
analysis = IrisAnalysis.get_zone_interpretation( | |
zone_name, mean_intensity, std_dev | |
) | |
# Adicionar métricas estatísticas | |
analysis["metricas_detalhadas"] = { | |
"mediana": float(percentiles[1]), | |
"quartil_inferior": float(percentiles[0]), | |
"quartil_superior": float(percentiles[2]), | |
"pixels_analisados": len(pixels), | |
"variacao_cor": { | |
"r": mean_color[0], | |
"g": mean_color[1], | |
"b": mean_color[2] | |
} | |
} | |
return analysis | |
return {"erro": "Zona sem pixels válidos para análise"} | |
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]: | |
"""Análise principal com relatório detalhado""" | |
try: | |
output_img = img.copy() | |
detailed_results = { | |
"meta": { | |
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), | |
"versao_analise": "1.0.0" | |
}, | |
"resumo_geral": {}, | |
"zonas": {}, | |
"observacoes": [] | |
} | |
# 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 círculo da pupila | |
cv2.circle(output_img, (x, y), pupil_radius, (0, 0, 0), 2) | |
# Analisar cada zona | |
overall_health_score = 0 | |
num_zones = len(self.zones) | |
for zone in self.zones: | |
inner_r = int(iris_radius * zone.inner_ratio) | |
outer_r = int(iris_radius * zone.outer_ratio) | |
# Criar máscara para a zona | |
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 círculos da zona | |
cv2.circle(output_img, (x, y), outer_r, zone.color, 2) | |
# Analisar zona | |
analysis = self.analyze_zone(img, mask, zone.name) | |
detailed_results["zonas"][zone.name] = analysis | |
# Calcular score geral | |
if "metricas" in analysis: | |
if analysis["metricas"]["nivel_geral"] == "alta": | |
overall_health_score += 1 | |
elif analysis["metricas"]["nivel_geral"] == "média": | |
overall_health_score += 0.5 | |
# 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 resumo geral | |
health_percentage = (overall_health_score / num_zones) * 100 | |
detailed_results["resumo_geral"] = { | |
"indice_geral": f"{health_percentage:.1f}%", | |
"interpretacao": "Bom" if health_percentage > 75 else | |
"Moderado" if health_percentage > 50 else | |
"Requer atenção" | |
} | |
return output_img, detailed_results | |
except Exception as e: | |
logging.error(f"Erro na análise da íris: {str(e)}") | |
return img, {"erro": str(e)} | |
def format_results(results: Dict) -> str: | |
"""Formata os resultados para exibição""" | |
if "erro" in results: | |
return f"Erro na análise: {results['erro']}" | |
formatted = "# Relatório de Análise da Íris\n\n" | |
# Adicionar resumo geral | |
if "resumo_geral" in results: | |
formatted += "## Resumo Geral\n" | |
formatted += f"- Índice Geral: {results['resumo_geral']['indice_geral']}\n" | |
formatted += f"- Interpretação: {results['resumo_geral']['interpretacao']}\n\n" | |
# Adicionar análise por zona | |
if "zonas" in results: | |
formatted += "## Análise por Zona\n\n" | |
for zone_name, analysis in results["zonas"].items(): | |
formatted += f"### {zone_name}\n" | |
formatted += f"- Aspectos Analisados: {analysis.get('aspectos_analisados', 'N/A')}\n" | |
formatted += f"- Interpretação: {analysis.get('interpretacao', 'N/A')}\n" | |
if "sugestoes" in analysis: | |
formatted += "- Sugestões:\n" | |
for sugestao in analysis["sugestoes"]: | |
formatted += f" * {sugestao}\n" | |
if "metricas" in analysis: | |
formatted += f"- Nível Geral: {analysis['metricas']['nivel_geral']}\n" | |
formatted += f"- Confiança da Análise: {analysis['metricas']['confianca_analise']}\n" | |
formatted += "\n" | |
# Adicionar timestamp | |
if "meta" in results: | |
formatted += f"\n---\nAnálise realizada em: {results['meta']['timestamp']}\n" | |
formatted += f"Versão do sistema: {results['meta']['versao_analise']}\n" | |
return formatted | |
def process_image(img): | |
"""Função principal para processar imagem""" | |
if img is None: | |
return None, "Erro: Nenhuma imagem fornecida" | |
analyzer = IrisAnalyzer() | |
output_img, results = analyzer.analyze_iris(np.array(img)) | |
formatted_results = format_results(results) | |
return output_img, formatted_results | |
# Interface Gradio | |
with gr.Blocks(theme=gr.themes.Soft()) as iface: | |
gr.Markdown(""" | |
# 🔍 Analisador Avançado de Íris | |
### Sistema de análise baseado na teoria de Jensen | |
⚠️ **AVISO**: Esta é uma demonstração educacional. Não deve ser utilizada para diagnósticos médicos. | |
""") | |
with gr.Row(): | |
with gr.Column(scale=1): | |
input_image = gr.Image( | |
label="Upload da imagem do olho", | |
type="numpy", | |
sources=["upload", "clipboard"] | |
) | |
analyze_btn = gr.Button( | |
"📸 Analisar Imagem", | |
variant="primary" | |
) | |
gr.Markdown(""" | |
### Instruções: | |
1. Faça upload de uma imagem clara do olho | |
2. Certifique-se que a íris está bem visível | |
3. Clique em "Analisar Imagem" | |
4. Revise o relatório detalhado | |
""") | |
with gr.Column(scale=1): | |
output_image = gr.Image(label="Análise Visual") | |
results_text = gr.Markdown(label="Relatório Detalhado") | |
with gr.Row(): | |
gr.Markdown(""" | |
### Legenda das Zonas: | |
- 🔴 Zona Cerebral/Neural: Sistema nervoso | |
- 🟢 Zona Digestiva: Sistema digestivo | |
- 🔵 Zona Respiratória: Sistema respiratório | |
- 🟡 Zona Circulatória: Sistema circulatório | |
- 🟣 Zona Linfática: Sistema linfático | |
- 🔰 Zona Endócrina: Sistema hormonal | |
- ⚪ Zona Pupilar: Sistema nervoso autônomo | |
""") | |
analyze_btn.click( | |
fn=process_image, | |
inputs=input_image, | |
outputs=[output_image, results_text] | |
) | |
gr.Markdown(""" | |
--- | |
### 📋 Sobre a Análise | |
Este sistema realiza: | |
- Detecção automática da pupila | |
- Análise de 7 zonas principais da íris | |
- Avaliação de padrões e texturas | |
- Geração de relatório detalhado | |
**Observações Importantes:** | |
- A iridologia é uma prática alternativa | |
- Os resultados são interpretativos | |
- Consulte profissionais de saúde para diagnósticos | |
--- | |
""") | |
# Configurações para execução | |
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 |