Spaces:
Sleeping
Sleeping
import gradio as gr | |
import cv2 | |
import numpy as np | |
from dataclasses import dataclass | |
from typing import Dict, List, Tuple, Optional | |
from datetime import datetime | |
class IrisZone: | |
name: str | |
ratio: Tuple[float, float] # (inner, outer) | |
color: Tuple[int, int, int] | |
conditions: Dict[str, List[str]] | |
recommendations: Dict[str, List[str]] | |
class IrisAnalyzer: | |
def __init__(self): | |
self.zones = [ | |
IrisZone( | |
name="Zona Cerebral/Neural", | |
ratio=(0.85, 1.0), | |
color=(255, 0, 0), | |
conditions={ | |
"baixa": [ | |
"Possível fadiga neural crônica", | |
"Indicadores de estresse prolongado", | |
"Sinais de insônia ou distúrbios do sono", | |
"Possível déficit de vitamina B12" | |
], | |
"media": ["Estado neural estável", "Função cognitiva normal"], | |
"alta": ["Excelente saúde neural", "Ótima resposta cognitiva"] | |
}, | |
recommendations={ | |
"baixa": [ | |
"Suplementação de vitamina B12", | |
"Técnicas de meditação diária", | |
"Melhorar qualidade do sono", | |
"Reduzir exposição a telas" | |
], | |
"media": ["Manter rotina de sono", "Exercícios mentais regulares"], | |
"alta": ["Manter práticas atuais", "Exercícios de mindfulness"] | |
} | |
), | |
IrisZone( | |
name="Zona Digestiva", | |
ratio=(0.7, 0.85), | |
color=(0, 255, 0), | |
conditions={ | |
"baixa": [ | |
"Possível inflamação intestinal", | |
"Sinais de má absorção", | |
"Indicadores de disbiose", | |
"Possível deficiência enzimática" | |
], | |
"media": ["Digestão funcional", "Absorção adequada"], | |
"alta": ["Excelente saúde digestiva", "Ótima absorção"] | |
}, | |
recommendations={ | |
"baixa": [ | |
"Probióticos específicos", | |
"Enzimas digestivas", | |
"Dieta anti-inflamatória", | |
"Eliminar alimentos processados" | |
], | |
"media": ["Manter dieta balanceada", "Hidratação adequada"], | |
"alta": ["Manter dieta atual", "Rotina alimentar saudável"] | |
} | |
), | |
IrisZone( | |
name="Zona Respiratória", | |
ratio=(0.55, 0.7), | |
color=(0, 0, 255), | |
conditions={ | |
"baixa": [ | |
"Possível comprometimento respiratório", | |
"Sinais de baixa oxigenação", | |
"Indicadores de congestão brônquica", | |
"Possível sensibilidade respiratória" | |
], | |
"media": ["Função respiratória adequada", "Oxigenação normal"], | |
"alta": ["Excelente capacidade respiratória", "Ótima oxigenação"] | |
}, | |
recommendations={ | |
"baixa": [ | |
"Exercícios respiratórios diários", | |
"Avaliar qualidade do ar", | |
"Considerar atividades aeróbicas", | |
"Técnicas de respiração profunda" | |
], | |
"media": ["Manter exercícios regulares", "Praticar respiração consciente"], | |
"alta": ["Continuar práticas saudáveis", "Manter atividades aeróbicas"] | |
} | |
), | |
IrisZone( | |
name="Zona Circulatória", | |
ratio=(0.4, 0.55), | |
color=(255, 255, 0), | |
conditions={ | |
"baixa": [ | |
"Possível circulação periférica reduzida", | |
"Indicadores de estagnação sanguínea", | |
"Sinais de baixo fluxo sanguíneo", | |
"Possível deficiência de ferro" | |
], | |
"media": ["Circulação adequada", "Fluxo sanguíneo normal"], | |
"alta": ["Excelente circulação", "Ótimo fluxo sanguíneo"] | |
}, | |
recommendations={ | |
"baixa": [ | |
"Aumentar atividade física", | |
"Considerar suplementação de ferro", | |
"Massagens circulatórias", | |
"Hidratação adequada" | |
], | |
"media": ["Manter exercícios regulares", "Alimentação rica em ferro"], | |
"alta": ["Manter rotina atual", "Continuar exercícios"] | |
} | |
), | |
IrisZone( | |
name="Zona Linfática", | |
ratio=(0.25, 0.4), | |
color=(255, 0, 255), | |
conditions={ | |
"baixa": [ | |
"Sistema linfático congestionado", | |
"Possível retenção de líquidos", | |
"Indicadores de toxicidade", | |
"Baixa resposta imunológica" | |
], | |
"media": ["Sistema linfático funcional", "Drenagem adequada"], | |
"alta": ["Excelente drenagem linfática", "Ótima desintoxicação"] | |
}, | |
recommendations={ | |
"baixa": [ | |
"Drenagem linfática regular", | |
"Aumentar consumo de água", | |
"Exercícios específicos", | |
"Dieta desintoxicante" | |
], | |
"media": ["Manter hidratação", "Exercícios leves regulares"], | |
"alta": ["Manter hábitos atuais", "Continuar atividades físicas"] | |
} | |
), | |
IrisZone( | |
name="Zona Endócrina", | |
ratio=(0.15, 0.25), | |
color=(0, 255, 255), | |
conditions={ | |
"baixa": [ | |
"Possível desequilíbrio hormonal", | |
"Sinais de estresse adrenal", | |
"Indicadores de fadiga endócrina", | |
"Possível disfunção tireoidiana" | |
], | |
"media": ["Sistema endócrino estável", "Função hormonal adequada"], | |
"alta": ["Excelente equilíbrio hormonal", "Ótima função endócrina"] | |
}, | |
recommendations={ | |
"baixa": [ | |
"Gestão do estresse", | |
"Suporte adrenal natural", | |
"Regular ciclo sono-vigília", | |
"Alimentação rica em iodo" | |
], | |
"media": ["Manter rotina regular", "Cuidar do sono"], | |
"alta": ["Manter equilíbrio atual", "Continuar boas práticas"] | |
} | |
), | |
IrisZone( | |
name="Zona Pupilar", | |
ratio=(0, 0.15), | |
color=(128, 128, 128), | |
conditions={ | |
"baixa": [ | |
"Sistema nervoso autônomo sobrecarregado", | |
"Possível desequilíbrio simpático/parassimpático", | |
"Indicadores de estresse crônico", | |
"Sinais de fadiga autonômica" | |
], | |
"media": ["SNA equilibrado", "Resposta autonômica normal"], | |
"alta": ["Excelente regulação autonômica", "Ótimo equilíbrio do SNA"] | |
}, | |
recommendations={ | |
"baixa": [ | |
"Técnicas de relaxamento", | |
"Práticas de mindfulness", | |
"Regular rotina diária", | |
"Exercícios de respiração" | |
], | |
"media": ["Manter práticas relaxantes", "Continuar boa rotina"], | |
"alta": ["Manter equilíbrio atual", "Continuar práticas saudáveis"] | |
} | |
) | |
] | |
def _assess_image_quality(self, image: np.ndarray) -> float: | |
"""Assess image quality with better error handling.""" | |
try: | |
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) | |
blur_score = cv2.Laplacian(gray, cv2.CV_64F).var() | |
brightness = np.mean(gray) | |
contrast = np.std(gray) | |
quality_score = ( | |
np.clip(blur_score / 500, 0, 1) * 0.4 + | |
np.clip(1 - abs(brightness - 128) / 128, 0, 1) * 0.3 + | |
np.clip(contrast / 50, 0, 1) * 0.3 | |
) * 100 | |
return float(quality_score) | |
except Exception as e: | |
print(f"Error in image quality assessment: {str(e)}") | |
return 0.0 | |
def _analyze_texture(self, gray: np.ndarray, mask: np.ndarray) -> float: | |
"""Analyze texture with improved error handling and normalization.""" | |
try: | |
if mask is None or np.sum(mask) == 0: | |
return 0.0 | |
zone_pixels = cv2.bitwise_and(gray, gray, mask=mask) | |
valid_pixels = zone_pixels[mask > 0] | |
if len(valid_pixels) == 0: | |
return 0.0 | |
mean = np.mean(valid_pixels) | |
std = np.std(valid_pixels) | |
entropy = np.sum(np.abs(np.diff(valid_pixels))) | |
texture_score = ( | |
np.clip(mean / 255, 0, 1) * 0.3 + | |
np.clip(std / 128, 0, 1) * 0.3 + | |
np.clip(entropy / 1000, 0, 1) * 0.4 | |
) * 100 | |
return float(texture_score) | |
except Exception as e: | |
print(f"Error in texture analysis: {str(e)}") | |
return 0.0 | |
def _analyze_contrast(self, l_channel: np.ndarray, mask: np.ndarray) -> float: | |
"""Analyze contrast with improved error handling.""" | |
try: | |
if mask is None or np.sum(mask) == 0: | |
return 0.0 | |
zone_pixels = l_channel[mask > 0] | |
if len(zone_pixels) == 0: | |
return 0.0 | |
p5 = np.percentile(zone_pixels, 5) | |
p95 = np.percentile(zone_pixels, 95) | |
contrast_score = np.clip((p95 - p5) / 255, 0, 1) * 100 | |
return float(contrast_score) | |
except Exception as e: | |
print(f"Error in contrast analysis: {str(e)}") | |
return 0.0 | |
def _detect_patterns(self, gray: np.ndarray, mask: np.ndarray) -> float: | |
"""Detect patterns with improved error handling.""" | |
try: | |
if mask is None or np.sum(mask) == 0: | |
return 0.0 | |
sobelx = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=3) | |
sobely = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=3) | |
gradient = np.sqrt(sobelx**2 + sobely**2) | |
zone_gradient = gradient[mask > 0] | |
if len(zone_gradient) == 0 or np.max(gradient) == 0: | |
return 0.0 | |
pattern_score = np.clip((np.mean(zone_gradient) / np.max(gradient)), 0, 1) * 100 | |
return float(pattern_score) | |
except Exception as e: | |
print(f"Error in pattern detection: {str(e)}") | |
return 0.0 | |
def _customize_conditions(self, base_conditions: List[str], metrics: Dict) -> List[str]: | |
"""Customize conditions based on metrics.""" | |
customized = [] | |
for condition in base_conditions: | |
if metrics["intensity"] < 50: | |
condition += " (intensidade muito baixa)" | |
elif metrics["contrast"] < 30: | |
condition += " (baixo contraste)" | |
if metrics["patterns"] > 70: | |
condition += " (padrões significativos detectados)" | |
customized.append(condition) | |
return customized | |
def _customize_recommendations(self, base_recommendations: List[str], metrics: Dict) -> List[str]: | |
"""Customize recommendations based on metrics.""" | |
customized = [] | |
for rec in base_recommendations: | |
if metrics["texture"] < 40: | |
rec += " (prioridade alta)" | |
elif metrics["saturation"] < 50: | |
rec += " (atenção especial necessária)" | |
customized.append(rec) | |
return customized | |
def _calculate_confidence(self, metrics: Dict) -> str: | |
"""Calculate analysis confidence level.""" | |
confidence_score = ( | |
metrics["intensity"] * 0.25 + | |
metrics["contrast"] * 0.25 + | |
metrics["texture"] * 0.25 + | |
metrics["patterns"] * 0.25 | |
) | |
if confidence_score > 75: | |
return "alta" | |
elif confidence_score > 50: | |
return "média" | |
else: | |
return "baixa" | |
def analyze_iris(self, image: np.ndarray) -> Tuple[np.ndarray, Dict]: | |
"""Main analysis function with improved error handling and image processing.""" | |
try: | |
# Convert BGR to RGB if needed | |
if len(image.shape) == 2: | |
image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR) | |
elif image.shape[2] == 4: | |
image = cv2.cvtColor(image, cv2.COLOR_BGRA2BGR) | |
# Create copies for different color spaces | |
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) | |
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) | |
lab = cv2.cvtColor(image, cv2.COLOR_BGR2LAB) | |
# Improve circle detection | |
circles = cv2.HoughCircles( | |
gray, | |
cv2.HOUGH_GRADIENT, | |
dp=1, | |
minDist=max(gray.shape[0], gray.shape[1]), # Only detect one circle | |
param1=50, | |
param2=30, | |
minRadius=min(gray.shape) // 6, | |
maxRadius=min(gray.shape) // 2 | |
) | |
if circles is not None: | |
circles = np.uint16(np.around(circles)) | |
circle = circles[0][0] | |
center = (int(circle[0]), int(circle[1])) | |
radius = int(circle[2]) | |
else: | |
# Fallback to image center if no circle is detected | |
center = (image.shape[1] // 2, image.shape[0] // 2) | |
radius = min(image.shape[:2]) // 4 | |
results = { | |
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), | |
"analysis": {}, | |
"metrics": { | |
"iris_radius": radius, | |
"image_quality": self._assess_image_quality(image) | |
} | |
} | |
# Analysis for each zone | |
for zone in self.zones: | |
inner_r = int(radius * zone.ratio[0]) | |
outer_r = int(radius * zone.ratio[1]) | |
# Create zone mask | |
mask = np.zeros(gray.shape, dtype=np.uint8) | |
cv2.circle(mask, center, outer_r, 255, -1) | |
cv2.circle(mask, center, inner_r, 0, -1) | |
# Calculate metrics | |
zone_metrics = { | |
"intensity": float(cv2.mean(gray, mask=mask)[0]), | |
"saturation": float(cv2.mean(hsv[..., 1], mask=mask)[0]), | |
"texture": self._analyze_texture(gray, mask), | |
"contrast": self._analyze_contrast(lab[..., 0], mask), | |
"patterns": self._detect_patterns(gray, mask) | |
} | |
# Calculate health score | |
health_score = ( | |
zone_metrics["intensity"] * 0.3 + | |
zone_metrics["saturation"] * 0.2 + | |
zone_metrics["texture"] * 0.2 + | |
zone_metrics["contrast"] * 0.15 + | |
zone_metrics["patterns"] * 0.15 | |
) | |
# Determine health level | |
level = "baixa" if health_score < 40 else ("media" if health_score < 75 else "alta") | |
# Store results | |
results["analysis"][zone.name] = { | |
"conditions": self._customize_conditions(zone.conditions[level], zone_metrics), | |
"recommendations": self._customize_recommendations(zone.recommendations[level], zone_metrics), | |
"metrics": {k: float(v) for k, v in zone_metrics.items()}, | |
"health_score": float(health_score), | |
"status": level, | |
"confianca_analise": self._calculate_confidence(zone_metrics) | |
} | |
# Draw zone visualization | |
cv2.circle(image, center, outer_r, zone.color, 2) | |
cv2.putText( | |
image, | |
zone.name, | |
(center[0] - outer_r, center[1] + outer_r), | |
cv2.FONT_HERSHEY_SIMPLEX, | |
0.5, | |
zone.color, | |
1, | |
cv2.LINE_AA | |
) | |
return image, results | |
except Exception as e: | |
print(f"Error in iris analysis: {str(e)}") | |
return image, {"error": str(e)} | |
def process_image(img: Optional[np.ndarray]) -> Tuple[Optional[np.ndarray], str, str, str, str]: | |
"""Process image with improved error handling and input validation.""" | |
if img is None: | |
return None, "⚠️ Por favor, carregue uma imagem.", "", "", "" | |
try: | |
analyzer = IrisAnalyzer() | |
processed_img, results = analyzer.analyze_iris(img) | |
if "error" in results: | |
return None, f"⚠️ Erro na análise: {results['error']}", "", "", "" | |
# Generate reports | |
general_report = "# 📊 Visão Geral da Análise\n\n" | |
status_counts = {"baixa": 0, "media": 0, "alta": 0} | |
for analysis in results["analysis"].values(): | |
status_counts[analysis["status"]] += 1 | |
health_score = ( | |
(status_counts["alta"] * 100 + status_counts["media"] * 50) / | |
max(1, len(results["analysis"])) | |
) | |
general_report += ( | |
f"**Índice de Saúde Geral:** {health_score:.1f}%\n\n" | |
f"**Data da Análise:** {results['timestamp']}\n\n" | |
f"**Qualidade da Imagem:** {results['metrics']['image_quality']:.1f}%\n\n" | |
) | |
# Detailed reports | |
detailed_conditions = "# 🔍 Análise Detalhada por Zona\n\n" | |
recommendations = "# 💡 Recomendações Personalizadas\n\n" | |
health_alerts = "# ⚠️ Alertas e Atenção Especial\n\n" | |
for zone_name, analysis in results["analysis"].items(): | |
# Add detailed conditions | |
detailed_conditions += f"## {zone_name}\n\n" | |
detailed_conditions += "### Condições Identificadas:\n" | |
for condition in analysis["conditions"]: | |
detailed_conditions += f"- {condition}\n" | |
detailed_conditions += ( | |
f"\n**Status:** {analysis['status'].title()}\n" | |
f"**Confiança da Análise:** {analysis['confianca_analise']}\n" | |
"**Métricas Detalhadas:**\n" | |
) | |
for metric, value in analysis["metrics"].items(): | |
detailed_conditions += f"- {metric.replace('_', ' ').title()}: {value:.1f}\n" | |
detailed_conditions += "\n" | |
# Add recommendations | |
recommendations += f"## {zone_name}\n\n" | |
for rec in analysis["recommendations"]: | |
recommendations += f"- {rec}\n" | |
recommendations += "\n" | |
# Add health alerts | |
if analysis["status"] == "baixa" or analysis["metrics"]["health_score"] < 50: | |
health_alerts += f"## {zone_name}\n" | |
health_alerts += "### Pontos de Atenção:\n" | |
for condition in analysis["conditions"]: | |
health_alerts += f"- ⚠️ {condition}\n" | |
health_alerts += "\n### Ações Recomendadas:\n" | |
for rec in analysis["recommendations"]: | |
health_alerts += f"- ✅ {rec}\n" | |
health_alerts += "\n" | |
return processed_img, general_report, detailed_conditions, recommendations, health_alerts | |
except Exception as e: | |
error_message = f"⚠️ Erro no processamento: {str(e)}" | |
return None, error_message, "", "", "" | |
# Gradio Interface | |
with gr.Blocks(theme=gr.themes.Soft()) as iface: | |
gr.Markdown(""" | |
# 🔍 Analisador Avançado de Íris | |
### Sistema Educacional de Análise Iridológica v2.0 | |
⚠️ Este é um sistema para fins educacionais. Não utilize para diagnósticos médicos. | |
""") | |
with gr.Tabs() as tabs: | |
with gr.Tab("📸 Análise de Imagem"): | |
with gr.Row(): | |
with gr.Column(scale=1): | |
input_image = gr.Image( | |
label="Upload da Imagem da Íris", | |
type="numpy", | |
sources=["upload", "webcam", "clipboard"], | |
height=400 | |
) | |
analyze_btn = gr.Button("🔍 Analisar Íris", variant="primary", size="lg") | |
with gr.Column(scale=1): | |
output_image = gr.Image(label="Visualização da Análise", height=400) | |
with gr.Tab("📊 Resultados"): | |
with gr.Tabs() as result_tabs: | |
with gr.Tab("📈 Visão Geral"): | |
general_output = gr.Markdown() | |
with gr.Tab("🔍 Condições Detalhadas"): | |
conditions_output = gr.Markdown() | |
with gr.Tab("💡 Recomendações"): | |
recommendations_output = gr.Markdown() | |
with gr.Tab("⚠️ Alertas"): | |
alerts_output = gr.Markdown() | |
with gr.Tab("ℹ️ Informações"): | |
gr.Markdown(""" | |
## 📚 Sobre a Análise Iridológica | |
### 🎯 Zonas Analisadas: | |
1. **Zona Cerebral/Neural** - Sistema nervoso central e periférico | |
2. **Zona Digestiva** - Sistema digestório completo | |
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 | |
### 📋 Como Usar: | |
1. Faça upload de uma imagem clara da íris | |
2. Clique em "Analisar Íris" | |
3. Verifique os resultados nas diferentes abas | |
4. Consulte os alertas e recomendações | |
### 🔍 Interpretação dos Resultados: | |
- **Visão Geral**: Índice geral de saúde e qualidade da análise | |
- **Condições**: Análise detalhada por zona | |
- **Recomendações**: Sugestões personalizadas | |
- **Alertas**: Pontos que requerem atenção especial | |
### ⚠️ Observações Importantes: | |
- Sistema para fins educacionais | |
- Não substitui avaliação médica | |
- Consulte profissionais de saúde | |
- Mantenha check-ups regulares | |
""") | |
# Event handlers | |
analyze_btn.click( | |
fn=process_image, | |
inputs=input_image, | |
outputs=[ | |
output_image, | |
general_output, | |
conditions_output, | |
recommendations_output, | |
alerts_output | |
] | |
) | |
if __name__ == "__main__": | |
iface.launch() |