-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdetector_marcadores.py
104 lines (92 loc) · 5.75 KB
/
detector_marcadores.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
import numpy as np
import cv2
def obtener_firma_bits(imagen, pts_contorno, umbral=127):
# Obtención de los 4 vértices del cuadrilátero
x1, y1 = pts_contorno[0][0] # Coordenadas del primer vértice
x2, y2 = pts_contorno[1][0] # Coordenadas del segundo vértice
x3, y3 = pts_contorno[2][0] # Coordenadas del tercer vértice
x4, y4 = pts_contorno[3][0] # Coordenadas del cuarto vértice
firma_bits = []
for i in range(8): # Iterar sobre las filas (eje y) del cuadrilátero
for j in range(8): # Iterar sobre las columnas (eje x) del cuadrilátero
# Utilizando interpolación bilineal para encontrar la coordenada usando contribuciones fraccionales de los 4 vértices del cuadrilátero
fraccion1 = float(i) / 8 + 1. / 16
fraccion2 = float(j) / 8 + 1. / 16
# Encontrando las coordenadas intermedias mediante la interpolación bilineal
x_superior = (1 - fraccion1) * x1 + fraccion1 * x2 # Coordenada x del punto superior
x_inferior = (1 - fraccion1) * x4 + fraccion1 * x3 # Coordenada x del punto inferior
y_superior = (1 - fraccion1) * y1 + fraccion1 * y2 # Coordenada y del punto superior
y_inferior = (1 - fraccion1) * y4 + fraccion1 * y3 # Coordenada y del punto inferior
x_interpolado = int((1 - fraccion2) * x_superior + (fraccion2) * x_inferior) # Coordenada x interpolada
y_interpolado = int((1 - fraccion2) * y_superior + (fraccion2) * y_inferior) # Coordenada y interpolada
# Umbralización: si el valor de píxel es mayor o igual al umbral, se asigna 1, de lo contrario 0
if imagen[y_interpolado][x_interpolado] >= umbral:
firma_bits.append(1)
else:
firma_bits.append(0)
return firma_bits
def coincidir_firmas(firma1, firma2, umbral=62):
# Calcula la cantidad de bits coincidentes entre las dos firmas
coincidencias = sum([ (1- abs(a - b)) for a, b in zip(firma1, firma2)])
# Comprueba si la cantidad de coincidencias supera el umbral especificado
return coincidencias >= umbral
def encontrar_marcador_aruco(imagen, marcador_aruco, firmas):
# Convierte la imagen a escala de grises
gris = cv2.cvtColor(imagen, cv2.COLOR_BGR2GRAY)
# Aplica umbral adaptativo para manejar cambios en la iluminación
umbralizado = cv2.adaptiveThreshold(gris, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 10)
# Obtiene las dimensiones del marcador ArUco
alto_marcador, ancho_marcador = marcador_aruco.shape
# Encuentra los contornos en la imagen umbralizada
contornos, _ = cv2.findContours(umbralizado, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# Itera sobre los contornos encontrados
for contorno in contornos:
# Aproxima el contorno para obtener un polígono
contorno_aproximado = cv2.approxPolyDP(contorno, 0.01 * cv2.arcLength(contorno, True), True)
# Verifica si el polígono tiene 4 lados
if contorno_aproximado.shape[0] == 4:
x1 = contorno_aproximado[0][0][0]
x2 = contorno_aproximado[1][0][0]
y1 = contorno_aproximado[0][0][1]
y2 = contorno_aproximado[1][0][1]
# Calcula la distancia entre dos puntos del polígono
distancia = (x1 - x2) ** 2 + (y1 - y2) ** 2
# Restricción sobre el tamaño mínimo de los bordes del cuadrilátero
if distancia > 100:
# Calcula la firma del contorno
firma_aux = obtener_firma_bits(gris, contorno_aproximado)
# Comprueba si la firma coincide con alguna de las firmas conocidas
coincide1 = coincidir_firmas(firmas[0], firma_aux)
coincide2 = coincidir_firmas(firmas[1], firma_aux)
coincide3 = coincidir_firmas(firmas[2], firma_aux)
coincide4 = coincidir_firmas(firmas[3], firma_aux)
if coincide1 or coincide2 or coincide3 or coincide4:
# Puntos de destino corresponden al contorno del marcador
puntos_destino = contorno_aproximado
# Asigna los puntos de origen según la coincidencia con las firmas
if coincide1:
puntos_origen = np.array([[0, 0], [0, ancho_marcador], [alto_marcador, ancho_marcador], [alto_marcador, 0]])
if coincide2:
puntos_origen = np.array([[0, ancho_marcador], [alto_marcador, ancho_marcador], [alto_marcador, 0], [0, 0]])
if coincide3:
puntos_origen = np.array([[alto_marcador, ancho_marcador], [alto_marcador, 0], [0, 0], [0, ancho_marcador]])
if coincide4:
puntos_origen = np.array([[alto_marcador, 0], [0, 0], [0, ancho_marcador], [alto_marcador, ancho_marcador]])
return puntos_origen, puntos_destino, True
# No se encontró ningún marcador ArUco
return None, None, False
def encontrar_homografia_aruco(imagen, marcador_aruco, firmas):
# Encuentra los puntos de origen y destino del marcador ArUco
puntos_origen, puntos_destino, encontrado = encontrar_marcador_aruco(imagen, marcador_aruco, firmas)
# Inicializa la matriz de homografía como None
homografia = None
# Si se encontró el marcador ArUco
if encontrado:
# Calcula la homografía entre los puntos de origen y destino
homografia, mask = cv2.findHomography(puntos_origen.reshape(-1, 1, 2), puntos_destino.reshape(-1, 1, 2), cv2.RANSAC, 5.0)
# Si no se encontró una homografía válida, devuelve False y None
if homografia is None:
return False, None
else:
# Si se encontró una homografía válida, devuelve True y la homografía calculada
return True, homografia