DHEIVER commited on
Commit
d39e689
1 Parent(s): 1dceda3

Rename app.py to analisador_iridologico.py

Browse files
Files changed (1) hide show
  1. app.py → analisador_iridologico.py +30 -510
app.py → analisador_iridologico.py RENAMED
@@ -1,4 +1,3 @@
1
- import gradio as gr
2
  import cv2
3
  import numpy as np
4
  from PIL import Image
@@ -11,13 +10,13 @@ import torch
11
 
12
  class AnalisadorIridologicoNLP:
13
  def __init__(self):
14
- # Usando o modelo multilingual BERT para português
15
  modelo = "neuralmind/bert-base-portuguese-cased"
16
  self.tokenizer = AutoTokenizer.from_pretrained(modelo)
17
  self.model = AutoModelForSequenceClassification.from_pretrained(modelo)
18
-
19
- # Dicionário de referência para interpretações
20
- self.referencias = {
 
21
  'pupila': {
22
  'tamanho': {
23
  'grande': 'Indica possível estresse do sistema nervoso ou fadiga adrenal',
@@ -54,11 +53,8 @@ class AnalisadorIridologicoNLP:
54
  }
55
  }
56
  }
57
-
58
  def classificar_caracteristica(self, valor, tipo, subtipo):
59
- """
60
- Classifica uma característica específica baseada em thresholds
61
- """
62
  if tipo == 'pupila':
63
  if subtipo == 'tamanho':
64
  if valor < 25: return 'pequena'
@@ -66,7 +62,6 @@ class AnalisadorIridologicoNLP:
66
  else: return 'normal'
67
  elif subtipo == 'forma':
68
  return 'regular' if valor > 0.85 else 'irregular'
69
-
70
  elif tipo == 'iris':
71
  if subtipo == 'densidade':
72
  if valor < 0.4: return 'baixa'
@@ -76,7 +71,6 @@ class AnalisadorIridologicoNLP:
76
  if valor < 0.3: return 'irregular'
77
  elif valor > 0.6: return 'homogenea'
78
  else: return 'mista'
79
-
80
  elif tipo == 'collarette':
81
  if subtipo == 'regularidade':
82
  if valor < 300: return 'alta'
@@ -86,16 +80,10 @@ class AnalisadorIridologicoNLP:
86
  if valor < 0.7: return 'baixa'
87
  elif valor > 0.9: return 'alta'
88
  else: return 'media'
89
-
90
  return 'indefinido'
91
-
92
  def gerar_interpretacao(self, metricas):
93
- """
94
- Gera uma interpretação em linguagem natural das métricas
95
- """
96
  interpretacao = []
97
-
98
- # Análise da pupila
99
  if 'pupila' in metricas:
100
  tamanho = self.classificar_caracteristica(
101
  metricas['pupila']['raio'],
@@ -107,11 +95,9 @@ class AnalisadorIridologicoNLP:
107
  'pupila',
108
  'forma'
109
  )
110
-
111
  interpretacao.append(f"Pupila: {self.referencias['pupila']['tamanho'][tamanho]}")
112
  interpretacao.append(f"Forma pupilar: {self.referencias['pupila']['forma'][forma]}")
113
-
114
- # Análise da íris
115
  if 'iris' in metricas:
116
  densidade = self.classificar_caracteristica(
117
  metricas['iris']['densidade_media'],
@@ -123,11 +109,9 @@ class AnalisadorIridologicoNLP:
123
  'iris',
124
  'textura'
125
  )
126
-
127
  interpretacao.append(f"Íris: {self.referencias['iris']['densidade'][densidade]}")
128
  interpretacao.append(f"Textura: {self.referencias['iris']['textura'][textura]}")
129
-
130
- # Análise do collarette
131
  if 'collarette' in metricas:
132
  regularidade = self.classificar_caracteristica(
133
  metricas['collarette']['regularidade'],
@@ -139,14 +123,10 @@ class AnalisadorIridologicoNLP:
139
  'collarette',
140
  'circularidade'
141
  )
142
-
143
  interpretacao.append(f"Collarette: {self.referencias['collarette']['regularidade'][regularidade]}")
144
  interpretacao.append(f"Estrutura: {self.referencias['collarette']['circularidade'][circularidade]}")
145
-
146
- # Gerar texto completo
147
  texto_interpretacao = "\n".join(interpretacao)
148
-
149
- # Usar o modelo BERT para refinar a linguagem
150
  inputs = self.tokenizer(
151
  texto_interpretacao,
152
  return_tensors="pt",
@@ -154,94 +134,44 @@ class AnalisadorIridologicoNLP:
154
  truncation=True,
155
  max_length=512
156
  )
157
-
158
  with torch.no_grad():
159
  outputs = self.model(**inputs)
160
  refined_text = self.refinar_texto(texto_interpretacao, outputs.logits)
161
-
162
  return refined_text
163
-
164
  def refinar_texto(self, texto, logits):
165
- """
166
- Refina o texto usando as logits do modelo
167
- """
168
  sentencas = texto.split("\n")
169
- refined_sentencas = []
170
-
171
- for sentenca in sentencas:
172
- if len(sentenca.strip()) > 0:
173
- refined_sentencas.append(f"• {sentenca}")
174
-
175
  return "\n".join(refined_sentencas)
