-
Notifications
You must be signed in to change notification settings - Fork 0
/
ej1.py
214 lines (160 loc) · 7.89 KB
/
ej1.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
import cv2
import numpy as np
import matplotlib.pyplot as plt
#Funcion para mostrar la imagen
def imshow(img, new_fig=True, title=None, color_img=False, blocking=False, colorbar=True, ticks=False):
if new_fig:
plt.figure()
if color_img:
plt.imshow(img)
else:
plt.imshow(img, cmap='gray')
plt.title(title)
if not ticks:
plt.xticks([]), plt.yticks([])
if colorbar:
plt.colorbar()
if new_fig:
plt.show(block=blocking)
#Vemos la imagen en escala de grises
f = cv2.imread('monedas.jpg', cv2.IMREAD_GRAYSCALE)
#Filtro pasa bajo
w1 = np.ones((2,2))/(2*2)
img1 = cv2.filter2D(f,-1,w1)
#Canny
f_blur = cv2.GaussianBlur(img1, ksize=(7, 7), sigmaX=1)
gcan = cv2.Canny(f_blur, threshold1=0.12*255, threshold2=0.62*255)
#Dilatamos
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (36,36))
Fd = cv2.dilate(gcan, kernel, iterations=1)
#Reconstrucción Morgológica
def imreconstruct(marker, mask, kernel=None):
if kernel==None:
kernel = np.ones((3,3), np.uint8)
while True:
expanded = cv2.dilate(marker, kernel) # Dilatacion
expanded_intersection = cv2.bitwise_and(src1=expanded, src2=mask) # Interseccion
if (marker == expanded_intersection).all(): # Finalizacion?
break #
marker = expanded_intersection
return expanded_intersection
#Rellenamos
def imfillhole(img):
# img: Imagen binaria de entrada. Valores permitidos: 0 (False), 255 (True).
mask = np.zeros_like(img) # Genero mascara para...
mask = cv2.copyMakeBorder(mask[1:-1,1:-1], 1, 1, 1, 1, cv2.BORDER_CONSTANT, value=int(255)) # ... seleccionar los bordes.
marker = cv2.bitwise_not(img, mask=mask) # El marcador lo defino como el complemento de los bordes.
img_c = cv2.bitwise_not(img) # La mascara la defino como el complemento de la imagen.
img_r = imreconstruct(marker=marker, mask=img_c) # Calculo la reconstrucción R_{f^c}(f_m)
img_fh = cv2.bitwise_not(img_r) # La imagen con sus huecos rellenos es igual al complemento de la reconstruccion.
return img_fh
#Rellenamos huecos de nuestra imagen
Fd = imfillhole(Fd)
#Apertura
B = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (50, 50))
Aop = cv2.morphologyEx(Fd, cv2.MORPH_OPEN, B)
#Componentes Conectadas
num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(Aop)
labels_color = np.uint8(255/(num_labels-1)*labels) # Llevo el rango de valores a [0 255] para diferenciar mejor los colores
im_color = cv2.applyColorMap(labels_color, cv2.COLORMAP_JET)
im_color = cv2.cvtColor(im_color, cv2.COLOR_BGR2RGB) # El mapa de color que se aplica está en BGR --> convierto a RGB
# --- Defino parametros para la clasificación -------------------------------------------
aux = np.zeros_like(labels)
labeled_image = cv2.merge([aux, aux, aux])
moneda50, moneda1, moneda10 = 0,0,0
#Lista donde iremos almacenando los diccionarios con datos de las monedas y dados
lista_objetos = []
# --- Clasificación ---------------------------------------------------------------------
# Clasifico en base al factor de forma
for i in range(1, num_labels):
#Creamos diccionario para almacenar el objeto y sus datos
objeto_dicc = {}
# --- Selecciono el objeto actual -----------------------------------------
obj = (labels == i).astype(np.uint8)
# --- Calculo Rho ---------------------------------------------------------
ext_contours, _ = cv2.findContours(obj, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
area = cv2.contourArea(ext_contours[0])
perimeter = cv2.arcLength(ext_contours[0], True)
rho = 4 * np.pi * area/(perimeter**2)
fp = area / perimeter**2
area = stats[i, cv2.CC_STAT_AREA] // 1000
# Guardamos el objeto y su centroide
objeto_dicc['labels'] = obj
objeto_dicc['centroid'] = centroids[i]
# --- Clasificamos -----------------------------------------------------------
if 1/fp > 10 and 1/fp < 15:
objeto_dicc['clase'] = 'moneda'
if (area > 110):
labeled_image[obj == 1, 0] = 255 # moneda de 50 (Rojo)
moneda50 += 1
objeto_dicc['valor'] = '0.5'
elif (area < 110 and area > 100 ):
labeled_image[obj == 1, 1] = 255 # moneda de 1 (Verde)
moneda1 += 1
objeto_dicc['valor'] = '1'
else:
labeled_image[obj == 1, 2] = 255 # moneda de 10 (azul)
moneda10 += 1
objeto_dicc['valor'] = '0.1'
else:
labeled_image[obj == 1, 1] = 50 # dados (verde oscuro)
objeto_dicc['clase'] = 'dado'
lista_objetos.append(objeto_dicc)
#--------------------
# Identificar dados
#--------------------
# Hacer una máscara con solo los dados
dados = [dicc for dicc in lista_objetos if dicc['clase'] == 'dado']
#placeholder
labeled_image = np.zeros_like(labels)
for dado in dados:
numero_dado = 0
# Decidimos usar Canny para identificar cada punto. Umbralizar también es una opción
dado_canny = dado['labels'] * gcan
# Hacemos componentes conectadas para separar cada punto del dado
num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(dado_canny)
# Clasifico en base al factor de forma
for i in range(1, num_labels):
# --- Selecciono el objeto actual -----------------------------------------
obj = (labels == i).astype(np.uint8)
# --- Calculo Rho ---------------------------------------------------------
ext_contours, _ = cv2.findContours(obj, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
area = cv2.contourArea(ext_contours[0])
perimeter = cv2.arcLength(ext_contours[0], True)
rho = 4 * np.pi * area/(perimeter**2)
fp = area / perimeter**2
# Removemos el caso donde fp = 0, es decir, una componente conectada de un solo punto
if fp == 0:
continue
# Identificamos círculos y nos quedamos con aquellos más grandes (filtramos según área)
if 1/fp > 10 and 1/fp < 15 and stats[i][4] > 80:
labeled_image[obj == 1] = 255
# Contamos los puntos
numero_dado += 1
dado['valor'] = str(numero_dado)
# Graficamos los dados con su número y las monedas con su tipo
aux = np.zeros_like(labels)
labeled_image = cv2.merge([aux, aux, aux])
# Parámetros para el texto
font = cv2.FONT_HERSHEY_SIMPLEX
font_scale = 4
font_thickness = 15
font_color = (0, 0, 0)
delta = 70
for objeto in lista_objetos:
obj = (objeto['labels']).astype(np.uint8)
if objeto['clase'] == 'moneda':
if objeto['valor'] == '0.5':
labeled_image[obj == 1, 0] = 255 # moneda de 50
cv2.putText(labeled_image, objeto['valor'], (int(objeto['centroid'][0])-delta,int(objeto['centroid'][1])+delta), font, font_scale, font_color, font_thickness)
elif objeto['valor'] == '1':
labeled_image[obj == 1, 1] = 255 # moneda de 1
cv2.putText(labeled_image, objeto['valor'], (int(objeto['centroid'][0])-delta,int(objeto['centroid'][1])+delta), font, font_scale, font_color, font_thickness)
elif objeto['valor'] == '0.1':
labeled_image[obj == 1, 2] = 255 # moneda de 10
cv2.putText(labeled_image, objeto['valor'], (int(objeto['centroid'][0])-delta,int(objeto['centroid'][1])+delta), font, font_scale, font_color, font_thickness)
if objeto['clase'] == 'dado':
labeled_image[obj == 1, 1] = 50 # dado
cv2.putText(labeled_image, objeto['valor'], (int(objeto['centroid'][0])-delta,int(objeto['centroid'][1])+delta), font, font_scale, font_color, font_thickness)
plt.imshow(labeled_image)
plt.show()