Logo Mon Club Elec

Processing + ARToolkit + JavacvPro : Détection du centre, du type d’un marker à partir d’un flux vidéo webcam.

Le traitement d’images et la détection de marqueurs sont des domaines qui ont connu une croissance exponentielle ces dernières années. Les technologies telles que Processing, ARToolkit et JavacvPro offrent aux développeurs des outils puissants pour détecter le centre et le type d’un marqueur à partir d’un flux vidéo webcam. Dans cet article, nous allons examiner comment ces technologies peuvent être utilisées pour détecter le centre et le type d’un marqueur à partir d’un flux vidéo webcam.

Processing + ARToolkit + JavacvPro : Détection du centre, du type d’un marker à partir d’un flux vidéo webcam.

Par X. HINAULT – 29 Février 2012

Processing + ARToolkit + JavacvPro : Détection du centre, du type d’un marker à partir d’un flux vidéo webcam.

Explication

  • Ce programme récupère les coordonnées 2D du centre d’un marker ainsi que son type sur un flux vidéo de webcam en utilisant ARToolkit avec Processing à l’aide de la librairie nyar4psg.
  • On réalise ici :
    • la capture d’un flux vidéo avec la librairie GSVideo
    • à chaque nouvelle frame, on réalise la détection détection d’un marker parmi plusieurs prédéfinis (les fichiers doivent être présents sur votre machine)
    • on récupère les informations grâce aux fonctions dédiées de la librairie javacvPro
    • on affiche également le repère 3D du marker détecté

Matériel et configuration utilisés

  • PC Intel Core Quad 2.33 Ghz
  • Webcam(s) USB C270
  • Ubuntu 10.04 LTS
  • Processing 1-5
  • Librairie GSVideo 0.9 / 1.0
  • nyar4psg 1.1.7
  • javacvPro 0.4

Ressources utiles

Le programme

Copier/coller le code dans Processing, adaptez les chemins à votre situation, enjoy !
Adapter également la taille du marker que vous utilisez.

// Programme processing
// généré avec le générateur de code Processing
// du site www.mon-club-elec.fr
// par X. HINAULT – tous droits réservés

// Programme écrit le : 29/2/2012.

// ——- Licence du code de ce programme : GPL v3—–
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License,
//  or any later version.
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//  You should have received a copy of the GNU General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.

/////////////// Description du programme ////////////
// Utilise la librairie GSVideo de capture et lecture vidéo
// Utilise la librairie javacvPro de traitement d’image et reconnaissance visuelle
// Utilise la librairie nyar4psg qui implémente ARToolkit dans Processing

/*
Détection du centre et du type d’un marker ARToolkit
*/

// XXXXXXXXXXXXXXXXXXXXXX ENTETE DECLARATIVE XXXXXXXXXXXXXXXXXXXXXX

// inclusion des librairies utilisées

import codeanticode.gsvideo.*; // importe la librairie vidéo GSVideo qui implémente GStreamer pour Processing (compatible Linux)
// librairie comparable à la librairie native vidéo de Processing (qui implémente QuickTime..)- Voir Reference librairie Video Processing
// cette librairie doit être présente dans le répertoire modes/java/libraries du répertoire Processing (1-5)
// voir ici : http://gsvideo.sourceforge.net/
// et ici : http://codeanticode.wordpress.com/2011/05/16/gsvideo-09-release

import monclubelec.javacvPro.*; // importe la librairie javacvPro qui implémente le traitement d’image avancé et la reconnaissance visuelle pour Processing
// cette librairie se base sur les fonctions java de la librairie javacv par Samuel Audet : http://code.google.com/p/javacv/
// javacv implémente en Java les centaines de fonctions natives de la librairie OpenCV (2500 algorithmes) !
// la librairie javacvPro doit être présente dans le répertoire modes/java/libraries du répertoire Processing (1-5)
// dispo ici : https://www.mon-club-elec.fr/pmwiki_reference_lib_javacvPro/pmwiki.php
// nécessite également que la librairie native OpenCV 2.3.1 soit installée sur votre ordinateur
// NB : compatibilité avec la plupart des fonctions de la librairie OpenCV pour Processing : http://ubaa.net/shared/processing/opencv/

import java.awt.*; // Classe Point, Rectangle , etc…

