Estimer la posture du marqueur AR avec Python + OpenCV + drone

introduction

C'est le premier message de Qiita. J'aimerais écrire une méthode très approximative pour les étudiants en ingénierie de l'information pour générer et détecter des marqueurs AR à l'aide de Python, OpenCV et des drones, et pour estimer leur posture.

J'ai fait référence à ce blog. https://qiita.com/ReoNagai/items/a8fdee89b1686ec31d10

la mise en oeuvre

Génération de marqueurs ArUco

Cette fois, nous utiliserons ArUco, une bibliothèque AR qui est l'un des modules OpenCV. Le marqueur ArUco peut être généré avec le code suivant.

generate.py


#!/usr/bin/env python
# -*- coding: utf-8 -*
import cv2
aruco = cv2.aruco
dir(aruco)

dictionary = aruco.getPredefinedDictionary(aruco.DICT_4X4_50)

marker = aruco.drawMarker(dictionary, 1, 300)
cv2.imwrite('id-001.png', marker)

50 types de marqueurs peuvent être générés avec aruco.DICT_4X4_50. Pour le moment, quand j'essaye d'en générer un, ça ressemble à ça. id-001.png

Il sera imprimé et collé sur le mur. Je l'ai utilisé pour suivre le drone, alors je l'ai collé à l'arrière du drone comme ça. IMG_3873.jpg

Détection de marqueurs ArUco

Lors de la détection depuis la caméra du drone

J'utilise AR.Drone 2.0 de parrot.

Parrot AR. Drone2.0, https://www.parrot.com/jp/doron/parrot-ardrone-20-power-edition (2020.4.22 access)

detect_drone.py


# -*- coding: utf-8 -*-
import numpy as np
import cv2 
import sys
from pyardrone import ARDrone
import logging

logging.basicConfig(level=logging.DEBUG)

client = ARDrone()
client.video_ready.wait()
cnt=0

aruco = cv2.aruco #bibliothèque aruco
dictionary = aruco.getPredefinedDictionary(aruco.DICT_4X4_50)

try:
    while True:
        cv2.imwrite('drone'+str(cnt)+'.png',client.frame)
        cnt+=1
        corners, ids, rejectedImgPoints = aruco.detectMarkers(client.frame, dictionary)    #Détecter le marqueur
        aruco.drawDetectedMarkers(client.frame, corners, ids, (0,255,0))   #Dessiner sur le marqueur détecté
        if cv2.waitKey(10) == ord(' '):
            break
finally:
    client.close()

Lorsque vous utilisez une caméra Web générale, etc.

detect_camera.py


# -*- coding: utf-8 -*-
import numpy as np
import cv2 
import sys
 
aruco = cv2.aruco #bibliothèque aruco
dictionary = aruco.getPredefinedDictionary(aruco.DICT_4X4_50)

def arReader(): 
    print(cv2.getBuildInformation())
    cap = cv2.VideoCapture(0)
    cnt=0

    while True:
 
        ret, frame = cap.read()
        if frame is None: break
 
        corners, ids, rejectedImgPoints = aruco.detectMarkers(frame, dictionary) #Détecter le marqueur
        print(corners,ids)
        aruco.drawDetectedMarkers(frame, corners, ids, (0,255,0)) #Dessiner sur le marqueur détecté

        cv2.imwrite('result'+str(cnt)+'.png',frame)
        cnt+=1

    cap.release()
    cv2.destroyAllWindows()

if __name__ == '__main__':
    arReader()

Résultat d'exécution

De cette manière, la bordure, l'ID, le coin et les axes XYZ du marqueur ont été dessinés et détectés. 座標①.png

Mesurez la distance et l'inclinaison entre le marqueur et la caméra

Lorsque vous souhaitez trouver la distance et l'inclinaison entre le marqueur et la caméra, vous utiliserez généralement un capteur infrarouge, mais cette fois, en plus des paramètres internes de la caméra et du coefficient de distorsion obtenu par l'étalonnage de la caméra, la rotation Il est calculé à l'aide d'une matrice, d'un vecteur de rotation et d'un vecteur de translation.

Calibrage de la caméra

Tout d'abord, effectuez un étalonnage de la caméra pour obtenir les paramètres internes et le coefficient de distorsion de la caméra.

calib.py


# -*- coding: utf-8 -*
import numpy as np
import cv2
import glob

criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)

objp = np.zeros((7*7,3), np.float32)
objp[:,:2] = np.mgrid[0:7,0:7].T.reshape(-1,2)

objpoints = []
imgpoints = []

gray_images=glob.glob('chess*.png')
cnt=0

