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()