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 tapermake 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 canalk
: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);
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 :
- autres types et accès aux pixels, voir annexe 1 ci-dessous ;
- on peut faire des conversions de format avec
cv::Mat::convertTo()
; - pour un tutorial voir https://docs.opencv.org/master/d5/d98/tutorial_mat_operations.html
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
:
-
Dans
Makefile
, rajoutez-g
à la fin de la ligneCFLAGS = ...
-
Dans la console, tapez
$ make clean toto $ gdb toto ... (gdb) run IMAGES/chat1.jpg
-
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.
-
Quand vous avez fini, tapez
(gdb) quit