for fname in gray_images:
    img = cv2.imread(fname)
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

    ret, corners = cv2.findChessboardCorners(gray, (7,7),None)

    if ret == True:
        objpoints.append(objp)

        corners2 = cv2.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria)
        imgpoints.append(corners2)

        img = cv2.drawChessboardCorners(img, (7,7), corners2,ret)
        cv2.imwrite('calib'+str(cnt)+'.png',img)
        cnt+=1

    ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1],None,None)

print(mtx, dist)

cv2.destroyAllWindows()

Résultat d'exécution

calib1.png

Résultat d'exécution


Paramètres internes de la caméra
[[9.31357583e+03 0.00000000e+00 1.61931898e+03]
[0.00000000e+00 9.64867367e+03 1.92100899e+03]
[0.00000000e+00 0.00000000e+00 1.00000000e+00]]
Coefficient de déformation
[[ 0.22229833 -6.34741982  0.01145082  0.01934784 -8.43093571]]

Calculé avec Rodriguez

Calculez à l'aide d'une matrice de rotation, d'un vecteur de rotation et d'un vecteur de translation. Réécrivez camera_matrix avec les paramètres obtenus par la méthode ci-dessus.

distance.py


#!/usr/bin/env python
# -*- coding: utf-8 -*
import cv2
import numpy as np
import sys
from pyardrone import ARDrone
import logging

logging.basicConfig(level=logging.DEBUG)

aruco = cv2.aruco #bibliothèque aruco
dictionary = aruco.getPredefinedDictionary(aruco.DICT_4X4_50)

client = ARDrone()
client.video_ready.wait()

parameters =  aruco.DetectorParameters_create()

parameters.cornerRefinementMethod = aruco.CORNER_REFINE_CONTOUR


def main():
    cnt=0
    marker_length = 0.1 # [m]

    camera_matrix = np.array( [[ , , ],
                               [ , , ],
                               [ , , ]] )
    #Trouver les paramètres par calibrage de la caméra ↑

    distortion_coeff = np.array( [[ 0.22229833, -6.34741982,  0.01145082,  0.01934784, -8.43093571]] )

    try:
        while True:
            corners, ids, rejectedImgPoints = aruco.detectMarkers(client.frame, dictionary, parameters=parameters)

            aruco.drawDetectedMarkers(client.frame, corners, ids, (0,255,255))

            if len(corners) > 0:
                for i, corner in enumerate(corners):
                    # rvec -> rotation vector, tvec -> translation vector
                    rvec, tvec, _ = aruco.estimatePoseSingleMarkers(corner, marker_length, camera_matrix, distortion_coeff)

                    tvec = np.squeeze(tvec)
                    rvec = np.squeeze(rvec)
                    rvec_matrix = cv2.Rodrigues(rvec)
                    rvec_matrix = rvec_matrix[0]
                    transpose_tvec = tvec[np.newaxis, :].T
                    proj_matrix = np.hstack((rvec_matrix, transpose_tvec))
                    euler_angle = cv2.decomposeProjectionMatrix(proj_matrix)[6] # [deg]
                    print("x : " + str(tvec[0]))
                    print("y : " + str(tvec[1]))
                    print("z : " + str(tvec[2]))
                    print("roll : " + str(euler_angle[0]))
                    print("pitch: " + str(euler_angle[1]))
                    print("yaw  : " + str(euler_angle[2]))

                    draw_pole_length = marker_length/2 #Longueur réelle[m]
                    aruco.drawAxis(client.frame, camera_matrix, distortion_coeff, rvec, tvec, draw_pole_length)

            cv2.imwrite('distance'+str(cnt)+'.png',client.frame)
            cnt+=1

            key = cv2.waitKey(50)
            if key == 27: # ESC
                break
    finally:
        client.close()

if __name__ == '__main__':
    try:
        main()
    except KeyboardInterrupt:
        pass

Résultat d'exécution

Afin de confirmer que la distance peut être mesurée correctement, réglez la distance entre le marqueur et la caméra (drone) à 25 cm et 50 cm, et exécutez le programme. 25cm正方形.png 50cm正方形.png

Résultat d'exécution(25cm)


x : -0.5410338091817037 
y : -0.713790809892646
z : 3.828983632577233
roll : [173.43049198]
pitch: [-20.42010647]
yaw  : [1.58947772]

Résultat d'exécution(50cm)


x : -1.0633298519994792 
y : -1.3476793013004273
z : 7.311742619516305
roll : [-150.91884043]
pitch: [2.45488175]
yaw  : [3.61554034]

La valeur du résultat de l'exécution est bien doublée. De cette manière, la taille du mouvement et la valeur du lacet du pas de roulis peuvent être obtenues pour chacun des axes XYZ.

prime

À partir de la valeur obtenue, le drone a été suivi par branchement conditionnel comme indiqué dans le tableau ci-dessous.

