Aller au contenu

Géométrie Discrète - TP séance 01

Rendu du TP :
À la fin de la séance, même si vous ne l'avez pas fini, téléversez votre fichier C++ sur la page Ametice du cours dans la section "Rendu des TPs" en suivant bien les instructions.
Dans le cas où le TP n'est achevé, il vous est demandé de le terminer chez vous, puis de re-téléverser le fichier lorsqu'il sera dans sa version finale.

1. Prise en main d'OpenCV avec Astico2D

1.1 Installation et programme d'exemple

En salle TP, connectez-vous avec la machine VDI "LUNIX".

Allez dans la page de Astico2D, téléchargez l'archive astico2d.tgz puis décompactez l'archive.

  • Sur la machine VDI : OpenCV est déjà installé ; il vous suffit d'ouvrir un terminal (menu / Outils système / Terminal MATE), puis aller dans le répertoire Astico2D avec la commande cd, puis taper make all pour tout compiler.

  • Sur un PC personnel : vous pouvez installer OpenCV et compiler Astico2D en suivant les instructions indiquées dans Installation.

Exécutez ensuite le programme demo1 en lui passant une image en argument :

./demo1 IMAGES/chat1.jpg

Essayez les différentes touches du clavier (tapez a pour l'aide), déplacer la loupe à la souris, changer la valeur du seuil et du zoom.

Vous pouvez maintenant étudier le code source de demo1.cpp.

1.2 Accès aux pixels

Si on charge une image avec cv::imread en lui passant IMREAD_COLOR, alors l'image est codée en interne au format CV_8UC3 : 3 canaux sur 8 bits, qui peuvent coder du RGB, HSV, etc.

  • Afficher la valeur du pixel x,y du canal k :

    std::cout << img.at<cv::Vec3b>(y,x)[k];
    

  • Mettre tous les pixels du canal 2 à 0 :

    for (int y = 0; y < img_int.rows; y++)
    for (int x = 0; x < img_int.cols; x++)
        img.at<cv::Vec3b>(y,x)[2] = 0;
    

  • Un accès linéaire est possible avec une seule coordonnée t :

    t = y*img.cols+x;
    img.at<cv::Vec3b>(t)[k] = 0;
    
    for (t = 0; t < img.cols*img.rows; t++)
        img.at<cv::Vec3b>(t)[k] = 0;
    

Si on charge une image avec cv::imread en lui passant IMREAD_GRAYSCALE, alors l'image est codée en interne au format CV_8UC1 : 1 seul canal sur 8 bits.

  • Accéder au pixel x,y :
    img.at<uchar>(y,x)
    

On peut créer une image pour stocker des labels sur 32 bits signés avec

img.create(rows, cols, CV_32SC1);
puis accéder au pixel x,y par
img.at<int>(y,x)

Dans ces TPs avec Astico2D, les images sont systématiquement lues en couleur, puis seuillées et binarisées ; les images en entrée et en sortie pour les transformations sont en CV_32SC1.

Pour aller plus loin :

2. Exercices

Pour réaliser les exercices de ce TP, copiez le fichier demo1.cpp sous le nom tp1-vos-noms.cpp (voir intructions dans la page Rendus de TPs d'Ametice) ; pensez aussi à inscrire vos noms et la date de la version à la fin de l'entête.

Pour compiler votre programme utilisez la commande make et le fichier Makefile fourni (à ce stade, configurer un IDE serait une perte de temps).

Taille des lignes de code

Pensez à limiter la taille de vos lignes de code à (environ) 80 caractères, en alignant lorsque nécessaire (par exemple des tests à rallonge) de manière à en faciliter la relecture.

2.1 Marquage des contours

La fonction transform_horizontal_stripes reçoit une image img_int où les pixels sont soit à 0 (pixels du fond) ou à 255 (pixels de la forme) ; puis cette fonction remplace les pixels de la forme par une coordonnée pour afficher quelque chose.

Elle est déclenchée avec la touche 1, à partir de l'image originale seuillée avec le slider.

a) Renommer la fonction transform_horizontal_stripes en marquer_contours_c8. Dans cette fonction, marquer les points de tous les contours à 1, en utilisant la 8-connexité pour la forme (et donc la 4-connexité pour le fond).

Il suffit de balayer l'image, et de tester pour chaque pixel de la forme son 4-voisinage. Faire attention à ne pas sortir de l'image en testant les voisins ! (sinon, on peut considérer que les voisins en dehors de l'image sont à 0).

À l'issue de cette opération, les pixels pourront prendre les 3 valeurs :

  • 0 (noir) pixels du fond
  • 1 (bleu) pixels du contour de la forme
  • 255 (blanc) pixels de l'intérieur de la forme

b) Même question en renommant la fonction transform_vertical_stripes (déclenchée avec la touche 2 en marquer_contours_c4, cette fois en utilisant la 4-connexité pour la forme, et donc la 8-connexité pour le fond.

Cela revient à rajouter les voisins indirects dans votre test.

2.2 Numérotation des contours par balayage et fusion des labels

La fonction transform_diagonal_stripes est lancée avec la touche 3. Renommer la fonction en numeroter_contours_c8.

Dans cette fonction on se propose de numéroter tous les points du premier contour à 1, tous les points du deuxième contour à 2, etc, en utilisant la 8-connexité pour la forme, avec l'algorithme vu en cours.

Valeurs des pixels dans l'image :

  • en entrée : fond 0, forme 255
  • étape 1 : fond 0, forme 255, "déjà marqué" \(\neq\) 0 et 255
  • en sortie : fond 0, intérieur 255, contour \(\neq\) 0 et 255

Remarque : dans la première étape, le nouveau label risque rapidement d'atteindre 255 qui est la valeur associée à la forme. Pour éviter tout problème, passer de 254 à 256 ! De même pour le label final.

Annexe 1 : Liste des types Mat en OpenCV

Description des types de cv::Mat :

Unsigned 8bits uchar 0..255
    Mat:    CV_8UC1    CV_8UC2    CV_8UC3    CV_8UC4
    Pixel:  uchar      cv::Vec2b  cv::Vec3b  cv::Vec4b

Unsigned 16bits ushort 0..65535
    Mat:    CV_16UC1   CV_16UC2   CV_16UC3   CV_16UC4
    Pixel:  ushort     cv::Vec2w  cv::Vec3w  cv::Vec4w

Signed 16bits short -32768..32767
    Mat:    CV_16SC1   CV_16SC2   CV_16SC3   CV_16SC4
    Pixel:  short      cv::Vec2s  cv::Vec3s  cv::Vec4s

Signed 32bits int -2147483648..2147483647
    Mat:    CV_32SC1   CV_32SC2   CV_32SC3   CV_32SC4
    Pixel:  int        cv::Vec2i  cv::Vec3i  cv::Vec4i

Float 32bits float -1.18*10-38..3.40*10-38 
    Mat:    CV_32FC1   CV_32FC2   CV_32FC3   CV_32FC4
    Pixel:  float      cv::Vec2f  cv::Vec3f  cv::Vec4f

Double 64bits double 
    Mat:    CV_64FC1   CV_64FC2   CV_64FC3   CV_64FC4
    Pixel:  double     cv::Vec2d  cv::Vec3d  cv::Vec4d

Correspondance des types avec leur numéro interne (utile à connaître pour les messages d'erreur) :

C1 C2 C3 C4
CV_8U 0 8 16 24
CV_16U 2 10 18 26
CV_16S 3 11 19 27
CV_32S 4 12 20 28
CV_32F 5 13 21 29
CV_64F 6 14 22 30

Annexe 2 : Chercher une erreur avec gdb

Si votre programme toto.cpp plante et que vous avez du mal à trouver la cause de l'erreur, vous pouvez la chercher avec gdb :

  1. Dans Makefile, rajoutez -g à la fin de la ligne CFLAGS = ...

  2. Dans la console, tapez

    $ make clean toto
    $ gdb toto
    ...
    (gdb) run IMAGES/chat1.jpg
    
  3. Lorsque le programme a planté, tapez

    (gdb) bt
    

    (ou backtrace), puis examinez la pile d'appels.

    On peut aussi placer des points d'arrêts, faire une exécution pas à pas, etc ; voir par exemple ce tutoriel.

  4. Quand vous avez fini, tapez

    (gdb) quit