Créer des images transparentes avec CodeBlocks et OpenCV


Il est possible, en utilisant un logiciel graphique (GIMP par exemple) de placer une image transparente sur une photo, sans modifier les dimensions de cette photo. L'image transparente (appelée "masque") peut être préalablement enregistrée dans un fichier .png. Cette technique peut être utilisée pour encadrer une photo ou pour ajouter un texte, une signature, un copyright ou un dessin à cette photo.

Cette page montre comment créer automatiquement une image transparente d'une taille quelconque, destinée à être appliqué sur une photo de même taille. Pour cela on utilise l'environnement de développement CodeBlocks avec la librairie graphique OpenCV qui sont des produits libres. Remarque : La page Programmer avec CodeBlocks et OpenCV montre comment installer et mettre en oeuvre cet l’environnement.

Programme exemple

L'exemple ci-après crée une image transparente de W x H pixels puis l'enregistre dans un fichier "C:/cadre-noir-blanc.png" avec le format png non compressé (qualité maximale). Cette image contient un encadrement présentant les caractéristiquesindiquées ci-après. On peut obtenir une infinité d'images différentes en modifiant les paramètres qui figurent au début du programme :

  • encadrement : couleur intérieure b, g, r, a (blue, gree, red, alpha) et largeur d pixels
  • ligne frontière intérieure de l'encadrement : couleur bc, gc, rc, ac et épaisseur e pixels)

Cet exemple permet d'appliquer un encadrement particulier à une photo de taille quelconque sans modifier les dimensions de cette photo. Pour appliquer cet encadrement transparent à un grand nombre de photos de façon automatique (traitement par lot), consulter la page suivante : Gimp Script-Fu - Ajouter un masque à une image.

1

Code source

/*--------- CREATION AUTOMATIQUE DE MASQUES ‹ ›
Auteur : Claude Turrier - juin 2016
----------*/
#include "stdio.h"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
int main( )
{
//--------- Valeur modifiables ---------
int W=1200, H=800; //largeur et hauteur image
int d=20; //largeur encadrement
unsigned char b=0, g=0, r=0, a=127; //couleur encadrement
int e=1; //épaisseur ligne intérieure
unsigned char bc=255, gc=255, rc=255, ac=255;//couleur ligne intérieure
//---------- ---------------- --------- Mat m(H, W, CV_8UC4, Scalar(0,0,0,0)); //image BGRA noire transparente
int x0=d, y0=d, x1=W-1-d, y1=d, x2=W-1-d, y2=H-1-d, x3=d, y3=H-1-d;
//création d'un cadre blanc de 1 pixel entre les points ((x0,y0) et (x2, y2)
line( m, Point( x0, y0 ), Point( x1, y1), Scalar( bc, gc, rc, ac ), e, 8 ); //haut
line( m, Point( x1, y1 ), Point( x2, y2), Scalar( bc, gc, rc, ac ), e, 8 ); //Bas
line( m, Point( x2, y2 ), Point( x3, y3), Scalar( bc, gc, rc, ac ), e, 8 ); //Gauche
line( m, Point( x3, y3 ), Point( x0, y0), Scalar( bc, gc, rc, ac ), e, 8 ); //Droit
//remplissage du dessus
for(int i = 0; i < d; i++){
for(int j = 0; j < W; j++){
Vec4b &v = m.at<Vec4b>(i,j);
v[0] = b;
v[1] = g;
v[2] = r;
v[3] = a;
}}
//remplissage du dessous
for(int i = H-d; i < H; i++){
for(int j = 0; j < W; j++){
Vec4b &v = m.at<Vec4b>(i,j);
v[0] = b;
v[1] = g;
v[2] = r;
v[3] = a;
}}
//remplissage gauche
for(int i = d ; i < H-d; i++){
for(int j = 0; j < d; j++){
Vec4b &v = m.at<Vec4b>(i,j);
v[0] = b;
v[1] = g;
v[2] = r;
v[3] = a;
}}
//remplissage droit
for(int i = d ; i < H-d; i++){
for(int j = W-d; j < W; j++){
Vec4b &v = m.at<Vec4b>(i,j);
v[0] = b;
v[1] = g;
v[2] = r;
v[3] = a;
}}
namedWindow("m", WINDOW_AUTOSIZE);
imshow("m", m);
//enregistrement -&image sans compression
vector compression;
compression.push_back ( CV_IMWRITE_PNG_COMPRESSION );
compression.push_back(0); // 0 (sans compression) -> 9 (compression max)
imwrite("C:/cadre-noir-blanc.png", m, compression);
waitKey(0);
return 1;
}

Télécharger le code source cadre-noir-blanc.cpp

Exécution du programme

