¡Hola, Habr! En este artículo, me gustaría decirte cómo reconocer objetos usando solo OpenCV, usando naipes como ejemplo:
Introducción
Digamos que tenemos la siguiente imagen con mapas:
También tenemos imágenes de referencia para cada tarjeta:
Y ahora, para detectar cada tarjeta, necesitamos escribir tres funciones clave, que:
- encuentra los contornos de todos los mapas;
- encuentra las coordenadas de cada mapa individual;
- reconoce el mapa utilizando puntos clave.
Encontrar contornos de mapas
def find_contours_of_cards(image):
blurred = cv2.GaussianBlur(image, (3, 3), 0)
T, thresh_img = cv2.threshold(blurred, 215, 255,
cv2.THRESH_BINARY)
(_, cnts, _) = cv2.findContours(thresh_img,
cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
return cnts
, , , . threshold() . , — , — , , . , , 215, 255, , 215, . . THRESH_BINARY(), , , 215 , . , — , , — - , :
, — , , . findContours(), , — , . cv2.RETR_EXTERNAL . , , cv2.RETR_LIST, . cv2.CHAIN_APPROX_SIMPLE, , , . , , , ? , . , cv2.CHAIN_APPROX_SIMPLE.
def find_coordinates_of_cards(cnts, image):
cards_coordinates = {}
for i in range(0, len(cnts)):
x, y, w, h = cv2.boundingRect(cnts[i])
if w > 20 and h > 30:
img_crop = image[y - 15:y + h + 15,
x - 15:x + w + 15]
cards_name = find_features(img_crop)
cards_coordinates[cards_name] = (x - 15,
y - 15, x + w + 15, y + h + 15)
return cards_coordinates
, , . , , . , boundingRect() : x y , . , , , 31 , 4. , , .
, , , . find_features()( ), , . .
, . — . , . , , . , , - . , :
:
, . , . :
def find_features(img1):
correct_matches_dct = {}
directory = 'images/cards/sample/'
for image in os.listdir(directory):
img2 = cv2.imread(directory+image, 0)
orb = cv2.ORB_create()
kp1, des1 = orb.detectAndCompute(img1, None)
kp2, des2 = orb.detectAndCompute(img2, None)
bf = cv2.BFMatcher()
matches = bf.knnMatch(des1, des2, k=2)
correct_matches = []
for m, n in matches:
if m.distance < 0.75*n.distance:
correct_matches.append([m])
correct_matches_dct[image.split('.')[0]]
= len(correct_matches)
correct_matches_dct =
dict(sorted(correct_matches_dct.items(),
key=lambda item: item[1], reverse=True))
return list(correct_matches_dct.keys())[0]
ORB, ORB_create(), ( ) , . , , :
( ) . BFMatcher BFMatcher(). knnMatch() k , k 2. , . m.distance < 0.75*n.distance, . ( , ) , . :
Y luego dibuja un rectángulo alrededor de la tarjeta usando la función draw_rectangle_aroud_cards ():
def draw_rectangle_aroud_cards(cards_coordinates, image):
for key, value in cards_coordinates.items():
rec = cv2.rectangle(image, (value[0], value[1]),
(value[2], value[3]),
(255, 255, 0), 2)
cv2.putText(rec, key, (value[0], value[1] - 10),
cv2.FONT_HERSHEY_SIMPLEX,
0.5, (36, 255, 12), 1)
cv2.imshow('Image', image)
cv2.waitKey(0)
Eso es todo. Espero que haya sido informativo) El código y las imágenes se pueden encontrar en github . Hasta la proxima vez :)