Spaces:
Sleeping
Sleeping
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 None: | |
print("Nenhum círculo de íris detectado.") | |
return None, 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), 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 None: | |
print("Nenhum círculo de pupila detectado.") | |
return (ix, iy, ir), None | |
pupil_circles = np.uint16(np.around(pupil_circles)) | |
px, py, pr = pupil_circles[0][0] | |
return (ix, iy, ir), (px, py, pr) | |
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 |