import jp.nyatla.nyar4psg.*; // La librairie NyARToolkit Processing library = ARToolKit pour Processing
// Cette librairie permet de détecter des pattern ou marker dans une image
// et d’analyser leur transformation de perspective
// nyAR4psg est à télécharger ici : http://sourceforge.jp/projects/nyartoolkit/releases/
// et à mettre dans le répertoire des librairies
// à noter : javacvPro intègre des fonctions utilisables directement avec nyar4psg

// déclaration objets

PImage imgSrc, imgDest; // déclare un/des objets PImage (conteneur d’image Processing)

GSCapture cam1; // déclare un objet GSCapture représentant une webcam
// L’objet GSCapture étend PImage – se comporte comme un conteneur des frames issues de la webcam

OpenCV opencv; // déclare un objet OpenCV principal

PMatrix3D syst3D; // déclare une matrice 4×4 représentant un système de coordonnées 3D..

MultiMarker nya; // déclaration de l’objet principal pour reconnaissance des markers – nya pour nyArtoolkit

// déclaration variables globales

//—— déclaration des variables de couleur utiles —-
int jaune=color(255,255,0);
int vert=color(0,255,0);
int rouge=color(255,0,0);
int bleu=color(0,0,255);
int noir=color(0,0,0);
int blanc=color(255,255,255);
int bleuclair=color(0,255,255);
int violet=color(255,0,255);

// variable pour la taille de la capture video
int widthCapture=320*2; // largeur capture
int heightCapture=240*2; // hauteur capture
int fpsCapture=15; // framerate (image/secondes) pour la capture video

// NB : pour la détection des markers, on peut utiliser une grande résolution facilement.
// Le résultat sera quand même rapide… et la précision plus élevée.

//—– variables pour calibration webcam —–
 float ouvertureX=19.43; // ouverture largeur en degres – Hercules DualPix Exchange
//float ouvertureX=22.53; // ouverture largeur en degres –  Logitech C270

// calculé avec tan angle= largeur réelle / 2 * distance camera
// exemple Logitech C270 : 1/2 largeur réelle = 83cm  distance = 200 cm
// d’où tan angle = 0.415 et d’où angle = 22.53 deg

//——— variables pour reconnaissance des Markers avec nyARToolkit  ———————

//—– chemin absolu fichier de paramètres de distorsion de la camera —-
//String camParamPath = « /home/hinault/Téléchargements/librairies_processing/nyar4psg-1.1.6/data/camera_para.dat »;
String camParamPath = « /home/hinault/Téléchargements/processing-1.5/modes/java/libraries/NyAR4psg/data/camera_para.dat »;
// utilise le fichier par défaut – donne résultat satisfaisant

//—– chemin absolu fichiers de description des patterns ou markers —-
String patternPath = « /home/hinault/Téléchargements/patternMaker/examples/ARToolKit_Patterns »;
// à télécharger ici : http://www.cs.utah.edu/gdc/projects/augmentedreality/

//— taille de l’image à utiliser pour la détection = plus petite pour plus rapide —
int widthAR= widthCapture;
int heightAR=heightCapture;

int numMarkers = 8; // le nombre de pattern ou markers à utiliser

Marker[] markersArray = new Marker[numMarkers]; // tableau pour stockage des paramètres des markers détectés avec ARToolkit – classe javacvPro !

float realWidthMarker=50; // taille réelle du marker utilisé en mmm – on aura un correspondance 1 mm = 1 pixel ou cran dans le repère 3D du marker

//String[] nameMarkers= new String[numMarkers]; // pour mémoriser le nom des marker

// XXXXXXXXXXXXXXXXXXXXXX  Fonction SETUP XXXXXXXXXXXXXXXXXXXXXX

