[PYTHON] Construisez un système de mesure de précision sous-pixel avec Jetson Nano + caméra USB + OpenCV + Scikit-image

J'ai écrit un script Python qui mesure la précision des sous-pixels avec Jetson Nano + caméra USB + OpenCV + Scikit-image. Non limité à Jetson Nano, si Python fonctionne, il fonctionnera sur Raspberry Pi.

Utilisez la corrélation de phase pour localiser les sous-pixels des coordonnées trouvées par correspondance de modèle. La reproductibilité est assez bonne, mais la linéarité dépend de l'objectif.

Vous pouvez télécharger le script depuis: https://github.com/takurot/templatematch

Environnement d'exécution

IMG_20191117_143549.jpg

Exemple d'exécution

IMG_20191117_143644.jpg

Modules requis

OpenCV Scikit-image Numpy Matplot

Procédure d'exécution

  1. Placez la cible du modèle dans le curseur □ à l'écran + ESC
  2. Exécution de la mesure continue à l'écran, le curseur □ est dessiné là où se trouve l'image modèle
  3. L'instruction print génère le temps d'exécution et les coordonnées des pixels avec le coin supérieur gauche sous la forme (0,0).

Commentaire de code

templatematch.py


def main():
    TEMPLATE_SIZE = 32
    capture = cv2.VideoCapture(0)

↑ Il dit TEMPLATE_SIZE, mais la taille réelle est le double de 64 cv2.VideoCapture (0) est utilisé pour acquérir des images à partir d'une caméra USB.

templatematch.py


    while True:
        ret, org_img = capture.read()
        img = cv2.resize(org_img, dsize=None, fx=0.5, fy=0.5)

↑ La taille de l'image est déterminée par fx et fy. La taille d'origine est de 1280x960, mais elle a été redimensionnée à 640x480. Je l'ai redimensionné pour que le temps de traitement soit approprié, mais la taille elle-même peut être définie de manière arbitraire. Plus l'image est petite, plus vite.

templatematch.py


        height, width, channnel = img.shape[:3]
        
        y1 = int(height/2-TEMPLATE_SIZE)
        y2 = int(height/2+TEMPLATE_SIZE)
        x1 = int(width/2-TEMPLATE_SIZE)
        x2 = int(width/2+TEMPLATE_SIZE)
        # print(width, height, x1, x2, y1, y2)
        if ret != True:
            print("Error1")
            return
        disp = cv2.rectangle(img, (x1, y1), (x2, y2), (0, 0, 255), 3)
        cv2.imshow("Select Template(Size 64x64) Press ESC", disp)
        key = cv2.waitKey(10)
        if key == 27: # ESC 
            break

↑ □ Les coordonnées pour dessiner le curseur sur le modèle sont calculées et affichées en fonction du centre de l'image. Appuyez sur ÉCHAP pour terminer l'enregistrement du modèle.

templatematch.py


    image = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    template = image[y1:y2, x1:x2]

    cv2.imshow("Template-2", template)

↑ L'image enregistrée comme modèle est convertie en monochrome et affichée.

templatematch.py


    while True:
        time_start = time.time()
        ret, org_img2 = capture.read()
        if ret != True:
            print("Error2")
            return
        img2 = cv2.resize(org_img2, dsize=None, fx=0.5, fy=0.5)
        offset_image = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)
        time_cap = int((time.time() - time_start) * 1000)

↑ Redimensionnez l'image mesurée et convertissez-la en monochrome. La mesure se fait en monochrome.

templatematch.py


        time_start = time.time()
        result = match_template(offset_image, template)
        ij = np.unravel_index(np.argmax(result), result.shape)
        x, y = ij[::-1]
        meas_image = offset_image[y:(y+TEMPLATE_SIZE*2), x:(x+TEMPLATE_SIZE*2)]
        # print (template.shape[0], template.shape[1], meas_image.shape[0], meas_image.shape[1])
        shift, error, diffphase = register_translation(template, meas_image, 100)
        time_meas = int((time.time() - time_start) * 1000)

↑ ** C'est le cœur du traitement ** Après avoir effectué la correspondance des modèles, découpez l'image à la taille du modèle en fonction des critères de coordonnées trouvés. Ensuite, la corrélation de phase (register_translation) est exécutée sur l'image découpée et l'image modèle pour obtenir les coordonnées avec une précision de sous-pixel. Le dernier 100 de register_translation signifie "1/100 pixel de précision". L'augmentation de ce nombre augmentera la précision.

templatematch.py


        cv2.rectangle(img2, (x, y), (x+TEMPLATE_SIZE*2, y+TEMPLATE_SIZE*2), (0, 255, 0), 3)

        cv2.imshow("Real Time Measurement 640x480", img2)

        print ("Capture[ms]:", time_cap, "Meas[ms]:", time_meas, "X[pix]:", x+TEMPLATE_SIZE+shift[0], "Y[pix]:", y+TEMPLATE_SIZE+shift[1])

        key = cv2.waitKey(10)
        if key == 27: # ESC 
            break

↑ □ Dessinez un curseur aux coordonnées où le modèle est trouvé et produit Sortie temps d'exécution et coordonnées Terminer lorsque ESC est enfoncé

Impressions

J'ai pu facilement construire un système de mesure de précision sous-pixel à la maison. Je pense qu'il est possible d'augmenter le nombre de caméras et d'effectuer des mesures multi-yeux. Puisque le temps d'exécution dépend de la taille de l'image mesurée et de la taille du modèle, il est nécessaire de l'ajuster de manière appropriée pour le temps cible. Si vous utilisez un microscope, etc., vous pouvez mesurer avec une précision de nm, mais étant donné que les vibrations de l'environnement d'exécution ont une grande influence, une table d'isolation des vibrations est nécessaire.

S'il vous plaît laissez-moi savoir si cela aide! Mais ne le soumettez pas en copiant!

Recommended Posts

Construisez un système de mesure de précision sous-pixel avec Jetson Nano + caméra USB + OpenCV + Scikit-image
Créez un système de synthèse bon marché avec des composants AWS
Afficher l'image de la caméra USB avec OpenCV de Python avec Raspeye
Créez une caméra de surveillance WEB avec Raspberry Pi et OpenCV
La tentative de construction d'opencv-python avec Dockerfile sur jetson nano échoue (/tmp/nano_build_opencv/build_opencv.sh 3.4.10 'a renvoyé un code différent de zéro: 1)