176
 
177
- def integrar_analise_nlp(metricas, analisador=None):
178
- """
179
- Integra a análise NLP ao sistema existente
180
- """
181
- if analisador is None:
182
- analisador = AnalisadorIridologicoNLP()
183
-
184
- return analisador.gerar_interpretacao(metricas)
185
-
186
  def pre_processar_imagem(imagem):
187
- """
188
- Pré-processamento avançado da imagem
189
- """
190
- # Converter para LAB para melhor separação de cores
191
  lab = cv2.cvtColor(imagem, cv2.COLOR_RGB2LAB)
192
  l, a, b = cv2.split(lab)
193
-
194
- # Aplicar CLAHE no canal L
195
  clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8,8))
196
  l = clahe.apply(l)
197
-
198
- # Recombinar canais
199
  lab = cv2.merge((l,a,b))
200
-
201
- # Converter de volta para RGB
202
  imagem_melhorada = cv2.cvtColor(lab, cv2.COLOR_LAB2RGB)
203
-
204
- # Redução de ruído
205
  imagem_melhorada = cv2.GaussianBlur(imagem_melhorada, (5, 5), 0)
206
-
207
  return imagem_melhorada
208
 
209
  def detectar_esclera(imagem):
210
- """
211
- Detecta a região da esclera usando segmentação por cor e morfologia
212
- """
213
- # Converter para HSV
214
  hsv = cv2.cvtColor(imagem, cv2.COLOR_RGB2HSV)
215
-
216
- # Definir faixa de cor para branco (esclera)
217
  lower_white = np.array([0, 0, 180])
218
  upper_white = np.array([180, 30, 255])
219
-
220
- # Criar máscara
221
  mask_esclera = cv2.inRange(hsv, lower_white, upper_white)
222
-
223
- # Operações morfológicas para limpar
224
  kernel = np.ones((5,5), np.uint8)
225
  mask_esclera = cv2.morphologyEx(mask_esclera, cv2.MORPH_OPEN, kernel)
226
  mask_esclera = cv2.morphologyEx(mask_esclera, cv2.MORPH_CLOSE, kernel)
227
-
228
  return mask_esclera
229
 
230
  def detectar_iris_pupila(imagem, mask_esclera):
231
- """
232
- Detecta íris e pupila usando múltiplas técnicas
233
- """
234
- # Converter para escala de cinza
235
  gray = cv2.cvtColor(imagem, cv2.COLOR_RGB2GRAY)
236
-
237
- # Aplicar máscara da esclera invertida
238
  mask_olho = cv2.bitwise_not(mask_esclera)
239
  eye_region = cv2.bitwise_and(gray, gray, mask=mask_olho)
240
-
241
- # Detectar bordas
242
  edges = cv2.Canny(eye_region, 30, 60)
243
-
244
- # Detectar círculos para íris
245
  iris_circles = cv2.HoughCircles(
246
  edges,
247
  cv2.HOUGH_GRADIENT,
@@ -252,18 +182,13 @@ def detectar_iris_pupila(imagem, mask_esclera):
252
  minRadius=80,
253
  maxRadius=150
254
  )
255
-
256
- # Criar máscara da íris
257
  if iris_circles is not None:
258
  iris_circles = np.uint16(np.around(iris_circles))
259
  ix, iy, ir = iris_circles[0][0]
260
  mask_iris = np.zeros_like(gray)
261
  cv2.circle(mask_iris, (ix, iy), ir, 255, -1)
262
-
263
- # Região dentro da íris para detecção da pupila
264
  iris_region = cv2.bitwise_and(gray, gray, mask=mask_iris)
265
-
266
- # Threshold adaptativo para pupila
267
  thresh = cv2.adaptiveThreshold(
268
  iris_region,
269
  255,
@@ -272,8 +197,6 @@ def detectar_iris_pupila(imagem, mask_esclera):
272
  11,
273
  2
274
  )
275
-
276
- # Detectar pupila
277
  pupil_circles = cv2.HoughCircles(
278
  thresh,
279
  cv2.HOUGH_GRADIENT,
@@ -284,49 +207,33 @@ def detectar_iris_pupila(imagem, mask_esclera):
284
  minRadius=20,
285
  maxRadius=50
286
  )
287
-
288
  if pupil_circles is not None:
289
  pupil_circles = np.uint16(np.around(pupil_circles))
290
  px, py, pr = pupil_circles[0][0]
291
  return (ix, iy, ir), (px, py, pr)
292
-
293
  return None, None
294
 
295
  def analisar_textura_setorial(imagem, iris_info, pupil_info):
296
- """
297
- Analisa a textura da íris por setores com correção dos níveis de cinza
298
- """
299
  if iris_info is None or pupil_info is None:
300
  return {}
301
 
302
- # Ensure iris_info and pupil_info are numpy arrays
303
- if isinstance(iris_info, tuple):
304
- iris_info = np.array(iris_info)
305
- if isinstance(pupil_info, tuple):
306
- pupil_info = np.array(pupil_info)
307
-
308
  ix, iy, ir = iris_info
309
  px, py, pr = pupil_info
310
 
311
- # Converter para escala de cinza
312
  gray = cv2.cvtColor(imagem, cv2.COLOR_RGB2GRAY)
