10.03.2014 Views

transparents du cours en PDF - IUT d'Arles

transparents du cours en PDF - IUT d'Arles

transparents du cours en PDF - IUT d'Arles

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

Imagerie Numérique<br />

Représ<strong>en</strong>tation et codage des images<br />

2. Implém<strong>en</strong>tation d’une<br />

classe Image <strong>en</strong> C++<br />

E. Remy<br />

<strong>IUT</strong> de Prov<strong>en</strong>ce<br />

7/01/2003


19/10/2003 2<br />

ATTENTION<br />

CE COURS NECESSITE UNE REECRITURE<br />

COMPLETE POUR ETRE EN<br />

SYNCHRONISATION AVEC LE<br />

PROGRAMME UTILISE EN TRAVAUX<br />

PRATIQUES.<br />

ETANT ENCORE UTILE TEL QUEL, IL EST<br />

DONNE A TITRE INDICATIF…


19/10/2003 3<br />

Préliminaires<br />

• 3 façons classiques de coder une image :<br />

• Une image « directe » dont chaque pixel conti<strong>en</strong>t un<br />

vecteur de couleur, par exemple (R,V,B) ;<br />

• Un vecteur d’images « directes » dont les pixels<br />

conti<strong>en</strong>n<strong>en</strong>t une et une seule composante parmi R, V<br />

et B. Il faut donc avoir les 3 images pour pouvoir<br />

interpréter le codage.<br />

• Une palette plus une image cont<strong>en</strong>ant les indices de<br />

couleurs utilisés dans la palette.


19/10/2003 4<br />

Cahier des charges<br />

• Coder toutes les formes d’images bitmap 2D (codage<br />

direct ou codage avec palette, noir et blanc, gris,<br />

couleur, etc).<br />

• Capacité de modifier le cont<strong>en</strong>u de l’image.<br />

• Opérations de conversion faciles d’un type d’image à<br />

un autre.<br />

• Lecture et écriture de l’image dans un fichier sur le<br />

disque <strong>du</strong>r dans plusieurs choix de formats.


19/10/2003 5<br />

Attributs de la classe<br />

Des dim<strong>en</strong>sions :<br />

• Largeur et hauteur<br />

• <strong>en</strong>tières et strictem<strong>en</strong>t positives.<br />

Le tableau de pixel :<br />

• Type de pixel variable : pixel_type<br />

• Taille <strong>du</strong> tableau varie d’une instance à<br />

l’autre, donc allocation dynamique.<br />

• Tableau « à plat » (schéma).<br />

Pour des raisons de performance, on veut que<br />

les classes héritant de Image puiss<strong>en</strong>t avoir<br />

accès directem<strong>en</strong>t aux données :<br />

• Droit d’accès « protected ».<br />

template<br />

class Image {<br />

protected:<br />

unsigned int dimx,dimy<br />

dimy;<br />

pixel_type *array;<br />

};


19/10/2003 6<br />

Méthodes primitives<br />

Consultation de la largeur et de<br />

la hauteur :<br />

• Obt<strong>en</strong>ir la valeur, mais…<br />

• Ne pas pouvoir la changer !<br />

Modification de la largeur et de<br />

la hauteur :<br />

• Pouvoir changer la taille de<br />

l’image ;<br />

• Réallouer le tableau de pixels,<br />

sans préservation de l’image<br />

qui est dedans.<br />

• On suppose que le tableau est<br />

déjà alloué avant, ou qu’il est<br />

bi<strong>en</strong> indiqué comme étant à<br />

l’adresse NULL.<br />

inline unsigned int GetDimX(void<br />

void) const<br />

{ return dimx; ; }<br />

inline unsigned int GetDimY(void<br />

void) const<br />

{ return dimy; ; }<br />

void SetSize(const<br />

unsigned int dimx,<br />

const unsigned int _dimy)<br />

{<br />

delete [] array;<br />

dimx = _dimx;<br />

dimy = _dimy;<br />

array = new pixel_type[dimx<br />

dimx*dimy];<br />

}


19/10/2003 7<br />

Modification d’un pixel<br />

Vérification des<br />

paramètres ;<br />

Gestion d’erreur<br />

avec des<br />

exceptions ;<br />

Adressage d’un<br />

pixel dans le<br />

tableau linéaire ;<br />

Modification <strong>du</strong><br />

pixel si les<br />

paramètres sont<br />

valides.<br />

void SetPixel(const<br />

unsigned int x, const unsigned int y,<br />

const pixel_type pixel_value)<br />

