Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -4,53 +4,69 @@ import numpy as np
|
|
4 |
from PIL import Image
|
5 |
import io
|
6 |
from collections import defaultdict
|
|
|
7 |
|
8 |
-
def
|
9 |
"""
|
10 |
-
|
11 |
"""
|
|
|
12 |
lab = cv2.cvtColor(imagem, cv2.COLOR_RGB2LAB)
|
13 |
l, a, b = cv2.split(lab)
|
|
|
|
|
14 |
clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8,8))
|
15 |
l = clahe.apply(l)
|
|
|
|
|
16 |
lab = cv2.merge((l,a,b))
|
17 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
|
19 |
-
def
|
20 |
"""
|
21 |
-
Detecta
|
22 |
"""
|
23 |
-
#
|
24 |
-
|
25 |
|
26 |
-
#
|
27 |
-
|
|
|
28 |
|
29 |
-
#
|
30 |
-
|
31 |
|
32 |
-
#
|
33 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
|
35 |
-
# Aplicar
|
36 |
-
|
37 |
-
|
38 |
|
39 |
-
# Detectar
|
40 |
-
|
41 |
-
closed,
|
42 |
-
cv2.HOUGH_GRADIENT,
|
43 |
-
dp=1,
|
44 |
-
minDist=50,
|
45 |
-
param1=50,
|
46 |
-
param2=25,
|
47 |
-
minRadius=20,
|
48 |
-
maxRadius=50
|
49 |
-
)
|
50 |
|
51 |
-
# Detectar círculos para íris
|
52 |
iris_circles = cv2.HoughCircles(
|
53 |
-
|
54 |
cv2.HOUGH_GRADIENT,
|
55 |
dp=1,
|
56 |
minDist=100,
|
@@ -60,76 +76,72 @@ def detectar_pupila_iris(imagem):
|
|
60 |
maxRadius=150
|
61 |
)
|
62 |
|
63 |
-
|
64 |
-
|
65 |
-
# Desenhar círculos da pupila
|
66 |
-
if pupila_circles is not None:
|
67 |
-
pupila_circles = np.uint16(np.around(pupila_circles))
|
68 |
-
for i in pupila_circles[0,:]:
|
69 |
-
# Desenhar círculo da pupila
|
70 |
-
cv2.circle(output_img, (i[0], i[1]), i[2], (255, 0, 0), 2)
|
71 |
-
# Desenhar centro
|
72 |
-
cv2.circle(output_img, (i[0], i[1]), 2, (0, 0, 255), 3)
|
73 |
-
pupila_info = (i[0], i[1], i[2])
|
74 |
-
else:
|
75 |
-
pupila_info = None
|
76 |
-
|
77 |
-
# Desenhar círculos da íris
|
78 |
if iris_circles is not None:
|
79 |
iris_circles = np.uint16(np.around(iris_circles))
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
93 |
|
94 |
-
return
|
95 |
|
96 |
-
def
|
97 |
"""
|
98 |
-
|
99 |
"""
|
100 |
-
if
|
101 |
return {}
|
102 |
|
103 |
-
# Converter para escala de cinza
|
104 |
-
gray = cv2.cvtColor(imagem, cv2.COLOR_RGB2GRAY)
|
105 |
-
|
106 |
-
# Coordenadas da pupila e íris
|
107 |
-
px, py, pr = pupila_info
|
108 |
ix, iy, ir = iris_info
|
|
|
109 |
|
110 |
-
#
|
111 |
-
|
112 |
-
cv2.circle(mask, (ix, iy), ir, 255, -1) # Íris
|
113 |
-
cv2.circle(mask, (px, py), pr, 0, -1) # Pupila
|
114 |
-
|
115 |
-
# Aplicar máscara
|
116 |
-
iris_ring = cv2.bitwise_and(gray, gray, mask=mask)
|
117 |
-
|
118 |
-
# Análise de textura
|
119 |
-
caracteristicas = {}
|
120 |
|
121 |
-
#
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
"inferior": (135, 225),
|
126 |
-
"esquerdo": (225, 315)
|
127 |
-
}
|
128 |
|
129 |
-
|
|
|
|
|
|
|
|
|
|
|
130 |
# Criar máscara do setor
|
131 |
-
|
132 |
-
cv2.ellipse(
|
133 |
(ix, iy),
|
134 |
(ir, ir),
|
135 |
0,
|
@@ -138,58 +150,90 @@ def extrair_caracteristicas_avancadas(imagem, pupila_info, iris_info):
|
|
138 |
255,
|
139 |
-1)
|
140 |
|
141 |
-
#
|
142 |
-
|
143 |
|
144 |
-
#
|
|
|
|
|
|
|
145 |
non_zero = setor_roi[setor_roi != 0]
|
146 |
if len(non_zero) > 0:
|
147 |
-
|
|
|
|
|
|
|
148 |
"media": np.mean(non_zero),
|
149 |
"std": np.std(non_zero),
|
150 |
-
"
|
151 |
-
"
|
|
|
|
|
152 |
}
|
153 |
|
154 |
-
return
|
155 |
|
156 |
-
def
|
157 |
"""
|
158 |
-
Analisa o
|
159 |
"""
|
160 |
-
if
|
161 |
return None
|
162 |
|
163 |
-
px, py, pr = pupila_info
|
164 |
ix, iy, ir = iris_info
|
|
|
165 |
|
166 |
-
#
|
167 |
-
|
168 |
|
169 |
-
#
|
|
|
|
|
|
|
|
|
170 |
mask = np.zeros_like(cv2.cvtColor(imagem, cv2.COLOR_RGB2GRAY))
|
171 |
-
cv2.circle(mask, (px, py),
|
172 |
-
cv2.circle(mask, (px, py),
|
173 |
|
174 |
-
#
|
175 |
-
|
176 |
|
177 |
-
# Análise
|
178 |
-
gray_collarette = cv2.cvtColor(
|
179 |
non_zero = gray_collarette[gray_collarette != 0]
|
180 |
|
181 |
if len(non_zero) > 0:
|
|
|
|
|
|
|
182 |
return {
|
183 |
"intensidade_media": np.mean(non_zero),
|
184 |
"variacao": np.std(non_zero),
|
185 |
-
"
|
|
|
|
|
|
|
186 |
}
|
187 |
|
188 |
return None
|
189 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
190 |
def criar_interface():
|
191 |
"""
|
192 |
-
Cria interface do Gradio
|
193 |
"""
|
194 |
theme = gr.themes.Soft(
|
195 |
primary_hue="teal",
|
@@ -204,70 +248,100 @@ def criar_interface():
|
|
204 |
)
|
205 |
|
206 |
def processar_imagem(imagem):
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
if pupila_info is None or iris_info is None:
|
211 |
-
return output_img, "Não foi possível detectar pupila ou íris corretamente."
|
212 |
-
|
213 |
-
# Extrair características
|
214 |
-
caracteristicas = extrair_caracteristicas_avancadas(imagem, pupila_info, iris_info)
|
215 |
-
|
216 |
-
# Analisar collarette
|
217 |
-
collarette_info = analisar_padrao_collarette(imagem, pupila_info, iris_info)
|
218 |
-
|
219 |
-
# Gerar relatório
|
220 |
-
relatorio = "ANÁLISE IRIDOLÓGICA DETALHADA\n\n"
|
221 |
-
|
222 |
-
# Informações da pupila
|
223 |
-
px, py, pr = pupila_info
|
224 |
-
relatorio += f"Pupila:\n"
|
225 |
-
relatorio += f"- Centro: ({px}, {py})\n"
|
226 |
-
relatorio += f"- Raio: {pr}px\n"
|
227 |
-
|
228 |
-
# Informações da íris
|
229 |
-
ix, iy, ir = iris_info
|
230 |
-
relatorio += f"\nÍris:\n"
|
231 |
-
relatorio += f"- Centro: ({ix}, {iy})\n"
|
232 |
-
relatorio += f"- Raio: {ir}px\n"
|
233 |
-
|
234 |
-
# Análise por setores
|
235 |
-
relatorio += "\nAnálise por Setores:\n"
|
236 |
-
for setor, dados in caracteristicas.items():
|
237 |
-
relatorio += f"\n{setor.title()}:\n"
|
238 |
-
relatorio += f"- Intensidade média: {dados['media']:.1f}\n"
|
239 |
-
relatorio += f"- Variação: {dados['std']:.1f}\n"
|
240 |
|
241 |
-
#
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
256 |
|
257 |
# Interface
|
258 |
with gr.Blocks(theme=theme, title="Análise Iridológica Avançada") as interface:
|
259 |
gr.Markdown("""
|
260 |
# Sistema Avançado de Análise Iridológica
|
261 |
-
### Detecção precisa de
|
262 |
""")
|
263 |
|
264 |
with gr.Tabs():
|
265 |
-
# Aba de Análise
|
266 |
with gr.Tab("Análise de Imagem"):
|
267 |
with gr.Row():
|
268 |
with gr.Column():
|
269 |
input_image = gr.Image(
|
270 |
-
label="Imagem
|
271 |
type="numpy"
|
272 |
)
|
273 |
with gr.Column():
|
@@ -275,10 +349,10 @@ def criar_interface():
|
|
275 |
label="Análise Visual"
|
276 |
)
|
277 |
|
278 |
-
analysis_btn = gr.Button("Analisar
|
279 |
output_text = gr.Textbox(
|
280 |
label="Relatório de Análise",
|
281 |
-
lines=
|
282 |
)
|
283 |
|
284 |
analysis_btn.click(
|
@@ -287,36 +361,97 @@ def criar_interface():
|
|
287 |
outputs=[output_image, output_text]
|
288 |
)
|
289 |
|
290 |
-
# Aba de
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
291 |
with gr.Tab("Guia de Captura"):
|
292 |
gr.Markdown("""
|
293 |
## Guia para Captura de Imagem
|
294 |
|
295 |
-
###
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
|
301 |
-
2.
|
302 |
-
|
303 |
-
|
304 |
-
|
|
|
305 |
|
306 |
-
3.
|
307 |
-
|
308 |
-
|
309 |
-
|
|
|
310 |
|
311 |
-
###
|
312 |
-
-
|
313 |
-
-
|
314 |
-
-
|
315 |
-
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
316 |
""")
|
317 |
|
318 |
return interface
|
319 |
|
320 |
-
|
321 |
interface = criar_interface()
|
322 |
-
interface.launch(share=True)
|
|
|
|
|
|
|
|
4 |
from PIL import Image
|
5 |
import io
|
6 |
from collections import defaultdict
|
7 |
+
from scipy import ndimage
|
8 |
|
9 |
+
def pre_processar_imagem(imagem):
|
10 |
"""
|
11 |
+
Pré-processamento avançado da imagem
|
12 |
"""
|
13 |
+
# Converter para LAB para melhor separação de cores
|
14 |
lab = cv2.cvtColor(imagem, cv2.COLOR_RGB2LAB)
|
15 |
l, a, b = cv2.split(lab)
|
16 |
+
|
17 |
+
# Aplicar CLAHE no canal L
|
18 |
clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8,8))
|
19 |
l = clahe.apply(l)
|
20 |
+
|
21 |
+
# Recombinar canais
|
22 |
lab = cv2.merge((l,a,b))
|
23 |
+
|
24 |
+
# Converter de volta para RGB
|
25 |
+
imagem_melhorada = cv2.cvtColor(lab, cv2.COLOR_LAB2RGB)
|
26 |
+
|
27 |
+
# Redução de ruído
|
28 |
+
imagem_melhorada = cv2.GaussianBlur(imagem_melhorada, (5, 5), 0)
|
29 |
+
|
30 |
+
return imagem_melhorada
|
31 |
|
32 |
+
def detectar_esclera(imagem):
|
33 |
"""
|
34 |
+
Detecta a região da esclera usando segmentação por cor e morfologia
|
35 |
"""
|
36 |
+
# Converter para HSV
|
37 |
+
hsv = cv2.cvtColor(imagem, cv2.COLOR_RGB2HSV)
|
38 |
|
39 |
+
# Definir faixa de cor para branco (esclera)
|
40 |
+
lower_white = np.array([0, 0, 180])
|
41 |
+
upper_white = np.array([180, 30, 255])
|
42 |
|
43 |
+
# Criar máscara
|
44 |
+
mask_esclera = cv2.inRange(hsv, lower_white, upper_white)
|
45 |
|
46 |
+
# Operações morfológicas para limpar
|
47 |
+
kernel = np.ones((5,5), np.uint8)
|
48 |
+
mask_esclera = cv2.morphologyEx(mask_esclera, cv2.MORPH_OPEN, kernel)
|
49 |
+
mask_esclera = cv2.morphologyEx(mask_esclera, cv2.MORPH_CLOSE, kernel)
|
50 |
+
|
51 |
+
return mask_esclera
|
52 |
+
|
53 |
+
def detectar_iris_pupila(imagem, mask_esclera):
|
54 |
+
"""
|
55 |
+
Detecta íris e pupila usando múltiplas técnicas
|
56 |
+
"""
|
57 |
+
# Converter para escala de cinza
|
58 |
+
gray = cv2.cvtColor(imagem, cv2.COLOR_RGB2GRAY)
|
59 |
|
60 |
+
# Aplicar máscara da esclera invertida
|
61 |
+
mask_olho = cv2.bitwise_not(mask_esclera)
|
62 |
+
eye_region = cv2.bitwise_and(gray, gray, mask=mask_olho)
|
63 |
|
64 |
+
# Detectar bordas
|
65 |
+
edges = cv2.Canny(eye_region, 30, 60)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
66 |
|
67 |
+
# Detectar círculos para íris
|
68 |
iris_circles = cv2.HoughCircles(
|
69 |
+
edges,
|
70 |
cv2.HOUGH_GRADIENT,
|
71 |
dp=1,
|
72 |
minDist=100,
|
|
|
76 |
maxRadius=150
|
77 |
)
|
78 |
|
79 |
+
# Criar máscara da íris
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
80 |
if iris_circles is not None:
|
81 |
iris_circles = np.uint16(np.around(iris_circles))
|
82 |
+
ix, iy, ir = iris_circles[0][0]
|
83 |
+
mask_iris = np.zeros_like(gray)
|
84 |
+
cv2.circle(mask_iris, (ix, iy), ir, 255, -1)
|
85 |
+
|
86 |
+
# Região dentro da íris para detecção da pupila
|
87 |
+
iris_region = cv2.bitwise_and(gray, gray, mask=mask_iris)
|
88 |
+
|
89 |
+
# Threshold adaptativo para pupila
|
90 |
+
thresh = cv2.adaptiveThreshold(
|
91 |
+
iris_region,
|
92 |
+
255,
|
93 |
+
cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
|
94 |
+
cv2.THRESH_BINARY_INV,
|
95 |
+
11,
|
96 |
+
2
|
97 |
+
)
|
98 |
+
|
99 |
+
# Detectar pupila
|
100 |
+
pupil_circles = cv2.HoughCircles(
|
101 |
+
thresh,
|
102 |
+
cv2.HOUGH_GRADIENT,
|
103 |
+
dp=1,
|
104 |
+
minDist=50,
|
105 |
+
param1=50,
|
106 |
+
param2=25,
|
107 |
+
minRadius=20,
|
108 |
+
maxRadius=50
|
109 |
+
)
|
110 |
+
|
111 |
+
if pupil_circles is not None:
|
112 |
+
pupil_circles = np.uint16(np.around(pupil_circles))
|
113 |
+
px, py, pr = pupil_circles[0][0]
|
114 |
+
return (ix, iy, ir), (px, py, pr)
|
115 |
|
116 |
+
return None, None
|
117 |
|
118 |
+
def analisar_textura_setorial(imagem, iris_info, pupil_info):
|
119 |
"""
|
120 |
+
Analisa a textura da íris por setores
|
121 |
"""
|
122 |
+
if iris_info is None or pupil_info is None:
|
123 |
return {}
|
124 |
|
|
|
|
|
|
|
|
|
|
|
125 |
ix, iy, ir = iris_info
|
126 |
+
px, py, pr = pupil_info
|
127 |
|
128 |
+
# Converter para escala de cinza
|
129 |
+
gray = cv2.cvtColor(imagem, cv2.COLOR_RGB2GRAY)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
130 |
|
131 |
+
# Criar máscara anelar da íris
|
132 |
+
mask_iris = np.zeros_like(gray)
|
133 |
+
cv2.circle(mask_iris, (ix, iy), ir, 255, -1)
|
134 |
+
cv2.circle(mask_iris, (px, py), pr, 0, -1)
|
|
|
|
|
|
|
135 |
|
136 |
+
# Dividir em 12 setores (como um relógio)
|
137 |
+
setores = {}
|
138 |
+
for i in range(12):
|
139 |
+
ang_inicio = i * 30
|
140 |
+
ang_fim = (i + 1) * 30
|
141 |
+
|
142 |
# Criar máscara do setor
|
143 |
+
mask_setor = np.zeros_like(gray)
|
144 |
+
cv2.ellipse(mask_setor,
|
145 |
(ix, iy),
|
146 |
(ir, ir),
|
147 |
0,
|
|
|
150 |
255,
|
151 |
-1)
|
152 |
|
153 |
+
# Combinar máscaras
|
154 |
+
mask_final = cv2.bitwise_and(mask_iris, mask_setor)
|
155 |
|
156 |
+
# Extrair região do setor
|
157 |
+
setor_roi = cv2.bitwise_and(gray, gray, mask=mask_final)
|
158 |
+
|
159 |
+
# Análise de textura
|
160 |
non_zero = setor_roi[setor_roi != 0]
|
161 |
if len(non_zero) > 0:
|
162 |
+
# Calcular características de textura
|
163 |
+
glcm = graycomatrix(non_zero.reshape(-1, 1), [1], [0], symmetric=True, normed=True)
|
164 |
+
|
165 |
+
setores[f"setor_{i+1}"] = {
|
166 |
"media": np.mean(non_zero),
|
167 |
"std": np.std(non_zero),
|
168 |
+
"contraste": graycoprops(glcm, 'contrast')[0, 0],
|
169 |
+
"homogeneidade": graycoprops(glcm, 'homogeneity')[0, 0],
|
170 |
+
"energia": graycoprops(glcm, 'energy')[0, 0],
|
171 |
+
"correlacao": graycoprops(glcm, 'correlation')[0, 0]
|
172 |
}
|
173 |
|
174 |
+
return setores
|
175 |
|
176 |
+
def analisar_collarette(imagem, iris_info, pupil_info):
|
177 |
"""
|
178 |
+
Analisa o collarette (anel de contração) em detalhes
|
179 |
"""
|
180 |
+
if iris_info is None or pupil_info is None:
|
181 |
return None
|
182 |
|
|
|
183 |
ix, iy, ir = iris_info
|
184 |
+
px, py, pr = pupil_info
|
185 |
|
186 |
+
# Distância entre pupila e íris
|
187 |
+
dist = ir - pr
|
188 |
|
189 |
+
# Região do collarette (aproximadamente 35% da distância)
|
190 |
+
collarette_inner = pr + int(dist * 0.25)
|
191 |
+
collarette_outer = pr + int(dist * 0.45)
|
192 |
+
|
193 |
+
# Criar máscara do collarette
|
194 |
mask = np.zeros_like(cv2.cvtColor(imagem, cv2.COLOR_RGB2GRAY))
|
195 |
+
cv2.circle(mask, (px, py), collarette_outer, 255, -1)
|
196 |
+
cv2.circle(mask, (px, py), collarette_inner, 0, -1)
|
197 |
|
198 |
+
# Extrair região do collarette
|
199 |
+
collarette_region = cv2.bitwise_and(imagem, imagem, mask=mask)
|
200 |
|
201 |
+
# Análise detalhada
|
202 |
+
gray_collarette = cv2.cvtColor(collarette_region, cv2.COLOR_RGB2GRAY)
|
203 |
non_zero = gray_collarette[gray_collarette != 0]
|
204 |
|
205 |
if len(non_zero) > 0:
|
206 |
+
# Calcular características
|
207 |
+
glcm = graycomatrix(non_zero.reshape(-1, 1), [1], [0], symmetric=True, normed=True)
|
208 |
+
|
209 |
return {
|
210 |
"intensidade_media": np.mean(non_zero),
|
211 |
"variacao": np.std(non_zero),
|
212 |
+
"contraste": graycoprops(glcm, 'contrast')[0, 0],
|
213 |
+
"homogeneidade": graycoprops(glcm, 'homogeneity')[0, 0],
|
214 |
+
"regularidade": cv2.Laplacian(gray_collarette, cv2.CV_64F).var(),
|
215 |
+
"circularidade": avaliar_circularidade(mask)
|
216 |
}
|
217 |
|
218 |
return None
|
219 |
|
220 |
+
def avaliar_circularidade(mask):
|
221 |
+
"""
|
222 |
+
Avalia a circularidade de uma região
|
223 |
+
"""
|
224 |
+
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
225 |
+
if contours:
|
226 |
+
cnt = max(contours, key=cv2.contourArea)
|
227 |
+
area = cv2.contourArea(cnt)
|
228 |
+
perimeter = cv2.arcLength(cnt, True)
|
229 |
+
if perimeter > 0:
|
230 |
+
circularity = 4 * np.pi * area / (perimeter * perimeter)
|
231 |
+
return circularity
|
232 |
+
return 0
|
233 |
+
|
234 |
def criar_interface():
|
235 |
"""
|
236 |
+
Cria interface moderna do Gradio
|
237 |
"""
|
238 |
theme = gr.themes.Soft(
|
239 |
primary_hue="teal",
|
|
|
248 |
)
|
249 |
|
250 |
def processar_imagem(imagem):
|
251 |
+
try:
|
252 |
+
# Pré-processamento
|
253 |
+
imagem_processada = pre_processar_imagem(imagem)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
254 |
|
255 |
+
# Detectar esclera
|
256 |
+
mask_esclera = detectar_esclera(imagem_processada)
|
257 |
+
|
258 |
+
# Detectar íris e pupila
|
259 |
+
iris_info, pupil_info = detectar_iris_pupila(imagem_processada, mask_esclera)
|
260 |
+
|
261 |
+
if iris_info is None or pupil_info is None:
|
262 |
+
return imagem, "Não foi possível detectar íris ou pupila corretamente."
|
263 |
+
|
264 |
+
# Análise de textura
|
265 |
+
analise_setorial = analisar_textura_setorial(imagem_processada, iris_info, pupil_info)
|
266 |
+
|
267 |
+
# Análise do collarette
|
268 |
+
info_collarette = analisar_collarette(imagem_processada, iris_info, pupil_info)
|
269 |
+
|
270 |
+
# Criar visualização
|
271 |
+
output_img = imagem.copy()
|
272 |
+
|
273 |
+
# Desenhar esclera
|
274 |
+
contours, _ = cv2.findContours(mask_esclera, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
275 |
+
cv2.drawContours(output_img, contours, -1, (255, 255, 0), 1)
|
276 |
+
|
277 |
+
# Desenhar íris
|
278 |
+
ix, iy, ir = iris_info
|
279 |
+
cv2.circle(output_img, (ix, iy), ir, (0, 255, 0), 2)
|
280 |
+
|
281 |
+
# Desenhar pupila
|
282 |
+
px, py, pr = pupil_info
|
283 |
+
cv2.circle(output_img, (px, py), pr, (255, 0, 0), 2)
|
284 |
+
|
285 |
+
# Desenhar setores
|
286 |
+
for i in range(12):
|
287 |
+
ang = i * 30
|
288 |
+
rad = np.radians(ang)
|
289 |
+
end_x = int(ix + ir * np.cos(rad))
|
290 |
+
end_y = int(iy + ir * np.sin(rad))
|
291 |
+
cv2.line(output_img, (ix, iy), (end_x, end_y), (0, 255, 0), 1)
|
292 |
+
|
293 |
+
# Gerar relatório
|
294 |
+
relatorio = "ANÁLISE IRIDOLÓGICA DETALHADA\n\n"
|
295 |
+
|
296 |
+
# Informações estruturais
|
297 |
+
relatorio += "1. MEDIDAS ESTRUTURAIS\n"
|
298 |
+
relatorio += f"Pupila: Centro ({px}, {py}), Raio {pr}px\n"
|
299 |
+
relatorio += f"Íris: Centro ({ix}, {iy}), Raio {ir}px\n"
|
300 |
+
|
301 |
+
# Análise setorial
|
302 |
+
relatorio += "\n2. ANÁLISE SETORIAL\n"
|
303 |
+
for setor, dados in analise_setorial.items():
|
304 |
+
relatorio += f"\n{setor}:\n"
|
305 |
+
relatorio += f"- Contraste: {dados['contraste']:.2f}\n"
|
306 |
+
relatorio += f"- Homogeneidade: {dados['homogeneidade']:.2f}\n"
|
307 |
+
|
308 |
+
# Interpretação
|
309 |
+
if dados['contraste'] > 2.0:
|
310 |
+
relatorio += " * Alta densidade de sinais\n"
|
311 |
+
if dados['homogeneidade'] < 0.5:
|
312 |
+
relatorio += " * Possível área de alteração\n"
|
313 |
+
|
314 |
+
# Análise do collarette
|
315 |
+
if info_collarette:
|
316 |
+
relatorio += "\n3. ANÁLISE DO COLLARETTE\n"
|
317 |
+
relatorio += f"- Regularidade: {info_collarette['regularidade']:.2f}\n"
|
318 |
+
relatorio += f"- Circularidade: {info_collarette['circularidade']:.2f}\n"
|
319 |
+
|
320 |
+
# Interpretação
|
321 |
+
if info_collarette['regularidade'] > 500:
|
322 |
+
relatorio += " * Irregularidade significativa\n"
|
323 |
+
if info_collarette['circularidade'] < 0.8:
|
324 |
+
relatorio += " * Possível deformação estrutural\n"
|
325 |
+
|
326 |
+
return output_img, relatorio
|
327 |
+
|
328 |
+
except Exception as e:
|
329 |
+
return imagem, f"Erro durante o processamento: {str(e)}"
|
330 |
|
331 |
# Interface
|
332 |
with gr.Blocks(theme=theme, title="Análise Iridológica Avançada") as interface:
|
333 |
gr.Markdown("""
|
334 |
# Sistema Avançado de Análise Iridológica
|
335 |
+
### Detecção precisa de esclera, íris e pupila com análise setorial
|
336 |
""")
|
337 |
|
338 |
with gr.Tabs():
|
339 |
+
# Aba de Análise Principal
|
340 |
with gr.Tab("Análise de Imagem"):
|
341 |
with gr.Row():
|
342 |
with gr.Column():
|
343 |
input_image = gr.Image(
|
344 |
+
label="Imagem do Olho",
|
345 |
type="numpy"
|
346 |
)
|
347 |
with gr.Column():
|
|
|
349 |
label="Análise Visual"
|
350 |
)
|
351 |
|
352 |
+
analysis_btn = gr.Button("Analisar Olho", variant="primary")
|
353 |
output_text = gr.Textbox(
|
354 |
label="Relatório de Análise",
|
355 |
+
lines=20
|
356 |
)
|
357 |
|
358 |
analysis_btn.click(
|
|
|
361 |
outputs=[output_image, output_text]
|
362 |
)
|
363 |
|
364 |
+
# Aba de Configurações
|
365 |
+
with gr.Tab("Configurações"):
|
366 |
+
with gr.Row():
|
367 |
+
min_iris_radius = gr.Slider(
|
368 |
+
minimum=60,
|
369 |
+
maximum=200,
|
370 |
+
value=80,
|
371 |
+
label="Raio Mínimo da Íris (px)"
|
372 |
+
)
|
373 |
+
max_iris_radius = gr.Slider(
|
374 |
+
minimum=100,
|
375 |
+
maximum=250,
|
376 |
+
value=150,
|
377 |
+
label="Raio Máximo da Íris (px)"
|
378 |
+
)
|
379 |
+
|
380 |
+
with gr.Row():
|
381 |
+
min_pupil_radius = gr.Slider(
|
382 |
+
minimum=15,
|
383 |
+
maximum=70,
|
384 |
+
value=20,
|
385 |
+
label="Raio Mínimo da Pupila (px)"
|
386 |
+
)
|
387 |
+
max_pupil_radius = gr.Slider(
|
388 |
+
minimum=30,
|
389 |
+
maximum=100,
|
390 |
+
value=50,
|
391 |
+
label="Raio Máximo da Pupila (px)"
|
392 |
+
)
|
393 |
+
|
394 |
+
# Aba de Guia de Captura
|
395 |
with gr.Tab("Guia de Captura"):
|
396 |
gr.Markdown("""
|
397 |
## Guia para Captura de Imagem
|
398 |
|
399 |
+
### 1. Iluminação Ideal
|
400 |
+
- Luz natural indireta
|
401 |
+
- Sem reflexos diretos no olho
|
402 |
+
- Iluminação uniforme
|
403 |
+
- Evitar flash
|
404 |
|
405 |
+
### 2. Posicionamento
|
406 |
+
- Olho totalmente aberto
|
407 |
+
- Câmera perpendicular ao olho
|
408 |
+
- Distância adequada (15-20cm)
|
409 |
+
- Íris centralizada na imagem
|
410 |
|
411 |
+
### 3. Qualidade da Imagem
|
412 |
+
- Resolução mínima: 1280x720
|
413 |
+
- Foco perfeito na íris
|
414 |
+
- Sem movimento/tremor
|
415 |
+
- Imagem nítida e clara
|
416 |
|
417 |
+
### 4. Preparação
|
418 |
+
- Limpar a lente da câmera
|
419 |
+
- Olho descansado
|
420 |
+
- Ambiente calmo
|
421 |
+
- Múltiplas capturas
|
422 |
+
""")
|
423 |
+
|
424 |
+
# Aba de Interpretação
|
425 |
+
with gr.Tab("Guia de Interpretação"):
|
426 |
+
gr.Markdown("""
|
427 |
+
## Guia de Interpretação dos Resultados
|
428 |
+
|
429 |
+
### 1. Análise da Pupila
|
430 |
+
- **Tamanho**: Indica atividade do sistema nervoso
|
431 |
+
- **Forma**: Regular ou irregular
|
432 |
+
- **Posição**: Centralizada ou deslocada
|
433 |
+
|
434 |
+
### 2. Análise da Íris
|
435 |
+
- **Densidade**: Integridade do tecido
|
436 |
+
- **Coloração**: Atividade metabólica
|
437 |
+
- **Textura**: Estado geral dos tecidos
|
438 |
+
|
439 |
+
### 3. Sinais Específicos
|
440 |
+
- **Lacunas**: Possíveis deficiências
|
441 |
+
- **Manchas**: Toxicidade ou inflamação
|
442 |
+
- **Anéis**: Tensão ou congestão
|
443 |
+
|
444 |
+
### 4. Collarette
|
445 |
+
- **Regularidade**: Equilíbrio do sistema
|
446 |
+
- **Circularidade**: Integridade estrutural
|
447 |
+
- **Densidade**: Vitalidade geral
|
448 |
""")
|
449 |
|
450 |
return interface
|
451 |
|
452 |
+
def main():
|
453 |
interface = criar_interface()
|
454 |
+
interface.launch(share=True)
|
455 |
+
|
456 |
+
if __name__ == "__main__":
|
457 |
+
main()
|