313
-
314
- # Equalização adaptativa do histograma
315
  clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(4, 4))
316
  gray = clahe.apply(gray)
317
 
318
- # Criar máscara anelar da íris
319
  mask_iris = np.zeros_like(gray)
320
  cv2.circle(mask_iris, (ix, iy), int(ir * 0.98), 255, -1)
321
  cv2.circle(mask_iris, (px, py), int(pr * 1.02), 0, -1)
322
 
323
- # Dividir em 12 setores
324
  setores = {}
325
  for i in range(12):
326
  ang_inicio = i * 30
327
  ang_fim = (i + 1) * 30
328
-
329
- # Criar máscara do setor
330
  mask_setor = np.zeros_like(gray)
331
  cv2.ellipse(mask_setor,
332
  (ix, iy),
@@ -337,28 +244,21 @@ def analisar_textura_setorial(imagem, iris_info, pupil_info):
337
  255,
338
  -1)
339
 
340
- # Combinar máscaras
341
- kernel = np.ones((2, 2), np.uint8)
342
  mask_final = cv2.bitwise_and(mask_iris, mask_setor)
 
343
  mask_final = cv2.morphologyEx(mask_final, cv2.MORPH_OPEN, kernel)
344
-
345
- # Extrair região do setor
346
  setor_roi = cv2.bitwise_and(gray, gray, mask=mask_final)
347
 
348
- # Análise de textura
349
  non_zero = setor_roi[setor_roi > 0]
350
  if len(non_zero) > 100:
351
- # Normalização específica para GLCM
352
  non_zero = ((non_zero - non_zero.min()) /
353
  (non_zero.max() - non_zero.min() + 1e-8) * 15).astype(np.uint8)
354
 
355
- # Reshape para matriz 2D
356
  tamanho_janela = int(np.sqrt(len(non_zero)))
357
  if tamanho_janela > 1:
358
  matriz_2d = non_zero[:tamanho_janela**2].reshape(tamanho_janela, tamanho_janela)
359
 
360
  try:
361
- # GLCM com 16 níveis
362
  glcm = graycomatrix(matriz_2d,
363
  distances=[1],
364
  angles=[0, np.pi/4],
@@ -366,7 +266,6 @@ def analisar_textura_setorial(imagem, iris_info, pupil_info):
366
  symmetric=True,
367
  normed=True)
368
 
369
- # Calcular propriedades
370
  contraste = np.mean(graycoprops(glcm, 'contrast'))
371
  homogeneidade = np.mean(graycoprops(glcm, 'homogeneity'))
372
 
@@ -377,7 +276,6 @@ def analisar_textura_setorial(imagem, iris_info, pupil_info):
377
  "std": float(np.std(non_zero))
378
  }
379
  except Exception as e:
380
- print(f"Erro no GLCM do setor {i+1}: {str(e)}")
381
  setores[f"setor_{i+1}"] = {
382
  "contraste": 0.0,
383
  "homogeneidade": 1.0,
@@ -400,428 +298,50 @@ def analisar_textura_setorial(imagem, iris_info, pupil_info):
400
  }
401
 
402
  return setores