Marqueur-Distance entre les caméras Fonctionnement du drone
~0.5m Planant
0.5m ~ 2.0m Avance
2.0m ~ atterrissage
autre que ça Planant

Le diagramme de configuration ressemble à ceci.

構成図.png Puisque la communication multi-sauts (fossile) est utilisée, si même RasPi peut être placé sur le drone, ce sera un terminal de recherche dans un endroit où les gens ne peuvent pas entrer. Pour cette raison, je dois créer une grande quantité de points d'accès sans fil RasPi et définir dnsmasq et hostapd, mais c'est aussi trop gênant, donc je l'écrirai à un autre moment.

en conclusion

Cette fois, j'ai utilisé Python et OpenCV pour générer et détecter des marqueurs AR afin de trouver la distance et l'inclinaison. Je pense que ce marqueur ArUco est un excellent marqueur qui peut facilement et précisément reconnaître la distance entre le marqueur et la caméra, la direction du marqueur et le numéro (ID) attribué à chacun, mais ce n'est pas si célèbre ... ...? J'écrirai un jour une édition de drone.

Recommended Posts

Estimer la posture du marqueur AR avec Python + OpenCV + drone
Obtenez et estimez la forme de la tête en utilisant Dlib et OpenCV avec python
J'ai essayé la "correction gamma" de l'image avec Python + OpenCV
Etude de base d'OpenCV avec Python
L'extraction de couleur avec Python + OpenCV a résolu le mystère du fond vert
Vérifier l'existence du fichier avec python
J'ai essayé de "lisser" l'image avec Python + OpenCV
Préparer l'environnement d'exécution de Python3 avec Docker
Comparaison des performances du détecteur de visage avec Python + OpenCV
Mathématiques Todai 2016 résolues avec Python
J'ai essayé de "différencier" l'image avec Python + OpenCV
[Note] Exportez le html du site avec python.
Calculez le nombre total de combinaisons avec python
Vérifiez la date du devoir de drapeau avec Python
J'ai essayé de "binariser" l'image avec Python + OpenCV
Le moyen le plus simple d'utiliser OpenCV avec python
Convertir le code de caractère du fichier avec Python3
[Python] Déterminez le type d'iris avec SVM
[Python + OpenCV] Peignez la partie transparente de l'image en blanc
Binarisation avec OpenCV / Python
le zen de Python
Extraire le tableau des fichiers image avec OneDrive et Python
Apprenez Nim avec Python (dès le début de l'année).
Détruire l'expression intermédiaire de la méthode sweep avec Python
[OpenCV / Python] J'ai essayé l'analyse d'image de cellules avec OpenCV
Essayez de projeter la conversion d'image en utilisant OpenCV avec Python
Visualisez la gamme d'insertions internes et externes avec python
Calculer le coefficient de régression d'une analyse de régression simple avec python
Ecrire des caractères dans l'illustration de la carte avec OpenCV python
Remplissez l'arrière-plan d'une seule couleur avec OpenCV2 + Python
Résumé du flux de base de l'apprentissage automatique avec Python
Obtenez l'état de fonctionnement de JR West avec Python
[Windows] [Python] Calibrage de la caméra de l'objectif fisheye avec OpenCV
Visualisez le statut d'appréciation des œuvres d'art avec OpenCV
L'attitude que les programmeurs devraient avoir (Le Zen de Python)
J'ai essayé la "conversion de morphologie" de l'image avec Python + OpenCV
J'ai essayé de trouver l'entropie de l'image avec python
Essayez de gratter les données COVID-19 Tokyo avec Python
Vers la retraite de Python2
"Traitement Apple" avec OpenCV3 + Python3
L'histoire de la mise en œuvre du sujet Facebook Messenger Bot avec python
Unifier l'environnement de l'équipe de développement Python en commençant par Poetry
Visualisez les résultats des arbres de décision réalisés avec Python scikit-learn
Édition d'image avec python OpenCV
Capture de caméra avec Python + OpenCV
Calculez des millions de chiffres dans la racine carrée de 2 avec python
J'ai écrit la grammaire de base de Python dans Jupyter Lab
Exécutez l'intelligence de votre propre bibliothèque python avec VScode.
[Python] Utilisation d'OpenCV avec Python (basique)
J'ai évalué la stratégie de négociation du système boursier avec Python.
Touchons l'API de Netatmo Weather Station avec Python. #Python #Netatmo
L'histoire de l'affichage d'images avec OpenCV ou PIL (uniquement)
L'histoire du rubyiste aux prises avec Python :: Dict data with pycall
[Homologie] Comptez le nombre de trous dans les données avec Python
Détection de visage avec Python + OpenCV
Réécrivez le nœud d'ajout d'enregistrement de SPSS Modeler avec Python.
Appelez l'API avec python3.