import cv2 import numpy as np from PIL import Image import io from collections import defaultdict from scipy import ndimage from skimage.feature import graycomatrix, graycoprops from transformers import pipeline, AutoTokenizer, AutoModelForSequenceClassification import torch class AnalisadorIridologicoNLP: def __init__(self): modelo = "neuralmind/bert-base-portuguese-cased" self.tokenizer = AutoTokenizer.from_pretrained(modelo) self.model = AutoModelForSequenceClassification.from_pretrained(modelo) self.referencias = self._definir_referencias() def _definir_referencias(self): return { 'pupila': { 'tamanho': { 'grande': 'Indica possível estresse do sistema nervoso ou fadiga adrenal', 'pequena': 'Pode indicar tensão nervosa ou hiperatividade', 'normal': 'Sistema nervoso em equilíbrio' }, 'forma': { 'irregular': 'Possível desequilíbrio no sistema nervoso autônomo', 'regular': 'Boa regulação do sistema nervoso' } }, 'iris': { 'densidade': { 'alta': 'Boa integridade do tecido iridiano', 'baixa': 'Possível fragilidade tecidual', 'media': 'Integridade tecidual normal' }, 'textura': { 'homogenea': 'Tecidos em bom estado', 'irregular': 'Possíveis alterações teciduais', 'mista': 'Variações na qualidade tecidual' } }, 'collarette': { 'regularidade': { 'alta': 'Boa integridade do anel de contração', 'baixa': 'Possível comprometimento estrutural', 'media': 'Estrutura em condições normais' }, 'circularidade': { 'alta': 'Boa formação estrutural', 'baixa': 'Possível alteração na formação', 'media': 'Formação estrutural adequada' } } } def classificar_caracteristica(self, valor, tipo, subtipo): if tipo == 'pupila': if subtipo == 'tamanho': if valor < 25: return 'pequena' elif valor > 45: return 'grande' else: return 'normal' elif subtipo == 'forma': return 'regular' if valor > 0.85 else 'irregular' elif tipo == 'iris': if subtipo == 'densidade': if valor < 0.4: return 'baixa' elif valor > 0.7: return 'alta' else: return 'media' elif subtipo == 'textura': if valor < 0.3: return 'irregular' elif valor > 0.6: return 'homogenea' else: return 'mista' elif tipo == 'collarette': if subtipo == 'regularidade': if valor < 300: return 'alta' elif valor > 700: return 'baixa' else: return 'media' elif subtipo == 'circularidade': if valor < 0.7: return 'baixa' elif valor > 0.9: return 'alta' else: return 'media' return 'indefinido' def gerar_interpretacao(self, metricas): interpretacao = [] if 'pupila' in metricas: tamanho = self.classificar_caracteristica( metricas['pupila']['raio'], 'pupila', 'tamanho' ) forma = self.classificar_caracteristica( metricas['pupila']['circularidade'], 'pupila', 'forma' ) interpretacao.append(f"Pupila: {self.referencias['pupila']['tamanho'][tamanho]}") interpretacao.append(f"Forma pupilar: {self.referencias['pupila']['forma'][forma]}") if 'iris' in metricas: densidade = self.classificar_caracteristica( metricas['iris']['densidade_media'], 'iris', 'densidade' ) textura = self.classificar_caracteristica( metricas['iris']['homogeneidade'], 'iris', 'textura' ) interpretacao.append(f"Íris: {self.referencias['iris']['densidade'][densidade]}") interpretacao.append(f"Textura: {self.referencias['iris']['textura'][textura]}") if 'collarette' in metricas: regularidade = self.classificar_caracteristica( metricas['collarette']['regularidade'], 'collarette', 'regularidade' ) circularidade = self.classificar_caracteristica( metricas['collarette']['circularidade'], 'collarette', 'circularidade' ) interpretacao.append(f"Collarette: {self.referencias['collarette']['regularidade'][regularidade]}") interpretacao.append(f"Estrutura: {self.referencias['collarette']['circularidade'][circularidade]}") texto_interpretacao = "\n".join(interpretacao) inputs = self.tokenizer( texto_interpretacao, return_tensors="pt", padding=True, truncation=True, max_length=512 ) with torch.no_grad(): outputs = self.model(**inputs) refined_text = self.refinar_texto(texto_interpretacao, outputs.logits) return refined_text def refinar_texto(self, texto, logits): sentencas = texto.split("\n") refined_sentencas = [f"• {s}" for s in sentencas if len(s.strip()) > 0] return "\n".join(refined_sentencas) # Funções de pré-processamento, detecção e análise def pre_processar_imagem(imagem): lab = cv2.cvtColor(imagem, cv2.COLOR_RGB2LAB) l, a, b = cv2.split(lab) clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8,8)) l = clahe.apply(l) lab = cv2.merge((l,a,b)) imagem_melhorada = cv2.cvtColor(lab, cv2.COLOR_LAB2RGB) imagem_melhorada = cv2.GaussianBlur(imagem_melhorada, (5, 5), 0) return imagem_melhorada def detectar_esclera(imagem): hsv = cv2.cvtColor(imagem, cv2.COLOR_RGB2HSV) lower_white = np.array([0, 0, 180]) upper_white = np.array([180, 30, 255]) mask_esclera = cv2.inRange(hsv, lower_white, upper_white) 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): gray = cv2.cvtColor(imagem, cv2.COLOR_RGB2GRAY) mask_olho = cv2.bitwise_not(mask_esclera) eye_region = cv2.bitwise_and(gray, gray, mask=mask_olho) edges = cv2.Canny(eye_region, 30, 60) iris_circles = cv2.HoughCircles( edges, cv2.HOUGH_GRADIENT, dp=1, minDist=100, param1=50, param2=30, minRadius=80, maxRadius=150 ) 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) iris_region = cv2.bitwise_and(gray, gray, mask=mask_iris) thresh = cv2.adaptiveThreshold( iris_region, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2 ) 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): if iris_info is None or pupil_info is None: return {} ix, iy, ir = iris_info px, py, pr = pupil_info gray = cv2.cvtColor(imagem, cv2.COLOR_RGB2GRAY) clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(4, 4)) gray = clahe.apply(gray) mask_iris = np.zeros_like(gray) cv2.circle(mask_iris, (ix, iy), int(ir * 0.98), 255, -1) cv2.circle(mask_iris, (px, py), int(pr * 1.02), 0, -1) setores = {} for i in range(12): ang_inicio = i * 30 ang_fim = (i + 1) * 30 mask_setor = np.zeros_like(gray) cv2.ellipse(mask_setor, (ix, iy), (ir, ir), 0, ang_inicio, ang_fim, 255, -1) mask_final = cv2.bitwise_and(mask_iris, mask_setor) kernel = np.ones((2, 2), np.uint8) mask_final = cv2.morphologyEx(mask_final, cv2.MORPH_OPEN, kernel) setor_roi = cv2.bitwise_and(gray, gray, mask=mask_final) non_zero = setor_roi[setor_roi > 0] if len(non_zero) > 100: non_zero = ((non_zero - non_zero.min()) / (non_zero.max() - non_zero.min() + 1e-8) * 15).astype(np.uint8) tamanho_janela = int(np.sqrt(len(non_zero))) if tamanho_janela > 1: matriz_2d = non_zero[:tamanho_janela**2].reshape(tamanho_janela, tamanho_janela) try: glcm = graycomatrix(matriz_2d, distances=[1], angles=[0, np.pi/4], levels=16, symmetric=True, normed=True) contraste = np.mean(graycoprops(glcm, 'contrast')) homogeneidade = np.mean(graycoprops(glcm, 'homogeneity')) setores[f"setor_{i+1}"] = { "contraste": float(contraste), "homogeneidade": float(homogeneidade), "media": float(np.mean(non_zero)), "std": float(np.std(non_zero)) } except Exception as e: setores[f"setor_{i+1}"] = { "contraste": 0.0, "homogeneidade": 1.0, "media": 0.0, "std": 0.0 } else: setores[f"setor_{i+1}"] = { "contraste": 0.0, "homogeneidade": 1.0, "media": 0.0, "std": 0.0 } else: setores[f"setor_{i+1}"] = { "contraste": 0.0, "homogeneidade": 1.0, "media": 0.0, "std": 0.0 } return setores def validar_metricas(metricas): metricas_validadas = {} if 'pupila' in metricas: raio = metricas['pupila'].get('raio', 0) circularidade = metricas['pupila'].get('circularidade', 0) if raio <= 0 or raio > 100: raio = 35 if circularidade <= 0 or circularidade > 1: circularidade = 0.85 metricas_validadas['pupila'] = { 'raio': raio, 'circularidade': circularidade } if 'iris' in metricas: densidade = metricas['iris'].get('densidade_media', 0) homogeneidade = metricas['iris'].get('homogeneidade', 0) if densidade < 0: densidade = 0.5 if homogeneidade < 0 or homogeneidade > 1: homogeneidade = 0.5 metricas_validadas['iris'] = { 'densidade_media': densidade, 'homogeneidade': homogeneidade } if 'collarette' in metricas and metricas['collarette']: regularidade = metricas['collarette'].get('regularidade', 0) circularidade = metricas['collarette'].get('circularidade', 0) if regularidade < 0: regularidade = 300 if circularidade < 0 or circularidade > 1: circularidade = 0.85 metricas_validadas['collarette'] = { 'regularidade': regularidade, 'circularidade': circularidade } return metricas_validadas