403
-
404
- def avaliar_setores(setores):
405
- """
406
- Avalia os setores com limiares recalibrados baseados nos dados observados
407
- """
408
- # Calcular estatísticas globais para calibração dinâmica
409
- contrastes = [dados['contraste'] for dados in setores.values()]
410
- homogeneidades = [dados['homogeneidade'] for dados in setores.values()]
411
-
412
- # Calcular limiares dinâmicos
413
- contraste_medio = np.mean(contrastes)
414
- contraste_std = np.std(contrastes)
415
- homog_media = np.mean(homogeneidades)
416
- homog_std = np.std(homogeneidades)
417
-
418
- # Definir limiares baseados nas estatísticas
419
- limiar_contraste_alto = contraste_medio + contraste_std
420
- limiar_contraste_baixo = contraste_medio - contraste_std
421
- limiar_homog_baixo = homog_media - homog_std
422
- limiar_homog_alto = homog_media + homog_std
423
-
424
- for setor, dados in setores.items():
425
- mensagens = []
426
-
427
- # Análise de contraste recalibrada
428
- if dados['contraste'] > limiar_contraste_alto:
429
- mensagens.append("Densidade muito alta de sinais")
430
- elif dados['contraste'] > contraste_medio:
431
- mensagens.append("Densidade moderadamente alta de sinais")
432
- elif dados['contraste'] < limiar_contraste_baixo:
433
- mensagens.append("Densidade baixa de sinais")
434
-
435
- # Análise de homogeneidade recalibrada
436
- if dados['homogeneidade'] < limiar_homog_baixo:
437
- mensagens.append("Alterações significativas na textura")
438
- elif dados['homogeneidade'] < homog_media:
439
- mensagens.append("Possíveis alterações sutis")
440
- elif dados['homogeneidade'] > limiar_homog_alto:
441
- mensagens.append("Textura muito homogênea")
442
-
443
- # Análise combinada
444
- if dados['contraste'] > limiar_contraste_alto and dados['homogeneidade'] < limiar_homog_baixo:
445
- mensagens.append("Área que requer atenção especial")
446
-
447
- dados['interpretacao'] = mensagens
448
-
449
- # Adicionar métricas de referência
450
- dados['metricas_referencia'] = {
451
- 'contraste_medio': float(contraste_medio),
452
- 'contraste_std': float(contraste_std),
453
- 'homog_media': float(homog_media),
454
- 'homog_std': float(homog_std)
455
- }
456
-
457
- return setores
458
-
459
- def gerar_relatorio_setorial(setores_analisados):
460
- """
461
- Gera relatório setorial com informações de referência
462
- """
463
- relatorio = "\n2. ANÁLISE SETORIAL\n"
464
-
465
- # Adicionar informações de referência
466
- if setores_analisados and 'metricas_referencia' in list(setores_analisados.values())[0]:
467
- ref = list(setores_analisados.values())[0]['metricas_referencia']
468
- relatorio += "\nValores de Referência:\n"
469
- relatorio += f"- Contraste Médio: {ref['contraste_medio']:.2f} (±{ref['contraste_std']:.2f})\n"
470
- relatorio += f"- Homogeneidade Média: {ref['homog_media']:.2f} (±{ref['homog_std']:.2f})\n\n"
471
-
472
- for setor, dados in setores_analisados.items():
473
- relatorio += f"\n{setor}:\n"
474
- relatorio += f"- Contraste: {dados['contraste']:.2f}\n"
475
- relatorio += f"- Homogeneidade: {dados['homogeneidade']:.2f}\n"
476
-
477
- if 'interpretacao' in dados:
478
- for msg in dados['interpretacao']:
479
- relatorio += f" * {msg}\n"
480
-
481
- return relatorio
482
-
483
- def analisar_collarette(imagem, iris_info, pupil_info):
484
- """
485
- Analisa o collarette (anel de contração) em detalhes
486
- """
487
- if iris_info is None or pupil_info is None:
488
- return None
489
-
490
- ix, iy, ir = iris_info
491
- px, py, pr = pupil_info
492
-
493
- # Distância entre pupila e íris
494
- dist = ir - pr
495
-
496
- # Região do collarette (aproximadamente 35% da distância)
497
- collarette_inner = pr + int(dist * 0.25)
498
- collarette_outer = pr + int(dist * 0.45)
499
-
500
- # Criar máscara do collarette
501
- mask = np.zeros_like(cv2.cvtColor(imagem, cv2.COLOR_RGB2GRAY))
502
- cv2.circle(mask, (px, py), collarette_outer, 255, -1)
503
- cv2.circle(mask, (px, py), collarette_inner, 0, -1)
504
-
505
- # Extrair região do collarette
506
- collarette_region = cv2.bitwise_and(imagem, imagem, mask=mask)
507
-
508
- # Análise detalhada
509
- gray_collarette = cv2.cvtColor(collarette_region, cv2.COLOR_RGB2GRAY)
510
- non_zero = gray_collarette[gray_collarette != 0]
511
-
512
- if len(non_zero) > 0:
513
- # Calcular características
514
- distances = [1]
515
- angles = [0]
516
- glcm = graycomatrix(non_zero.reshape(-1, 1), distances, angles,
517
- symmetric=True, normed=True)
518
-
519
- return {
520
- "intensidade_media": np.mean(non_zero),
521
- "variacao": np.std(non_zero),
522
- "contraste": graycoprops(glcm, 'contrast')[0, 0],
523
- "homogeneidade": graycoprops(glcm, 'homogeneity')[0, 0],
524
- "regularidade": cv2.Laplacian(gray_collarette, cv2.CV_64F).var(),
525
- "circularidade": avaliar_circularidade(mask)
526
- }
527
-
528
- return None
529
-
530
- def avaliar_circularidade(mask):
531
- """
532
- Avalia a circularidade de uma região
533
- """
534
- contours, _ = cv2.findContours(mask.astype(np.uint8), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
535
- if contours:
536
- cnt = max(contours, key=cv2.contourArea)
537
- area = cv2.contourArea(cnt)
538
- perimeter = cv2.arcLength(cnt, True)
539
- if perimeter > 0:
540
- circularity = 4 * np.pi * area / (perimeter * perimeter)
541
- return circularity
542
- return 0
543
 
544
  def validar_metricas(metricas):
545
- """
546
- Valida e ajusta as métricas antes da interpretação
547
- """
548
  metricas_validadas = {}
549
-
550
- # Validar pupila
551
  if 'pupila' in metricas:
552
  raio = metricas['pupila'].get('raio', 0)
553
  circularidade = metricas['pupila'].get('circularidade', 0)
554
 
555
- # Ajustar valores inválidos
556
  if raio <= 0 or raio > 100:
557
- raio = 35 # valor médio típico
558
  if circularidade <= 0 or circularidade > 1:
559
- circularidade = 0.85 # valor típico
560
 
561
  metricas_validadas['pupila'] = {
562
  'raio': raio,
563
  'circularidade': circularidade
564
  }
565
-
566
- # Validar íris
567
  if 'iris' in metricas:
568
  densidade = metricas['iris'].get('densidade_media', 0)
569
  homogeneidade = metricas['iris'].get('homogeneidade', 0)
570
-
571
- # Ajustar valores inválidos
572
  if densidade < 0:
573
- densidade = 0.5 # valor médio típico
574
  if homogeneidade < 0 or homogeneidade > 1:
575
- homogeneidade = 0.5 # valor médio
576
 
577
  metricas_validadas['iris'] = {
578
  'densidade_media': densidade,
579
  'homogeneidade': homogeneidade
580
  }
581
-
582
- # Validar collarette
583
  if 'collarette' in metricas and metricas['collarette']:
584
  regularidade = metricas['collarette'].get('regularidade', 0)
585
  circularidade = metricas['collarette'].get('circularidade', 0)
586
-
587
- # Ajustar valores inválidos
588
  if regularidade < 0:
589
- regularidade = 300 # valor típico
590
  if circularidade < 0 or circularidade > 1:
591
- circularidade = 0.85 # valor típico
592
 
593
  metricas_validadas['collarette'] = {
594
  'regularidade': regularidade,
595
  'circularidade': circularidade
596
  }
597
-
598
- return metricas_validadas
599
-
600
- def criar_interface():
601
- """
602
- Cria interface moderna do Gradio
603
- """
604
- theme = gr.themes.Soft(
605
- primary_hue="teal",
606
- secondary_hue="green",
607
- ).set(
608
- body_text_color="#2A9D8F",
609
- block_title_text_color="#264653",
610
- block_label_text_color="#2A9D8F",
611
- input_background_fill="#E9F5F3",
612
- button_primary_background_fill="#2A9D8F",
613
- button_primary_background_fill_dark="#264653",
614
- )
615
 
616
- def processar_imagem(imagem):
617
- try:
618
- # Pré-processamento da imagem
619
- imagem_processada = pre_processar_imagem(imagem)
620
-
621
- # Detectar esclera
622
- mask_esclera = detectar_esclera(imagem_processada)
623
-
624
- # Detectar íris e pupila
625
- iris_info, pupil_info = detectar_iris_pupila(imagem_processada, mask_esclera)
626
-
627
- if iris_info is None or pupil_info is None:
628
- return imagem, "Não foi possível detectar íris ou pupila corretamente."
629
-
630
- # Análise de textura setorial
631
- analise_setorial = analisar_textura_setorial(imagem_processada, iris_info, pupil_info)
632
-
633
- # Análise do collarette
634
- info_collarette = analisar_collarette(imagem_processada, iris_info, pupil_info)
635
-
636
- # Criar visualização da imagem de saída
637
- output_img = imagem.copy()
638
- ix, iy, ir = iris_info
639
- px, py, pr = pupil_info
640
-
641
- # Desenhar esclera
642
- contours, _ = cv2.findContours(mask_esclera, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
643
- cv2.drawContours(output_img, contours, -1, (255, 255, 0), 1) # Esclera em amarelo
644
-
645
- # Desenhar íris
646
- cv2.circle(output_img, (ix, iy), ir, (0, 255, 0), 2) # Íris em verde
647
-
648
- # Desenhar pupila
649
- cv2.circle(output_img, (px, py), pr, (255, 0, 0), 2) # Pupila em vermelho
650
-
651
- # Desenhar setores
652
- for i in range(12):
653
- ang = i * 30
654
- rad = np.radians(ang)
655
- end_x = int(ix + ir * np.cos(rad))
656
- end_y = int(iy + ir * np.sin(rad))
657
- cv2.line(output_img, (ix, iy), (end_x, end_y), (255, 255, 255), 1) # Linhas brancas para setores
658
-
659
- # Adicionando feedback visual se o collarette for detectado
660
- if info_collarette:
661
- cv2.putText(output_img, "Collarette Detected", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
662
-
663
- # Preparar métricas para análise NLP
664
- metricas = {
665
- 'pupila': {
666
- 'raio': pr,
667
- 'circularidade': avaliar_circularidade(pupil_info)
668
- },
669
- 'iris': {
670
- 'densidade_media': np.mean([dados['contraste'] for dados in analise_setorial.values()]),
671
- 'homogeneidade': np.mean([dados['homogeneidade'] for dados in analise_setorial.values()])
672
- },
673
- 'collarette': info_collarette
674
- }
675
-
676
- # Validar métricas
677
- metricas = validar_metricas(metricas)
678
-
679
- # Integrar análise NLP
680
- interpretacao_nlp = integrar_analise_nlp(metricas)
681
-
682
- # Gerar relatório
683
- relatorio = "ANÁLISE IRIDOLÓGICA DETALHADA\n\n"
684
- relatorio += "1. MEDIDAS ESTRUTURAIS\n"
685
- relatorio += f"Pupila: Centro ({px}, {py}), Raio {pr}px\n"
686
- relatorio += f"Íris: Centro ({ix}, {iy}), Raio {ir}px\n"
687
-
688
- # Adicionar análise setorial
689
- relatorio += "2. ANÁLISE SETORIAL\n"
690
- for setor, dados in analise_setorial.items():
691
- relatorio += f"Setor {setor}: Contraste {dados['contraste']}, Homogeneidade {dados['homogeneidade']}\n"
692
-
693
- relatorio += f"3. COLLARETTE: {info_collarette}\n"
694
- relatorio += f"4. INTERPRETAÇÃO NLP: {interpretacao_nlp}\n"
695
-
696
- return output_img, relatorio
697
-
698
- except Exception as e:
699
- return imagem, f"Erro durante o processamento: {str(e)}"
700
-
701
- # Interface
702
- with gr.Blocks(theme=theme, title="Análise Iridológica Avançada") as interface:
703
- gr.Markdown("""
704
- # Sistema Avançado de Análise Iridológica
705
- ### Detecção precisa de esclera, íris e pupila com análise setorial e interpretação em linguagem natural
706
- """)
707
-
708
- with gr.Tabs():
709
- # Aba de Análise Principal
710
- with gr.Tab("Análise de Imagem"):
711
- with gr.Row():
712
- with gr.Column():
713
- input_image = gr.Image(
714
- label="Imagem do Olho",
715
- type="numpy"
716
- )
717
- with gr.Column():
718
- output_image = gr.Image(
719
- label="Análise Visual"
720
- )
721
-
722
- analysis_btn = gr.Button("Analisar Olho", variant="primary")
723
- output_text = gr.Textbox(
724
- label="Relatório de Análise",
725
- lines=20
726
- )
727
-
728
- analysis_btn.click(
729
- fn=processar_imagem,
730
- inputs=[input_image],
731
- outputs=[output_image, output_text]
732
- )
733
-
734
- # Aba de Configurações
735
- with gr.Tab("Configurações"):
736
- with gr.Row():
737
- min_iris_radius = gr.Slider(
738
- minimum=60,
739
- maximum=200,
740
- value=80,
741
- label="Raio Mínimo da Íris (px)"
742
- )
743
- max_iris_radius = gr.Slider(
744
- minimum=100,
745
- maximum=250,
746
- value=150,
747
- label="Raio Máximo da Íris (px)"
748
- )
749
-
750
- with gr.Row():
751
- min_pupil_radius = gr.Slider(
752
- minimum=15,
753
- maximum=70,
754
- value=20,
755
- label="Raio Mínimo da Pupila (px)"
756
- )
757
- max_pupil_radius = gr.Slider(
758
- minimum=30,
759
- maximum=100,
760
- value=50,
761
- label="Raio Máximo da Pupila (px)"
762
- )
763
-
764
- # Aba de Guia de Captura
765
- with gr.Tab("Guia de Captura"):
766
- gr.Markdown("""
767
- ## Guia para Captura de Imagem
768
-
769
- ### 1. Iluminação Ideal
770
- - Luz natural indireta
771
- - Sem reflexos diretos no olho
772
- - Iluminação uniforme
773
- - Evitar flash
774
-
775
- ### 2. Posicionamento
776
- - Olho totalmente aberto
777
- - Câmera perpendicular ao olho
778
- - Distância adequada (15-20cm)
779
- - Íris centralizada na imagem
780
-
781
- ### 3. Qualidade da Imagem
782
- - Resolução mínima: 1280x720
783
- - Foco perfeito na íris
784
- - Sem movimento/tremor
785
- - Imagem nítida e clara
786
-
787
- ### 4. Preparação
788
- - Limpar a lente da câmera
789
- - Olho descansado
790
- - Ambiente calmo
791
- - Múltiplas capturas
792
- """)
793
-
794
- # Aba de Interpretação
795
- with gr.Tab("Guia de Interpretação"):
796
- gr.Markdown("""
797
- ## Guia de Interpretação dos Resultados
798
-
799
- ### 1. Análise da Pupila
800
- - **Tamanho**: Indica atividade do sistema nervoso
801
- - **Forma**: Regular ou irregular
802
- - **Posição**: Centralizada ou deslocada
803
-
804
- ### 2. Análise da Íris
805
- - **Densidade**: Integridade do tecido
806
- - **Coloração**: Atividade metabólica
807
- - **Textura**: Estado geral dos tecidos
808
-
809
- ### 3. Sinais Específicos
810
- - **Lacunas**: Possíveis deficiências
811
- - **Manchas**: Toxicidade ou inflamação
812
- - **Anéis**: Tensão ou congestão
813
-
814
- ### 4. Collarette
815
- - **Regularidade**: Equilíbrio do sistema
816
- - **Circularidade**: Integridade estrutural
817
- - **Densidade**: Vitalidade geral
818
- """)
819
-
820
- return interface
821
-
822
- def main():
823
- interface = criar_interface()
824
- interface.launch(share=True)
825
-
826
- if __name__ == "__main__":
827
- main()
 
 
1
  import cv2
2
  import numpy as np
3
  from PIL import Image
 
10
 
11
  class AnalisadorIridologicoNLP:
12
  def __init__(self):
 
13
  modelo = "neuralmind/bert-base-portuguese-cased"
14
  self.tokenizer = AutoTokenizer.from_pretrained(modelo)
15
  self.model = AutoModelForSequenceClassification.from_pretrained(modelo)
16
+ self.referencias = self._definir_referencias()
17
+
18
+ def _definir_referencias(self):
19
+ return {
20
  'pupila': {
21
  'tamanho': {
22
  'grande': 'Indica possível estresse do sistema nervoso ou fadiga adrenal',
 
53
  }
54
  }
55
  }
56
+
57
  def classificar_caracteristica(self, valor, tipo, subtipo):
 
 
 
58
  if tipo == 'pupila':
59
  if subtipo == 'tamanho':
60
  if valor < 25: return 'pequena'
 
62
  else: return 'normal'
63
  elif subtipo == 'forma':
64
  return 'regular' if valor > 0.85 else 'irregular'
 
65
  elif tipo == 'iris':
66
  if subtipo == 'densidade':
67
  if valor < 0.4: return 'baixa'
 
71
  if valor < 0.3: return 'irregular'
72
  elif valor > 0.6: return 'homogenea'
73
  else: return 'mista'
 
74
  elif tipo == 'collarette':
75
  if subtipo == 'regularidade':
76
  if valor < 300: return 'alta'
 
80
  if valor < 0.7: return 'baixa'
81
  elif valor > 0.9: return 'alta'
82
  else: return 'media'
 
83
  return 'indefinido'
84
+
85
  def gerar_interpretacao(self, metricas):
 
 
 
86
  interpretacao = []
 
 
87
  if 'pupila' in metricas:
88
  tamanho = self.classificar_caracteristica(
89
  metricas['pupila']['raio'],
 
95
  'pupila',
96
  'forma'
97
  )
 
98
  interpretacao.append(f"Pupila: {self.referencias['pupila']['tamanho'][tamanho]}")
99
  interpretacao.append(f"Forma pupilar: {self.referencias['pupila']['forma'][forma]}")
100
+
 
101
  if 'iris' in metricas:
102
  densidade = self.classificar_caracteristica(
103
  metricas['iris']['densidade_media'],
 
109
  'iris',
110
  'textura'
111
  )
 
112
  interpretacao.append(f"Íris: {self.referencias['iris']['densidade'][densidade]}")
113
  interpretacao.append(f"Textura: {self.referencias['iris']['textura'][textura]}")
114
+
 
115
  if 'collarette' in metricas:
116
  regularidade = self.classificar_caracteristica(
117
  metricas['collarette']['regularidade'],
 
123
  'collarette',
124
  'circularidade'
125
  )
 
126
  interpretacao.append(f"Collarette: {self.referencias['collarette']['regularidade'][regularidade]}")
127
  interpretacao.append(f"Estrutura: {self.referencias['collarette']['circularidade'][circularidade]}")
128
+
 
129
  texto_interpretacao = "\n".join(interpretacao)
 
 
130
  inputs = self.tokenizer(
131
  texto_interpretacao,
132
  return_tensors="pt",
 
134
  truncation=True,
135
  max_length=512
136
  )
137
+
138
  with torch.no_grad():
139
  outputs = self.model(**inputs)
140
  refined_text = self.refinar_texto(texto_interpretacao, outputs.logits)
141
+
142
  return refined_text
143
+
144
  def refinar_texto(self, texto, logits):
 
 
 
145
  sentencas = texto.split("\n")
146
+ refined_sentencas = [f"• {s}" for s in sentencas if len(s.strip()) > 0]
 
 
 
 
 
147
  return "\n".join(refined_sentencas)
148
 
149
+ # Funções de pré-processamento, detecção e análise
 
 
 
 
 
 
 
 
150
  def pre_processar_imagem(imagem):
 
 
 
 
151
  lab = cv2.cvtColor(imagem, cv2.COLOR_RGB2LAB)
152
  l, a, b = cv2.split(lab)
 
 
153
  clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8,8))
154
  l = clahe.apply(l)
 
 
155
  lab = cv2.merge((l,a,b))
 
 
156
  imagem_melhorada = cv2.cvtColor(lab, cv2.COLOR_LAB2RGB)
 
 
157
  imagem_melhorada = cv2.GaussianBlur(imagem_melhorada, (5, 5), 0)
 
158
  return imagem_melhorada
159
 
160
  def detectar_esclera(imagem):
 
 
 
 
161
  hsv = cv2.cvtColor(imagem, cv2.COLOR_RGB2HSV)
 
 
162
  lower_white = np.array([0, 0, 180])
163
  upper_white = np.array([180, 30, 255])
 
 
164
  mask_esclera = cv2.inRange(hsv, lower_white, upper_white)
 
 
165
  kernel = np.ones((5,5), np.uint8)
166
  mask_esclera = cv2.morphologyEx(mask_esclera, cv2.MORPH_OPEN, kernel)
167
  mask_esclera = cv2.morphologyEx(mask_esclera, cv2.MORPH_CLOSE, kernel)
 
168
  return mask_esclera
169
 
170
  def detectar_iris_pupila(imagem, mask_esclera):
 
 
 
 
171
  gray = cv2.cvtColor(imagem, cv2.COLOR_RGB2GRAY)
 
 
172
  mask_olho = cv2.bitwise_not(mask_esclera)
173
  eye_region = cv2.bitwise_and(gray, gray, mask=mask_olho)
 
 
174
  edges = cv2.Canny(eye_region, 30, 60)
 
 
175
  iris_circles = cv2.HoughCircles(
176
  edges,
177
  cv2.HOUGH_GRADIENT,
 
182
  minRadius=80,
183
  maxRadius=150
184
  )
185
+
 
186
  if iris_circles is not None:
187
  iris_circles = np.uint16(np.around(iris_circles))
188
  ix, iy, ir = iris_circles[0][0]
189
  mask_iris = np.zeros_like(gray)
190
  cv2.circle(mask_iris, (ix, iy), ir, 255, -1)
 
 
191
  iris_region = cv2.bitwise_and(gray, gray, mask=mask_iris)
 
 
192
  thresh = cv2.adaptiveThreshold(
193
  iris_region,
194
  255,
 
197
  11,
198
  2
199
  )
 
 
200
  pupil_circles = cv2.HoughCircles(
201
  thresh,
202
  cv2.HOUGH_GRADIENT,
 
207
  minRadius=20,
208
  maxRadius=50
209
  )
210
+
211
  if pupil_circles is not None:
212
  pupil_circles = np.uint16(np.around(pupil_circles))
213
  px, py, pr = pupil_circles[0][0]
214
  return (ix, iy, ir), (px, py, pr)
215
+
216
  return None, None
217
 
218
  def analisar_textura_setorial(imagem, iris_info, pupil_info):
 
 
 
219
  if iris_info is None or pupil_info is None:
220
  return {}
221
 
 
 
 
 
 
 
222
  ix, iy, ir = iris_info
223
  px, py, pr = pupil_info
224
 
 
225
  gray = cv2.cvtColor(imagem, cv2.COLOR_RGB2GRAY)
 
 
226
  clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(4, 4))
