Introduction
On parle d'image ou de sous-image pour un tableau rectangulaire de pixels
contenant une information de couleur. Le terme de Carte de Pixels, PixMap
(pour Pixel Map) est aussi employé.
Il y a 3 commandes de base en OpenGL pour manipuler les images :
- glReadPixels permet de lire une PixMap dans un des tampons d'image, et de la stocker dans en mémoire centrale.
- glDrawPixels prend une PixMap stockée dans en mémoire centrale, et l'affiche dans un des tampons d'image.
- glCopyPixels copie une PixMap d'un tampon d'image dans un autre (qui peut être le même !), sans passer par la mémoire centrale.
Il est important de tenir compte de la manière dont les Pixels sont stockés.
Mode de Stockage des Pixels
C'est la fonction glPixelStore*(...)
qui définit le mode de stockage des pixels.
N.B. Par défaut les pixels sont alignés sur 4 octets. Dans
la plupart des cas, les données images que vous utiliserez seront
compactées au mieux, et donc alignées sur 1 octet.
Vous aurez sans doute à coeur d'appeler glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glReadPixels : Transférer une PixMap en mémoire centrale
La fonction glReadPixels(GLint
x,GLint y,GLsizei l,GLsizei h,GLenum format,GLenum
type,GLvoid *pixels);
Renvoie dans le tableau pixels le contenu d'une zone rectangulaire lue
dans le tampon chromatique sélectionné par glReadBuffer(),
ou bien lue dans le tampon Stencil ou dans le tampon de profondeur.
x et y indiquent la position du coin supérieur gauche du
rectangle de pixels (en coordonnées de fenêtre), et l et
w ses dimensions.
format permet de sélectionner la ou les composantes désirées,
et leur ordre (ex GL_RGB, GL_RED, GL_STENCIL_COMPONENT, GL_DEPTH_COMPONENT,
...)
type indique le type de données désiré pour chaque
composante. Chaque valeur sera mise à l'échelle pour s'adapter
au nombre de bits disponible.
N.B. les types de données peuvent être compactés.
Par exemple, le type GL_UNSIGNED_BYTE_3_3_2 pour un format GL_RVB
renverra un octet par pixel, avec les composantes Rouge et Verte sur 3 bits,
et la Bleue sur 2 bits.
Exemple : Sauvegarde du contenu de la fenêtre
Voici un exemple de récupération du contenu de la fenêtre
dans un tableau pixels, et de sa sauvegarde dans le fichier filename au format PPM binaire.
void my_grab_ppm (const string & filename)
{
int viewport [4];
glGetIntegerv (GL_VIEWPORT, viewport);
int larg = viewport [2]; if (larg & 1) ++larg; //Pour avoir des valeurs paires
int haut = viewport [3]; if (haut & 1) ++haut;
ofstream file (filename.c_str (), ios::out|ios::binary);
if (! file)
cerr << "Cannot open file \"" << filename.c_str () << "\"!\n";
else
{
file << "P6\n#\n" << larg << ' ' << haut << "\n255\n";
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
char * pixels = new char [3 * larg * haut];
glReadPixels (0, 0, larg, haut, GL_RGB, GL_UNSIGNED_BYTE, pixels);
char * ppix = pixels + (3 * larg * (haut - 1));
for (unsigned int j = haut; j-- ; ppix -= 3 * larg) file.write (ppix, 3 * larg);
delete[] pixels;
file.close ();
}
cout << "grabbed \"" << filename << "\".\n";
}
Thanks Aassif !
glDrawPixels : Afficher une PixMap
La fonction glDrawPixels(GLsizei
l,GLsizei h,GLenum format,GLenum type,GLvoid *pixels);
Affiche le tableau pixels dans l'un des tampons d'image (tampon chromatique
sélectionné en écriture avec glDrawBuffer(),
ou tampon stencil ou tampon de profondeur).
l et w: sont la largeur et la hauteur du tableau pixels.
format et type ont la même signification que dans glReadPixels(...)
N.B. Le tableau est placé à partir de la position de trame
active, définie par la fonction glRasterPos*(...).
glCopyPixels : Copier des pixels dans le tampon d'image
La fonction glCopyPixels(GLint
x,GLint y,GLsizei l,GLsizei h,GLenum buffer);
Copie le rectangle de pixels de largeur et hauteur l et h, situé
en (x, y),
depuis le tampon d'image sélectionné en lecture, ou le tampon
stencil, ou le tampon de profondeur,
dans le tampon d'image sélectionné en écriture, ou le tampon
stencil, ou le tampon de profondeur.
La nouvelle position est définie par la position de trame active.
buffer spécifie le tampon d'image utilisé (GL_COLOR,
GL_STENCIL ou GL_DEPTH)
N.B. Il n'est pas nécessaire d'utiliser un paramètre format,
puisque les données ne transitent pas par la mémoire centrale.
glCopyTexImage2D : Copier directement des pixels dans la mémoire de texture
Il est possible d'effectuer une copie directe d'un tampon d'image dans la mémoire
de texture, sans passer par la mémoire centrale, grâce
à
la fonction glCopyTexImage2D(GLenum
target, GLint level, GLenum internalformat, GLint x,
GLint y, GLsizei l, GLsizei h, GLint bordure);
target vaut GL_TEXTURE_2D
level est le niveau de détail choisi, de 0 pour
l'image de base àn pour la nième image mipmap.
internalformat est le format de la texture choisie. Une valeur courante
est GL_RGBA. Les valeurs possibles sont :
GL_ALPHA, GL_ALPHA4, GL_ALPHA8, GL_ALPHA12, GL_ALPHA16, GL_LUMINANCE, GL_LUMINANCE4,
GL_LUMINANCE8, GL_LUMINANCE12, GL_LUMINANCE16, GL_LUMINANCE_ALPHA, GL_LUMINANCE4_ALPHA4,
GL_LUMINANCE6_ALPHA2, GL_LUMINANCE8_ALPHA8, GL_LUMINANCE12_ALPHA4, GL_LUMINANCE12_ALPHA12,
GL_LUMINANCE16_ALPHA16, GL_INTENSITY, GL_INTENSITY4, GL_INTENSITY8, GL_INTENSITY12,
GL_INTENSITY16, GL_RGB, GL_R3_G3_B2, GL_RGB4, GL_RGB5, GL_RGB8, GL_RGB10, GL_RGB12,
GL_RGB16, GL_RGBA, GL_RGBA2, GL_RGBA4, GL_RGB5_A1, GL_RGBA8, GL_RGB10_A2, GL_RGBA12,
or GL_RGBA16
C'est le rectangle de pixels de largeur et hauteur l et h, situé
en (x, y) qui sera copié
bordure vaut 0 ou 1.
N.B. La largeur et la hauteur doivent être de la forme 2^n+2*bordure,
et 2^m+2*bordure. n et m peuvent être différents.
Traitement d'image
Agrandir ou réduire une image
La fonction glPixelZoom(GLfloat
xfactor, GLfloat yfactor) permet d'agrandir ou de réduire
un rectangle de pixels avant qu'il ne soit dessiné. Les paramètres
peuvent même être négatifs pour inverser l'image.
L'Imaging Subset est une collection de routines de traitement d'image :
Cette extension OpenGL est présente si le jeton GL_ARB_imaging est
défini. Elle permet :
- d'utiliser des tables de correspondance pour remplacer les valeurs des
pixels, avec glColorTable(...).
cf colortable.c
- d'utiliser des convolutions pour filtrer les images, avec glConvolutionFilter2D(...).
cf convolution.c
- d'utiliser des transformations linéaires comme les transformations
de couleur, grâce aux transformations sur les matrices chromatiques
: glMatrixMode(GL_COLOR).
cf colormatrix.c
- de collecter des informations sur les images : histogramme (avec glHistogram(...),
cf histogram.c), min et max (avec
glGetMinMax(...), cf minmax.c)
- de calculer la somme, la différence, le min, le max de deux images
grâce aux équations de blending (avec glBlendEquation(...),
cf blendeqn.c)
- d'utiliser des facteurs de blending pour modifier les couleurs des pixels,
avec glBlendFunc(...)
Exercices
Affichage du tampon de profondeur
Ouvrez deux viewports dans une fenêtre, et affichez dans celui de droite le tampon de profondeur correspondant à la scène de gauche.

L'image dans l'image
Ajoutez à votre classe Texture un constructeur Texture(GLuint larg,
GLuint haut); qui va créer une texture à partir d'un tampon
chromatique (en faisant attention à la taille...). Et utilisez une texture ainsi définie pour copier
tout le contenu de l'image.
Vous utiliserez cette texture plaquée sur un quadrilatère
que vous placerez dans la scène en en choisissant les dimensions, la position et l'orientation
Motion blur efficace
Vous pouvez maintenant placer le quadrilatère pour qu'il apparaisse dans le fond de votre fenêtre, et
mélanger le
contenu de votre scène à l'image précédente
de la scène. Comparez l'efficacité avec celle du Tampon d'Accumulation.
17 décembre 2012