A l’exécution, la transparence de l’image png n’est pas visible dans la fenêtre du progamme mais cette transparence est bien présente dans le fichier « C:/cadre-noi-blanc.png» créé, comme on peut le contaster en ouvrant ce fichier avec GIMP.

2

Utilisation de l'image transparente

Il ne reste plus qu’à placer ce masque sur une photo, à l’aide de GIMP par exemple.

3

Le cadre suivant a été créé avec W=1200, H=800, d=20, b=0, g=0, r=0, a=127, e=1, bc=255, gc=255, rc=255 et ac=255.

photo encadre

Il est à noter que lorsqu'il est supérieur à 1 le parammètre épaisseur (thickness) de la fonction line fonctionne à 1 pixel près. Par exemple une valeur e=1 conduit à un tracé de ligne de 1 pixel d'épaisseur mais les valeurs e=4 et e=5 conduisent à des tracés de lignes dont les épaoisseurs sont respectivement égales à 3 et 4 pixels. Par exemple, le cadre suivant a été créé avec W=1200, H=800, d=4, b=0, g=0, r=0, a=0, e=5, bc=255, gc=255, rc=255 et ac=255. Pour obtenir une ligne d'épaisseur 4 pixels, on a fixé e=5.

//--------- Valeur modifiables ---------
int W=1200, H=800; //largeur et hauteur image
int d=4; //largeur encadrement
unsigned char b=0, g=0, r=0, a=255; //couleur encadrement
int e=5; //épaisseur ligne intérieure
unsigned char bc=255, gc=255, rc=255, ac=255;//couleur ligne intérieure
//---------- ---------------- ---------

 6

Ce qui conduit au rendu suivant..

photo encadre2

Documentation

Classe cv::Mat

Mat::Mat(int rows, int cols, int type) est une classe C++ de OpenCV qui représente des tableaux multidimensionnels à un ou à plusieurs canaux (matrices). D'une façon générale, cette classe peut être utilisée pour ranger des vecteurs ou des matrices. Lorsqu'on manipule des images, le gros avantage à utiliser des classes C++ comme Mat (par rapport à d'anciennes fonctions C de OpenCV comme par exemple IplImage) c'est qu'avec ces classes, le programmeur n'a pas besoin d'allouer et de libérer lui-même la mémoire au fil du programme. Cela se fait automatiquement.

La classe Mat, lorsqu'elle est utilisée pour stocker une image comprend deux parties :
• une partie En-tête de taille fixe qui contient des informations générales comme la taille et l'adresse de la partie données ;
• un pointeur vers la partie données qui contient les valeurs des pixels de l'image et qui est donc de taille variable (selon la taille de l'image).

Il est à noter que OpenCV manipule les couleurs RGB dans le sens BGR (Blue = B, Green = G et Red = R). Par exemple, OpenCV code la couleur rouge (0,0,255) et non pas (255,0,0,).

Exemple :
Le programme suivant crée un objet m de classe Mat, doté de 2 lignes, 3 colonnes, du type CV_8UC4 (4 canaux de 8 bits chacun, c’est à dire BGRA) et initialisé avec la valeur BGRA = (0,0,255,127).
#include ‹iostream›
#include ‹opencv2/core/core.hpp›
#include ‹opencv2/highgui/highgui.hpp›
using namespace cv;
using namespace std;
int main( )
{
Mat m(2,3, CV_8UC4, Scalar(0,0,255,127));
cout ‹‹ "m = "‹‹ endl; cout ‹‹ " " ‹‹ m ‹‹ endl;
waitKey(0);
return(0);
}

4

Chaque élément de la matrice 2x3 est un vecteur de 4 éléments BGRA.
5

Constructeur cv ::Mat ::Mat

Un objet de la classe Mat peut être construit de plusieurs façons. La syntaxe Mat m(h,w, CV_8UC4, Scalar(b,g,r,a)); crée un objet m de h lignes, w colonnes, de type pixels RGBA (8UC4=> 4 canaux de 8bits chacun) initialisés avec la valeur (b,g,r,a)

Exemple : Mat m(2,3, CV_8UC4, Scalar(0,0,255,127)); image de 2 pixels de hauteur et 3 pixels de largeur initialiée en rouge transparent à 50% (127/225).

Méthode cv::Mat ::at

Soit m un objet de la classe Mat. La procédure m.at retourne la référence de l’élément spécifié. La syntaxe est <typename›& T m.at <typename>(i,j). Par exemple Vec4b &v = m.at<Vec4b>(i,j); <typename> est le type d’élément du tableau. Dans le cas d’une image, c’est un vecteur de 4 éléments BGRA donc <Vec4b>. Dans un tableau, i représente un numéro de ligne et j un numéro de colonne. Enfin, & T est l’adresse de l ‘élément (i,j) du tableau

Type Vec4b