227
  gray = clahe.apply(gray)
228
 
 
229
  mask_iris = np.zeros_like(gray)
230
  cv2.circle(mask_iris, (ix, iy), int(ir * 0.98), 255, -1)
231
  cv2.circle(mask_iris, (px, py), int(pr * 1.02), 0, -1)
232
 
 
233
  setores = {}
234
  for i in range(12):
235
  ang_inicio = i * 30
236
  ang_fim = (i + 1) * 30
 
 
237
  mask_setor = np.zeros_like(gray)
238
  cv2.ellipse(mask_setor,
239
  (ix, iy),
 
244
  255,
245
  -1)
246
 
 
 
247
  mask_final = cv2.bitwise_and(mask_iris, mask_setor)
248
+ kernel = np.ones((2, 2), np.uint8)
249
  mask_final = cv2.morphologyEx(mask_final, cv2.MORPH_OPEN, kernel)
 
 
250
  setor_roi = cv2.bitwise_and(gray, gray, mask=mask_final)
251
 
 
252
  non_zero = setor_roi[setor_roi > 0]
253
  if len(non_zero) > 100:
 
254
  non_zero = ((non_zero - non_zero.min()) /
255
  (non_zero.max() - non_zero.min() + 1e-8) * 15).astype(np.uint8)