void setup(){ // fonction d’initialisation exécutée 1 fois au démarrage

        // —- initialisation paramètres graphiques utilisés
        colorMode(RGB, 255,255,255); // fixe format couleur R G B pour fill, stroke, etc…
        fill(0,0,255); // couleur remplissage RGB – noFill() si pas de remplissage
        stroke (0,0,255); // couleur pourtour RGB – noStroke() si pas de pourtour
        rectMode(CORNER); // origine rectangle : CORNER = coin sup gauche | CENTER : centre
        imageMode(CORNER); // origine image : CORNER = coin sup gauche | CENTER : centre
        ellipseMode(CENTER); // origine cercles / ellipses : CENTER : centre (autres : RADIUS, CORNERS, CORNER
        //strokeWeight(0); // largeur pourtour
        frameRate(30);// Images par seconde – The default rate is 60 frames per second

        // — initialisation fenêtre de base —
        size(widthCapture,heightCapture,P3D); // ouvre une fenêtre xpixels  x ypixels – 3D active
        background(0,0,0); // couleur fond fenetre

// — initialisation des objets et fonctionnalités utilisées —

        //======== Initialisation Objets GSVideo (capture et/ou lecture video =========

        // GSCapture(this, int requestWidth, int requestHeight, [int frameRate], [String sourceName], [String cameraName])
        // cam1 = new GSCapture(this, widthCapture, heightCapture,fpsCapture, »v4l2src », »/dev/video0″); // Initialise objet GSCapture désignant webcam – avant GSVideo 1.0
        cam1 = new GSCapture(this, widthCapture, heightCapture,« v4l2src »,« /dev/video1 », fpsCapture); // Initialise objet GSCapture désignant webcam – depuis GSVideo 1.0
        // largeur et hauteur doivent être compatible avec la webcam – typiquement 160×120 ou 320×240 ou 640×480…
        // Meilleurs résultats avec framerate webcam entre 20 et 30 et frameRate programme idem ou multiple plus grand (40 pour 20 par ex)
        // la liste des webcam installées sous Ubuntu (Gnu/Linux) est donnée par la commande : ls /dev/video*

        // cam1.play();  // démarre objet GSCapture = la webcam – version GSVideo avant 0.9
        cam1.start();  // démarre objet GSCapture = la webcam – version GSVideo après 0.9

        //======== Initialisation Objets OpenCV (librairie javacvPro : traitement d’image et reconnaissance visuelle) =========

        opencv = new OpenCV(this); // initialise objet OpenCV à partir du parent This
        opencv.allocate(widthCapture,heightCapture); // crée les buffers image de la taille voulue

      //—- exemple code —-
      String nomFichier=« /home/hinault/Bureau/trans/monimage.png »;
      opencv.loadImage(nomFichier); // charge fichier dans le buffer opencv
      image(opencv.image(),0,0);// affiche le buffer opencv

    //opencv.contrast(100); // modifie contraste : -128/ +128
    //opencv.brightness(-50); // modifie luminosité : -128/ +128

    // opencv.copy(img); // charge le PImage dans le buffer opencv
    //opencv.cannyBuffer(); // applique filtre Canny et met le résultat dans le buffer Gray
    //opencv.sobelBuffer(3,2); // applique filtre Sobel sur le buffer
    //opencv.grayBuffer(); // bascule le buffer en niveau de gris

      image(opencv.getBuffer(),0,0); // alternative – affiche image stockée dans le buffer opencv

    //opencv.absDiff(); // réalise soustraction entre Buffer et Memory et met le résultat dans Memory2
    //opencv.gray(« MEMORY2 »); // transforme en niveaux de gris le buffer MEMORY2
    //opencv.invert(« MEMORY2 »); // inverse l’image du buffer MEMORY2
    //image(opencv.getMemory2(),0,0); // affiche image résultante stockée dans le mémory 2

    //opencv.rememberBuffer();  // mémorise le Buffer dans le buffer Memory

     //=========== initialisation détection des markers =========================

     // création d’un objet MultiMarker avec résolution voulue, les paramètres caméra et le système de coordonnées voulu
        nya = new MultiMarker(this, widthAR, heightAR, camParamPath, NyAR4PsgConfig.CONFIG_DEFAULT);

   // fixe le nombre de fois qu’un marqueur ne doit plus etre détecté pour ne plus l’afficher.
     //Par défaut = 10. Mettre à 1 pour visualisation immédiate
      nya.setLostDelay(1);

      // fixe le niveau de seuil de détection à utiliser. Valeur possible entre 0 et 255. Mettre -1 (=THLESHOLD_AUTO) pour seuil automatique – respecter la « faute »
        nya.setThreshold(MultiMarker.THLESHOLD_AUTO);

        // fixe le niveau de seuil de confiance (= probabilité de correspondance) à utiliser pour la reconnaissance des markers. Valeur possible entre 0 et 1.
        // Valeur par défaut = 0.51 (=.DEFAULT_CF_THRESHOLD). Plus le seuil est élevé et plus la détection est rigoureuse.
        nya.setConfidenceThreshold(MultiMarker.DEFAULT_CF_THRESHOLD);
        //nya.setConfidenceThreshold(0.8); // sélection exigeante

        //– chargement des fichiers de description des patterns

        //——- création des objets Marker individuel du tableau de markers (javacvPro)
        // et initialisation des propriétés communes
        for (int i=0; i<markersArray.length; i++) {
          markersArray[i]=new Marker();
          markersArray[i].realWidth=realWidthMarker;
        } // fin for

        //——– initialisation du tableau d’objets marker (javacvPro)
        // chaque objet Marker de la librairie javacvPro contient les paramètres attachés au marker nyar correspondant
        // son nom = le fichier de description *.patt
        markersArray[0].name=« 4x4_99.patt »; // mémorise le nom du fichier du marker voulu
        markersArray[1].name=« 4x4_50.patt »; // mémorise le nom du fichier du marker voulu
        markersArray[2].name=« 4x4_83.patt »; // mémorise le nom du fichier du marker voulu
        markersArray[3].name=« 4x4_23.patt »; // mémorise le nom du fichier du marker voulu
        markersArray[4].name=« 4x4_68.patt »; // mémorise le nom du fichier du marker voulu
        markersArray[5].name=« 4x4_76.patt »; // mémorise le nom du fichier du marker voulu
        markersArray[6].name=« 4x4_55.patt »; // mémorise le nom du fichier du marker voulu
        markersArray[7].name=« 4x4_34.patt »; // mémorise le nom du fichier du marker voulu
        // etc…

        //—- chargement des markers dans le MultiMarker (nyartoolkit)—
        for (int i=0; i<markersArray.length; i++) {
          nya.addARMarker(patternPath + « / » + markersArray[i].name, markersArray[i].realWidth); // ajoute le fichier de description à l’objet principal de détection AR – bordure 25% et 16×16 par défaut
          println (« Fichier chargé : «  + markersArray[i].name);
        } // fin for

} // fin fonction Setup