Vec4b est un type de vecteur Vec composé de 4 Unsigned char, c’est à dire de 4 nombres de 8 bits pouvant varier de 0 à 255 (comme les valeurs des couleurs RGBA). On a typedef Vec<uchar,4 > Vec4b;

Méthode cv ::line

La méthodecv ::line permet de dessiner une ligne entre deux points.

void line(m, Point pt1, Point pt2, Scalar(b,g,r,a), thickness, int type=8, int shift=0);
m : tableau (type Mat)
pt1 : Premier point de la ligne (type Point)
pt2 : Second point de la ligne (type Point)
Scalar(b,g,r,a) : couleur de la ligne
thickness : épaisseur de la ligne en pixels (type int)
type : type de ligne (8 pour une ligne sans antialiasing) (type int)
Exemple
Mat m(100,200, CV_8UC4, Scalar(0,0,0,0));
line( m, Point( 0, 0 ), Point( 1200, 800), Scalar( 0, 0, 255,255 ), 1, 8 );//BGRA image

Classe cv ::Point

Cv ::Point est une classe qui représente les points 2D spécifiés par leur coordonnées x et y.

Exemples
Point pt; pt.x = 10; pt.y = 5;
Point pt = Point(10, 5);
line( m, Point( 0, 0 ), Point( 1200, 800), Scalar( 0, 0, 255,255 ), 1, 8 );//BGRA image

Type Scalar

Le type Scalar représente un vecteur à 4 éléments. Il est dérivé du type Vec<Tp,4>. Le type Scalar est souvent utilisé avec OpenCV pour passer des valeurs de pixels. Pour représenter une couleur, on écrit Scalar( b, g, r ) avec b=blue, g=green et r=red.

Exemple
line( m, Point( 0, 0 ), Point( 1200, 800), Scalar( 0, 0, 255,255 ), 1, 8 );//BGRA image

Classe std::vector

std::vector est une classe qui représente un container pour ranger des valeurs de différents types. La classe std::vector <int> représente un container pour ranger des valeurs de type int

Méthode std::vector::push_back

La méthode std::vector::push_back ajoute un nouvel élément à la fin d'un vector, ce qui augmente la taille du container correspondant.

Exemple
std::vector‹int› monvecteur;
int n=0;
monvecteur.push_back (n);

Classe cv::imwrite

La méthode imwrite permet d’enregistrer une image dans un fichier.

bool imwrite( string filename, Mat m, vector‹int› compression)

  • filename : string - nom complet chemin + fichier.
  • m : Image à enregistrer
  • Compression : paramètres de compression de l'image Pour une image jpeg, il faut utiliser le paramètre CV_IMWRITE_JPEG_QUALITY et définir un taux de qualité pouvant varier de 0 à 100 (en l'absence d'indication de ces paramètres, la valeur retenue par défaut est 95). Pour une qualité maximum, indiquer 100. Pour une image png, il faut utiliser le paramètre CV_IMWRITE_PNG_COMPRESSION et définir un taux de compression de 0 à 9 (en l'absence de précision de ces paramètres, la valeur retenue par défaut est 3). Pour une qualité maximum indiquer 0.

Exemple
Mat m(800, 1200, CV_8UC4, Scalar(0,0,0,0)); //image BGRA noire transparente
vector compression;
compression.push_back ( CV_IMWRITE_PNG_COMPRESSION );
compression.push_back(0); // 0 (sans compression) -> 9 (compression max)
imwrite("C:/cadre-noir-blanc.png", m, compression);
...

Méthode cv::namedWindow

La méthode cv::namedWindow crée une fenêtre. Le programmeur peut appeler les fonctions destroyWindow() ou destroyAllWindows() pour fermer la fenêtre et libérer la mémoire mais cela n'est pas indispensable car les fenêtres sont automatiquement fermées et la mémoire correspondante libérée à la fin de l'exécution du programme.

void namedWindow(const string& winname, int flags=WINDOW_AUTOSIZE )

  • name : nom de la fenêtre, affiché dans la barre de titre
  • flags - type de fenêtre : WINDOW_NORMAL (l'utilisateur peut redimensionner manuellement la fenêtre), WINDOW_AUTOSIZE (la taille de la fenêtre s'ajuste à la taille de l'image et ne peut pas être modifiée manuellement), WINDOW_OPENGL (si la fenêtre est créée avec OpenGL ).

Méthode cv::imshow

La méthode cv::imshow affiche une image dans la fenêtre spécifiée. Si la fenêtre a été créée avec le paramètre CV WINDOW AUTOSIZE, l'image est affichée avec sa taille d'origine sinon elle est automatiquement dimensionnée pour tenir dans la fenêtre.

void imshow( const string& winname, const Mat& image );

  • winname : nom de la fenêtre
  • image : image affichée dans la fenêtre