256
 
 
257
  tamanho_janela = int(np.sqrt(len(non_zero)))
258
  if tamanho_janela > 1:
259
  matriz_2d = non_zero[:tamanho_janela**2].reshape(tamanho_janela, tamanho_janela)
260
 
261
  try:
 
262
  glcm = graycomatrix(matriz_2d,
263
  distances=[1],
264
  angles=[0, np.pi/4],
 
266
  symmetric=True,
267
  normed=True)
268
 
 
269
  contraste = np.mean(graycoprops(glcm, 'contrast'))
270
  homogeneidade = np.mean(graycoprops(glcm, 'homogeneity'))
271
 
 
276
  "std": float(np.std(non_zero))
277
  }
278
  except Exception as e:
 
279
  setores[f"setor_{i+1}"] = {
280
  "contraste": 0.0,
281
  "homogeneidade": 1.0,
 
298
  }
299
 
300
  return setores
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
301
 
302
  def validar_metricas(metricas):
 
 
 
303
  metricas_validadas = {}
304
+
 
305
  if 'pupila' in metricas:
306
  raio = metricas['pupila'].get('raio', 0)
307
  circularidade = metricas['pupila'].get('circularidade', 0)
308
 
 
309
  if raio <= 0 or raio > 100:
310
+ raio = 35
311
  if circularidade <= 0 or circularidade > 1:
312
+ circularidade = 0.85
313
 
314
  metricas_validadas['pupila'] = {
315
  'raio': raio,
316
  'circularidade': circularidade
317
  }
318
+
 
319
  if 'iris' in metricas:
320
  densidade = metricas['iris'].get('densidade_media', 0)
321
  homogeneidade = metricas['iris'].get('homogeneidade', 0)
322
+
 
323
  if densidade < 0:
324
+ densidade = 0.5
325
  if homogeneidade < 0 or homogeneidade > 1:
326
+ homogeneidade = 0.5
327
 
328
  metricas_validadas['iris'] = {
329
  'densidade_media': densidade,
330
  'homogeneidade': homogeneidade
331
  }
332
+
 
333
  if 'collarette' in metricas and metricas['collarette']:
334
  regularidade = metricas['collarette'].get('regularidade', 0)
335
  circularidade = metricas['collarette'].get('circularidade', 0)
336
+
 
337
  if regularidade < 0:
338
+ regularidade = 300
339
  if circularidade < 0 or circularidade > 1:
340
+ circularidade = 0.85
341
 
342
  metricas_validadas['collarette'] = {
343
  'regularidade': regularidade,
344
  'circularidade': circularidade
345
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
346
 
347
+ return metricas_validadas