// XXXXXXXXXXXXXXXXXXXXXX Fonction Draw XXXXXXXXXXXXXXXXXXXX

void  draw() { // fonction exécutée en boucle

// Code type capture GSVideo

  if (cam1.available() == true) { // si une nouvelle frame est disponible sur la webcam

    background(0);  // fond noir entre 2 images

    //—— gestion image webcam par GSCapture ——
    cam1.read(); // acquisition d’un frame
    image(cam1, 0, 0); // affiche image
    //set(0, 0, cam); // affiche image – plus rapide

    //——- gestion détection et dessin 2D des Markers ———-

    nya.detect(cam1); // detection des markers dans l’image à la résolution voulue – nyar4psg
    // l’image passée en paramètre doit avoir la même résolution que ce qui a été défini à l’initialisation du constructeur

    println(« seuil de binarisation actuel = «  + nya.getCurrentThreshold()); // affiche le niveau courant du seuillage binaire

    opencv.updateMarkers(nya, markersArray, false); // met à jour le tableau des paramètres 2D des markers – javacvPro

    //— dessin 2D —

   //public void draw2DMarkers(MultiMarker nyaIn, Marker[] markersIn, int xRefIn, int yRefIn, float scaleIn, int radius, int colorStrokeIn, int strokeWeightIn, boolean fillIn, int colorFillIn, boolean debugIn)
   opencv.draw2DMarkers(nya, markersArray); // trace les markers – javacvPro

   opencv.distanceMarkers (nya, markersArray, ouvertureX, widthCapture, false);  // calcule et mémorise la distance réelle des Markers à la caméra – javacvPro

   // accéder aux caractéristiques 2D des markers ? – le centre, la rotation du marker sur lui-meme…
   // sélectionner un Marker voulu…

/* — première possibilité —    
   if (nya.isExistMarker(3)) { // si le marker indice 3 est détecté

     println(« Le marker  » + markersArray[3].name +  » est détecté ! »); // le nom du fichier de description du marker

   }
*/

/*—- 2ème possibilité —

   if (opencv.isExistMarker(nya, markersArray, « 4x4_23.patt »)) { // détecte si marker détecté à partir de son nom

          println(« Le marker  » + « 4x4_23.patt »+  » est détecté ! »); // le nom du fichier de description du marker

   }

*/

// —- 3ème possibilité —-
   if (opencv.isExistMarker(nya, markersArray,23)) { // détecte si marker détecté à partir de son numero (pas l’indice)

         Marker selectedMarker = opencv.selectMarker(markersArray,23); // sélectionne le marker voulu

          println(« Le marker «  + selectedMarker.name +  » est détecté ! »); // le nom du fichier de description du marker

          println(« Le centre est en x= » + selectedMarker.center2D.x +  » | y= »+ selectedMarker.center2D.y); // affiche les coordonnées du centre  

          opencv.drawCircle (
                    selectedMarker.center2D, // le centre du cercle à tracer
                        0, 0, // les coordonnées du cercle à tracer
                        1, // l’échelle à utiliser
                        10, // rayon à utiliser
                        jaune,1, // couleur et épaisseur du pourtour du cercle
                        true, rouge, // drapeau de remplissage et couleur de remplissage
                        false // drapeau d’affichage des messages
                                );

   }

/* // pour mémoire : les champs de l’objet Marker

         public String name             = » » ; // le nom du fichier de description du marker

         public float realX             = (float) 0.0; // abscisse réelle au sol de l’espace d’évolution décrit par les markers
         public float realY             = (float) 0.0; // ordonnée réel au sol de l’espace d’évolution décrit par les markers

         public float realWidth         = (float) 0.0; // largeur réelle du Marker

         public float width2D           = (float) 0.0; // largeur 2D du Marker telle que affichée sur l’image webcam
         public float height2D          = (float) 0.0; // hauteur 2D du Marker telle que affichée sur l’image webcam

         //— pour réalité augmentée —
         public float width3D           = (float) 1000; // largeur 3D du Marker telle que affichée sur l’image webcam
         public float height3D          = (float) 1000; // hauteur 3D du Marker telle que affichée sur l’image webcam
         public float depth3D           = (float) 10; // profondeur 3D du Marker telle que affichée sur l’image webcam

         public float distance          = (float) 0.0; // distance du marker à la webcam (calculée)

         public float angleAxeY         = (float) 0.0; // angle de rotation dans l’axe Y en degrés

         public Point upCenter2D = new Point(); // milieu bord sup 2D du marqueur
         public Point downCenter2D = new Point(); // milieu bord inf 2D du marqueur
         public Point leftCenter2D = new Point(); // milieu bord gauche 2D du marqueur
         public Point rightCenter2D = new Point(); // milieu bord droit 2D du marqueur

         public Point center2D = new Point(); // centre 2D du marqueur

         public Point[] corners2D = new Point[4]; // coins 2D du marqueur
*/       

    //—- dessin 3D —
    //— opération 3D à faire APRES détection 2D

    //— affiche repère 3D centré sur l’écran —
    //translate(width/2,height/2,0); // translation du repère 3D courant de pour centrage au centre de la fenêtre camera
    //opencv.drawCurrentSyst3D(50, color(255,0,0), color(0,255,0), color(0,0,255),2); // affiche le repère 0xyz courant avec taille et épaisseur voulus

    //void draw3DMarkers(MultiMarker nyaIn, Marker[] markersIn, int widthBoxIn, int heightBoxIn, int depthBoxIn, boolean strokeIn, int colorStrokeIn, int strokeWeightIn, boolean fillIn, int colorFillIn, boolean debugIn)
    //opencv.draw3DMarkers(nya, markersArray,0, 0,10, false, 0, 0, true, color(255,0,0), true); // si width et height=0, utilise propriétés 3D de chaque marker

  } // fin if available

        // while(true); // stoppe boucle draw

} // fin de la fonction draw()

// XXXXXXXXXXXXXXXXXXXXXX Autres Fonctions XXXXXXXXXXXXXXXXXXXXXX

//————- Fonction d’arret de Processing —-

public void stop(){ // fonction d’arrêt de Processing

        cam1.delete(); // efface l’objet GScapture

        super.stop(); // obligatoire

} // fin fonction stop()

//XXXXXXXXXXXXXXXXXX Fin du programme XXXXXXXXXXXXXXXXX

 

Noter cet article

Laisser un commentaire

Archive Mon Club Elec

Articles populaires

Newsletter

Inscrivez-vous maintenant et bénéficiez d'un soutien continu pour réaliser vos travaux électriques en toute sécurité.