Spaces:
Sleeping
Sleeping
import gradio as gr | |
import cv2 | |
import numpy as np | |
from PIL import Image | |
import io | |
from collections import defaultdict | |
from scipy import ndimage | |
def pre_processar_imagem(imagem): | |
""" | |
Pré-processamento avançado da imagem | |
""" | |
# Converter para LAB para melhor separação de cores | |
lab = cv2.cvtColor(imagem, 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) | |
# Recombinar canais | |
lab = cv2.merge((l,a,b)) | |
# Converter de volta para RGB | |
imagem_melhorada = cv2.cvtColor(lab, cv2.COLOR_LAB2RGB) | |
# Redução de ruído | |
imagem_melhorada = cv2.GaussianBlur(imagem_melhorada, (5, 5), 0) | |
return imagem_melhorada | |
def detectar_esclera(imagem): | |
""" | |
Detecta a região da esclera usando segmentação por cor e morfologia | |
""" | |
# Converter para HSV | |
hsv = cv2.cvtColor(imagem, cv2.COLOR_RGB2HSV) | |
# Definir faixa de cor para branco (esclera) | |
lower_white = np.array([0, 0, 180]) | |
upper_white = np.array([180, 30, 255]) | |
# Criar máscara | |
mask_esclera = cv2.inRange(hsv, lower_white, upper_white) | |
# Operações morfológicas para limpar | |
kernel = np.ones((5,5), np.uint8) | |
mask_esclera = cv2.morphologyEx(mask_esclera, cv2.MORPH_OPEN, kernel) | |
mask_esclera = cv2.morphologyEx(mask_esclera, cv2.MORPH_CLOSE, kernel) | |
return mask_esclera | |
def detectar_iris_pupila(imagem, mask_esclera): | |
""" | |
Detecta íris e pupila usando múltiplas técnicas | |
""" | |
# Converter para escala de cinza | |
gray = cv2.cvtColor(imagem, cv2.COLOR_RGB2GRAY) | |
# Aplicar máscara da esclera invertida | |
mask_olho = cv2.bitwise_not(mask_esclera) | |
eye_region = cv2.bitwise_and(gray, gray, mask=mask_olho) | |
# Detectar bordas | |
edges = cv2.Canny(eye_region, 30, 60) | |
# Detectar círculos para íris | |
iris_circles = cv2.HoughCircles( | |
edges, | |
cv2.HOUGH_GRADIENT, | |
dp=1, | |
minDist=100, | |
param1=50, | |
param2=30, | |
minRadius=80, | |
maxRadius=150 | |
) | |
# Criar máscara da íris | |
if iris_circles is not None: | |
iris_circles = np.uint16(np.around(iris_circles)) | |
ix, iy, ir = iris_circles[0][0] | |
mask_iris = np.zeros_like(gray) | |
cv2.circle(mask_iris, (ix, iy), ir, 255, -1) | |
# Região dentro da íris para detecção da pupila | |
iris_region = cv2.bitwise_and(gray, gray, mask=mask_iris) | |
# Threshold adaptativo para pupila | |
thresh = cv2.adaptiveThreshold( | |
iris_region, | |
255, | |
cv2.ADAPTIVE_THRESH_GAUSSIAN_C, | |
cv2.THRESH_BINARY_INV, | |
11, | |
2 | |
) | |
# Detectar pupila | |
pupil_circles = cv2.HoughCircles( | |
thresh, | |
cv2.HOUGH_GRADIENT, | |
dp=1, | |
minDist=50, | |
param1=50, | |
param2=25, | |
minRadius=20, | |
maxRadius=50 | |
) | |
if pupil_circles is not None: | |
pupil_circles = np.uint16(np.around(pupil_circles)) | |
px, py, pr = pupil_circles[0][0] | |
return (ix, iy, ir), (px, py, pr) | |
return None, None | |
def analisar_textura_setorial(imagem, iris_info, pupil_info): | |
""" | |
Analisa a textura da íris por setores | |
""" | |
if iris_info is None or pupil_info is None: | |
return {} | |
ix, iy, ir = iris_info | |
px, py, pr = pupil_info | |
# Converter para escala de cinza | |
gray = cv2.cvtColor(imagem, cv2.COLOR_RGB2GRAY) | |
# Criar máscara anelar da íris | |
mask_iris = np.zeros_like(gray) | |
cv2.circle(mask_iris, (ix, iy), ir, 255, -1) | |
cv2.circle(mask_iris, (px, py), pr, 0, -1) | |
# Dividir em 12 setores (como um relógio) | |
setores = {} | |
for i in range(12): | |
ang_inicio = i * 30 | |
ang_fim = (i + 1) * 30 | |
# Criar máscara do setor | |
mask_setor = np.zeros_like(gray) | |
cv2.ellipse(mask_setor, | |
(ix, iy), | |
(ir, ir), | |
0, | |
ang_inicio, | |
ang_fim, | |
255, | |
-1) | |
# Combinar máscaras | |
mask_final = cv2.bitwise_and(mask_iris, mask_setor) | |
# Extrair região do setor | |
setor_roi = cv2.bitwise_and(gray, gray, mask=mask_final) | |
# Análise de textura | |
non_zero = setor_roi[setor_roi != 0] | |
if len(non_zero) > 0: | |
# Calcular características de textura | |
glcm = graycomatrix(non_zero.reshape(-1, 1), [1], [0], symmetric=True, normed=True) | |
setores[f"setor_{i+1}"] = { | |
"media": np.mean(non_zero), | |
"std": np.std(non_zero), | |
"contraste": graycoprops(glcm, 'contrast')[0, 0], | |
"homogeneidade": graycoprops(glcm, 'homogeneity')[0, 0], | |
"energia": graycoprops(glcm, 'energy')[0, 0], | |
"correlacao": graycoprops(glcm, 'correlation')[0, 0] | |
} | |
return setores | |
def analisar_collarette(imagem, iris_info, pupil_info): | |
""" | |
Analisa o collarette (anel de contração) em detalhes | |
""" | |
if iris_info is None or pupil_info is None: | |
return None | |
ix, iy, ir = iris_info | |
px, py, pr = pupil_info | |
# Distância entre pupila e íris | |
dist = ir - pr | |
# Região do collarette (aproximadamente 35% da distância) | |
collarette_inner = pr + int(dist * 0.25) | |
collarette_outer = pr + int(dist * 0.45) | |
# Criar máscara do collarette | |
mask = np.zeros_like(cv2.cvtColor(imagem, cv2.COLOR_RGB2GRAY)) | |
cv2.circle(mask, (px, py), collarette_outer, 255, -1) | |
cv2.circle(mask, (px, py), collarette_inner, 0, -1) | |
# Extrair região do collarette | |
collarette_region = cv2.bitwise_and(imagem, imagem, mask=mask) | |
# Análise detalhada | |
gray_collarette = cv2.cvtColor(collarette_region, cv2.COLOR_RGB2GRAY) | |
non_zero = gray_collarette[gray_collarette != 0] | |
if len(non_zero) > 0: | |
# Calcular características | |
glcm = graycomatrix(non_zero.reshape(-1, 1), [1], [0], symmetric=True, normed=True) | |
return { | |
"intensidade_media": np.mean(non_zero), | |
"variacao": np.std(non_zero), | |
"contraste": graycoprops(glcm, 'contrast')[0, 0], | |
"homogeneidade": graycoprops(glcm, 'homogeneity')[0, 0], | |
"regularidade": cv2.Laplacian(gray_collarette, cv2.CV_64F).var(), | |
"circularidade": avaliar_circularidade(mask) | |
} | |
return None | |
def avaliar_circularidade(mask): | |
""" | |
Avalia a circularidade de uma região | |
""" | |
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) | |
if contours: | |
cnt = max(contours, key=cv2.contourArea) | |
area = cv2.contourArea(cnt) | |
perimeter = cv2.arcLength(cnt, True) | |
if perimeter > 0: | |
circularity = 4 * np.pi * area / (perimeter * perimeter) | |
return circularity | |
return 0 | |
def criar_interface(): | |
""" | |
Cria interface moderna do Gradio | |
""" | |
theme = gr.themes.Soft( | |
primary_hue="teal", | |
secondary_hue="green", | |
).set( | |
body_text_color="#2A9D8F", | |
block_title_text_color="#264653", | |
block_label_text_color="#2A9D8F", | |
input_background_fill="#E9F5F3", | |
button_primary_background_fill="#2A9D8F", | |
button_primary_background_fill_dark="#264653", | |
) | |
def processar_imagem(imagem): | |
try: | |
# Pré-processamento | |
imagem_processada = pre_processar_imagem(imagem) | |
# Detectar esclera | |
mask_esclera = detectar_esclera(imagem_processada) | |
# Detectar íris e pupila | |
iris_info, pupil_info = detectar_iris_pupila(imagem_processada, mask_esclera) | |
if iris_info is None or pupil_info is None: | |
return imagem, "Não foi possível detectar íris ou pupila corretamente." | |
# Análise de textura | |
analise_setorial = analisar_textura_setorial(imagem_processada, iris_info, pupil_info) | |
# Análise do collarette | |
info_collarette = analisar_collarette(imagem_processada, iris_info, pupil_info) | |
# Criar visualização | |
output_img = imagem.copy() | |
# Desenhar esclera | |
contours, _ = cv2.findContours(mask_esclera, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) | |
cv2.drawContours(output_img, contours, -1, (255, 255, 0), 1) | |
# Desenhar íris | |
ix, iy, ir = iris_info | |
cv2.circle(output_img, (ix, iy), ir, (0, 255, 0), 2) | |
# Desenhar pupila | |
px, py, pr = pupil_info | |
cv2.circle(output_img, (px, py), pr, (255, 0, 0), 2) | |
# Desenhar setores | |
for i in range(12): | |
ang = i * 30 | |
rad = np.radians(ang) | |
end_x = int(ix + ir * np.cos(rad)) | |
end_y = int(iy + ir * np.sin(rad)) | |
cv2.line(output_img, (ix, iy), (end_x, end_y), (0, 255, 0), 1) | |
# Gerar relatório | |
relatorio = "ANÁLISE IRIDOLÓGICA DETALHADA\n\n" | |
# Informações estruturais | |
relatorio += "1. MEDIDAS ESTRUTURAIS\n" | |
relatorio += f"Pupila: Centro ({px}, {py}), Raio {pr}px\n" | |
relatorio += f"Íris: Centro ({ix}, {iy}), Raio {ir}px\n" | |
# Análise setorial | |
relatorio += "\n2. ANÁLISE SETORIAL\n" | |
for setor, dados in analise_setorial.items(): | |
relatorio += f"\n{setor}:\n" | |
relatorio += f"- Contraste: {dados['contraste']:.2f}\n" | |
relatorio += f"- Homogeneidade: {dados['homogeneidade']:.2f}\n" | |
# Interpretação | |
if dados['contraste'] > 2.0: | |
relatorio += " * Alta densidade de sinais\n" | |
if dados['homogeneidade'] < 0.5: | |
relatorio += " * Possível área de alteração\n" | |
# Análise do collarette | |
if info_collarette: | |
relatorio += "\n3. ANÁLISE DO COLLARETTE\n" | |
relatorio += f"- Regularidade: {info_collarette['regularidade']:.2f}\n" | |
relatorio += f"- Circularidade: {info_collarette['circularidade']:.2f}\n" | |
# Interpretação | |
if info_collarette['regularidade'] > 500: | |
relatorio += " * Irregularidade significativa\n" | |
if info_collarette['circularidade'] < 0.8: | |
relatorio += " * Possível deformação estrutural\n" | |
return output_img, relatorio | |
except Exception as e: | |
return imagem, f"Erro durante o processamento: {str(e)}" | |
# Interface | |
with gr.Blocks(theme=theme, title="Análise Iridológica Avançada") as interface: | |
gr.Markdown(""" | |
# Sistema Avançado de Análise Iridológica | |
### Detecção precisa de esclera, íris e pupila com análise setorial | |
""") | |
with gr.Tabs(): | |
# Aba de Análise Principal | |
with gr.Tab("Análise de Imagem"): | |
with gr.Row(): | |
with gr.Column(): | |
input_image = gr.Image( | |
label="Imagem do Olho", | |
type="numpy" | |
) | |
with gr.Column(): | |
output_image = gr.Image( | |
label="Análise Visual" | |
) | |
analysis_btn = gr.Button("Analisar Olho", variant="primary") | |
output_text = gr.Textbox( | |
label="Relatório de Análise", | |
lines=20 | |
) | |
analysis_btn.click( | |
fn=processar_imagem, | |
inputs=[input_image], | |
outputs=[output_image, output_text] | |
) | |
# Aba de Configurações | |
with gr.Tab("Configurações"): | |
with gr.Row(): | |
min_iris_radius = gr.Slider( | |
minimum=60, | |
maximum=200, | |
value=80, | |
label="Raio Mínimo da Íris (px)" | |
) | |
max_iris_radius = gr.Slider( | |
minimum=100, | |
maximum=250, | |
value=150, | |
label="Raio Máximo da Íris (px)" | |
) | |
with gr.Row(): | |
min_pupil_radius = gr.Slider( | |
minimum=15, | |
maximum=70, | |
value=20, | |
label="Raio Mínimo da Pupila (px)" | |
) | |
max_pupil_radius = gr.Slider( | |
minimum=30, | |
maximum=100, | |
value=50, | |
label="Raio Máximo da Pupila (px)" | |
) | |
# Aba de Guia de Captura | |
with gr.Tab("Guia de Captura"): | |
gr.Markdown(""" | |
## Guia para Captura de Imagem | |
### 1. Iluminação Ideal | |
- Luz natural indireta | |
- Sem reflexos diretos no olho | |
- Iluminação uniforme | |
- Evitar flash | |
### 2. Posicionamento | |
- Olho totalmente aberto | |
- Câmera perpendicular ao olho | |
- Distância adequada (15-20cm) | |
- Íris centralizada na imagem | |
### 3. Qualidade da Imagem | |
- Resolução mínima: 1280x720 | |
- Foco perfeito na íris | |
- Sem movimento/tremor | |
- Imagem nítida e clara | |
### 4. Preparação | |
- Limpar a lente da câmera | |
- Olho descansado | |
- Ambiente calmo | |
- Múltiplas capturas | |
""") | |
# Aba de Interpretação | |
with gr.Tab("Guia de Interpretação"): | |
gr.Markdown(""" | |
## Guia de Interpretação dos Resultados | |
### 1. Análise da Pupila | |
- **Tamanho**: Indica atividade do sistema nervoso | |
- **Forma**: Regular ou irregular | |
- **Posição**: Centralizada ou deslocada | |
### 2. Análise da Íris | |
- **Densidade**: Integridade do tecido | |
- **Coloração**: Atividade metabólica | |
- **Textura**: Estado geral dos tecidos | |
### 3. Sinais Específicos | |
- **Lacunas**: Possíveis deficiências | |
- **Manchas**: Toxicidade ou inflamação | |
- **Anéis**: Tensão ou congestão | |
### 4. Collarette | |
- **Regularidade**: Equilíbrio do sistema | |
- **Circularidade**: Integridade estrutural | |
- **Densidade**: Vitalidade geral | |
""") | |
return interface | |
def main(): | |
interface = criar_interface() | |
interface.launch(share=True) | |
if __name__ == "__main__": | |
main() |