{<br />

if(x >= dimx)<br />

{<br />

std::<br />

::ostringstream<br />

s;<br />

s


19/10/2003 8<br />

Consultation d’un pixel<br />

Méthode constante :<br />

on ne modifie pas<br />

l’image <strong>en</strong> la<br />

consultant.<br />

Vérification des<br />

paramètres ;<br />

Gestion d’erreur<br />

avec des exceptions ;<br />

Adressage d’un pixel<br />

dans le tableau<br />

linéaire ;<br />

R<strong>en</strong>voi d’une<br />

référ<strong>en</strong>ce constante<br />

sur le pixel dans le<br />

tableau afin d’éviter<br />

une construction par<br />

copie.<br />

const pixel_type& GetPixel(const<br />

unsigned int x,<br />

const unsigned int y) const<br />

{<br />

if(x >= dimx)<br />

{<br />

std::<br />

::ostringstream<br />

s;<br />

s


19/10/2003 9<br />

void Copy(const<br />

Image& source)<br />

{<br />

Copie d’une image<br />

SetSize(source.dimx<br />

source.dimx,source.dimy);<br />

for(unsigned<br />

long tmax = dimx*dimy<br />

dimy,t=0; t


19/10/2003 10<br />

Constructeurs<br />

Image(const<br />

unsigned int _dimx=0,<br />

const unsigned int _dimy=0)<br />

: dimx(0),<br />

(0),dimy(0),array(NULL)<br />

{ SetSize(_dim<br />

_dimx, x,_dimy); }<br />

• Valeurs des paramètres par défaut : correspond à une image de taille nulle.<br />

• Par sécurité, on utilise la liste d’initialisation pour mettre des d<br />

valeurs<br />

signifiant que l’image est vide, et on utilise uniquem<strong>en</strong>t la méthode<br />

SetSize()<br />

() pour effectuer l’allocation <strong>du</strong> tableau.<br />

Image(const Image& i)<br />

: dimx(0),dimy(0),array(NULL)<br />

{ Copy(i); }<br />

• Utilise la méthode Copy()<br />

• Ne pas abuser <strong>du</strong> constructeur de copie puisqu’il nécessite la coûteuse<br />

recopie pixel par pixel de l’image source.


19/10/2003 11<br />

Destructeur<br />

~Image()<br />

{ delete [] array; ; }<br />

• Le destructeur est trivial.<br />

• Son seul rôle est de libérer la mémoire prise par le tableau.<br />

• On aurait pu utiliser SetSize(0,0)<br />

qui aurait eu un effet s<strong>en</strong>siblem<strong>en</strong>t<br />

équival<strong>en</strong>t, mais il était inutile de placer les largeurs et hauteur à zéro pour<br />

<strong>en</strong>suite de toutes façons détruire l’instance…<br />

Opérateur d’affectation<br />

inline void operator=(const Image&<br />

src)<br />

{ Copy(src); }<br />

• Très semblable au constructeur de copie ;<br />

• Même coût de recopie.


19/10/2003 12<br />

Conversion implicite<br />

template<br />

void Convert(const<br />

Image& source)<br />

{<br />

SetSize(source.GetDimX<br />

source.GetDimX(), (),source.GetDimY());<br />

for(unsigned<br />

int y=0;y


19/10/2003 13<br />

Conversion explicite<br />

template<br />

void Convert(const<br />

Image& source,<br />

pixel_type (*conversion)(const<br />

const any_type))<br />

{<br />

SetSize(source.GetDimX<br />

source.GetDimX(), (),source.GetDimY());<br />

for(unsigned<br />

int y=0;y


19/10/2003 14<br />

Constructeur (suite)<br />

template<br />

Image(const<br />

Image& i,<br />

pixel_type (*conversion)(const<br />

const any_type))<br />

: dimx(0),<br />

(0),dimy(0),array(NULL)<br />

{ Convert(i,<br />

i,conversion); ; }<br />

• On rajoute un constructeur supplém<strong>en</strong>taire reposant sur la conversion<br />

explicite.<br />

• Il permet de créer directem<strong>en</strong>t une instance d’une image <strong>en</strong> effectuant la<br />

conversion explicite avec une fonction de conversion.


19/10/2003 15<br />

Type byte<br />

typedef unsigned char byte;<br />

const byte byte_MIN(0);<br />

const byte byte_MAX(UCHAR_MAX);<br />

• On définit un type byte correspondant à un <strong>en</strong>tier positif codé sur une<br />

taille de 8 bits (1 octet).<br />

• On définit aussi deux constantes qui sont les bornes supérieures et<br />

inférieures de l’intervalle de définition de ce type byte.<br />

• Ces définitions sont repos<strong>en</strong>t sur la définition de l’unsigned<br />

char dans la<br />

norme C++ 98. Idem pour UCHAR_MAX dont la définition est incorporées<br />

<strong>en</strong> faisant #include<br />

.


19/10/2003 16<br />

Type Gray<br />

typedef byte Gray;<br />

const Gray Gray_MIN(0);<br />

const Gray Gray_MAX(byte_MAX);<br />

• En se servant de byte, , on définit maint<strong>en</strong>ant un type Gray permettant de<br />

mémoriser un niveau de gris compris <strong>en</strong>tre 0 (Gray_MIN(<br />

Gray_MIN) ) et 255<br />

(Gray_MAX).<br />

• La définition <strong>du</strong> type byte était attachée à l’idée de taille 1 octet.<br />

• La définition de ce type Gray est liée au concept de niveau de gris.<br />

• On a vu précédemm<strong>en</strong>t que 255 niveaux de gris étai<strong>en</strong>t bi<strong>en</strong> plus que q<br />

ce<br />

que le système visuel humain est capable de percevoir. Notre codage sera<br />

donc probablem<strong>en</strong>t suffisant dans tous les cas.


Classe Color (1/2)<br />

class Color {<br />

byte red,gre<strong>en</strong>,blue;<br />

public:<br />

Color(byte r=0,byte g=0,byte b=0) : red(r),gre<strong>en</strong>(g),blue(b) ) {}<br />

Color(Gray g): red(g),gre<strong>en</strong>(g),blue(g) ) {}<br />

inline byte GetRed(void) ) const { return red; }<br />

inline byte GetGre<strong>en</strong>(void) ) const { return gre<strong>en</strong>; }<br />

inline byte GetBlue(void) ) const { return blue; }<br />

…<br />

};<br />

• Toujours <strong>en</strong> se servant de byte, , on définit maint<strong>en</strong>ant une classe Color<br />

permettant de mémoriser un vecteur couleur dans l’espace RGB.<br />

• Chaque composante <strong>du</strong> vecteur de couleur est codé par un byte, , et est<br />

donc compris <strong>en</strong>tre 0 (byte_MIN(<br />

byte_MIN) ) et 255 (byte_MAX(<br />

byte_MAX).<br />

• Le constructeur permet de faire par défaut une couleur noire (0,0,0).<br />

0,0).<br />

• 3 accesseurs permett<strong>en</strong>t d’obt<strong>en</strong>ir les valeurs de chaque composante, mais<br />

pas de les modifier. Pour modifier une couleur, <strong>en</strong> fait il faut <strong>en</strong> déclarer<br />

une autre, et se servir des paramètres <strong>du</strong> constructeur.<br />

19/10/2003 17


19/10/2003 18<br />

Classe Color (2/2)<br />

class Color {<br />

…<br />

fri<strong>en</strong>d inline bool operator==(const Color& c1,const Color& c2)<br />

{ return c1.red==c2.red && c1.gre<strong>en</strong>==c2.gre<strong>en</strong> && c1.blue==c2.blue; ue; }<br />

fri<strong>en</strong>d inline bool operator!=(const Color& c1,const Color& c2)<br />

{ return c1.red!=c2.red || c1.gre<strong>en</strong>!=c2.gre<strong>en</strong> || c1.blue!=c2.blue; ue; }<br />

inline Color& operator=(const Color& c)<br />

{ red=c.red<br />

c.red; ; gre<strong>en</strong>=c.gre<strong>en</strong><br />

c.gre<strong>en</strong>; ; blue=c.blue<br />

c.blue; ; return *this; }<br />

fri<strong>en</strong>d std::ostream& & operator


19/10/2003 19<br />

Classe GrayImage<br />

class GrayImage : public Image {<br />

public:<br />

GrayImage(const unsigned int dimx=0,const unsigned int dimy=0)<br />

: Image(dimx,dimy<br />

dimx,dimy)<br />

{}<br />

template<br />

GrayImage(const Image& source)<br />

: Image(0,0)<br />

{ Convert(source); }<br />

…<br />

};<br />

• On la fait hériter de Image afin de bénéficier de tout ce qui est déjà<br />

défini pour une template > Image.<br />

• On rajoutera au niveau de cette classe des méthodes spécifiques à une<br />

image <strong>en</strong> niveau de gris (<strong>en</strong> particulier, des méthodes de lecture et<br />

d’écriture d’image <strong>en</strong> niveau de gris).


19/10/2003 20<br />

Classe ColorImage<br />

class ColorImage : public Image {<br />

public:<br />

ColorImage(const unsigned int dimx=0,const unsigned int dimy=0)<br />

: Image(dimx,dimy<br />

dimx,dimy)<br />

{}<br />

template<br />

ColorImage(const Image& source)<br />

: Image(0,0)<br />

{ Convert(source); }<br />

…<br />

};<br />

• Exactem<strong>en</strong>t le même principe, mais avec Image.<br />

• Ici aussi, on rajoutera des méthodes spécifiques aux images <strong>en</strong> couleurs. c


19/10/2003 21<br />

Classe PaletteImage<br />

template<br />

class PaletteImage : public Image<br />

{<br />

protected:<br />

unsigned int palette_count,palette_max;<br />

pixel_type *palette;<br />

…<br />

};<br />

• Images définies avec une palette ;<br />

• Rester indép<strong>en</strong>dant <strong>du</strong> type des « couleurs » utilisées comme pour<br />

Image.<br />

• On hérite de Image car l’image conti<strong>en</strong>t des numéros de<br />

position des couleurs dans le tableau palette. (schéma)<br />

• On utilise un template pour ne pas verrouiller le type des élém<strong>en</strong>ts <strong>du</strong> tableau<br />

palette.


19/10/2003 22<br />

Constructeur et destructeur de la<br />

classe PaletteImage<br />

PaletteImage(const unsigned int dimx=0,const unsigned int dimy=0,<br />

const unsigned int _palette_max=0)<br />

: Image(dimx,dimy),palette_count(0),<br />

palette_max(_palette_max),palette(NULL)<br />

{ palette = new pixel_type[_palette_max]; }<br />

~PaletteImage()<br />

{ delete [] palette; }<br />

• On décide de contraindre l’utilisateur a donner <strong>en</strong> paramètre <strong>du</strong><br />

constructeur la borne supérieure <strong>du</strong> nombre de couleurs pouvant être ê<br />

mémorisées dans la palette.<br />

• Ce nombre permet d’allouer la palette au mom<strong>en</strong>t de la création de d<br />

l’image.<br />

• Contre partie : la palette est pour l’instant de taille fixe.


19/10/2003 23<br />

Copie d’une PaletteImage<br />

void Copy(const PaletteImage& source)<br />

{<br />

palette_count = source.palette_count;<br />

palette_max<br />

= source.palette_max;<br />

delete [] palette;<br />

palette = new pixel_type[palette_max];<br />

for(unsigned int i=0;i::Copy(source);<br />

}<br />

• Copier une PaletteImage c’est copier la palette…<br />

• Puis copier le tableau d’index.<br />

Consultation d’un pixel<br />

const pixel_type& GetPixel(unsigned int x,unsigned int y) const<br />

{ return palette[Image::<br />

>::GetPixel(x,y)]; }


19/10/2003 24<br />

Modification d’un pixel (1/2)<br />

Pour écrire un pixel avec une couleur donnée, il faut :<br />

1. Trouver si cette couleur est prés<strong>en</strong>te dans la palette actuelle, et<br />

noter son numéro.<br />

2. Si oui, utiliser ce numéro dans le tableau de points.<br />

3. Si non, utiliser une <strong>en</strong>trée libre de la palette pour stocker la<br />

couleur, noter son numéro, et l’utiliser dans le tableau de<br />

points.<br />

4. Si la palette est pleine, il y a échec de l’opération.<br />

On intro<strong>du</strong>it donc deux opérations avant d’écrire PutPixel()<br />

:<br />

• FindPaletteIndex()<br />

et<br />

• AllocatePaletteEntry()<br />

().


19/10/2003 25<br />

Recherche d’une couleur dans la palette<br />

unsigned int FindPaletteIndex(const pixel_type pixel)<br />

{<br />

unsigned int i;<br />

for(i=0;i<<br />

=0;i


19/10/2003 26<br />

Allocation d’une (nouvelle) couleur dans<br />

la palette<br />

unsigned int AllocatePaletteEntry(const pixel_type pixel)<br />

{<br />

}<br />

if(palette_count>=<br />

>=palette_max)<br />

{<br />

std::ostringstream os;<br />

os


19/10/2003 27<br />

Modification d’un pixel (2/2)<br />

void SetPixel(const unsigned int x,const unsigned int y,const pixel_type pixel)<br />

{<br />

}<br />

try { Image::<br />

>::SetPixel(x,y,FindPaletteIndex(pixel)); }<br />

catch(std::string s)<br />

{<br />

}<br />

try { Image::<br />

>::SetPixel(x,y,AllocatePaletteEntry(pixel)); }<br />

catch(std::string s2)<br />

{<br />

std::ostringstream os;<br />

os


19/10/2003 28<br />

Des questions ?

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!