Accueil
Rechercher:
sur developpez.com sur les forums
Forums | Tutoriels | F.A.Q's | Participez | Hébergement | Contacts
Club Emploi Blogs   TV   Dév. Web PHP XML Python Autres 2D-3D-Jeux Sécurité Windows Linux PC Mac
Accueil Conception Java DotNET Visual Basic  C  C++ Delphi MS-Office SQL & SGBD Oracle  4D  Business Intelligence
FORUMS DELPHI F.A.Q DELPHI TUTORIELS DELPHI LIVRES COMPOSANTS SOURCES DEFI TELECHARGEZ DELPHI TV

Utilisation de LibTiff avec Delphi

Date de publication : 25/05/2005 , Date de mise a jour : 28/05/2005

Par Eric SIBERT (Site)
 

Exemple d'utilisation de LibTiff avec Delphi : réduire en 256 couleurs optimales une grande image Tiff


I. Introduction
II. Détermination de la palette
III. Dans le code
IV. Conclusion


I. Introduction

Le format d'image Tiff est assez répandu et on peut trouver des composants Delphi pour lire voir écrire des images à ce format. Toutefois, dans certains cas, comme la manipulation de grandes images, on peut vouloir accéder directement au contenu de l'image sans la charger entièrement en mémoire comme le fait un composant. Il convient alors d'utiliser des outils de plus bas niveau. Compte tenu du nombre de variantes que comprend le format, il n'est pas envisageable d'aller lire directement le fichier, contrairement au Bitmap par exemple. Il existe par contre une librairie adaptée à ce type de travail : LibTiff. Cette librairie est disponible en opensource ... et en C. Heureusement,  Joris Van Damme a réalisé une  traduction des entêtes de LibTiff pour Delphi.

Dans la suite de cet article, je vais vous montrer comment se servir de cette librairie pour réduire de 16 millions à 256 le nombre de couleurs d'une image à priori grande. En essayant d'obtenir une palette de bonne qualité. Cette opération s'appelle aussi une quantification de palette.


II. Détermination de la palette

Sur le principe de base, il y a un article chez  Microsoft. Grosso modo, dans l'espace 3D des couleurs, on constitue des boîtes. Une boîte est définie par ses limites RougeMin, RougeMax, VertMin, VertMax, BleuMin, BleuMax. Chaque boîte contient une partie des couleurs présentes dans l'image avec leur fréquence d'apparition. Au début, on a une seule boîte englobant l'ensemble des couleurs. On recherche le plus grand côté de la boîte. On découpe la boîte perpendiculairement à cette direction, au niveau de la valeur moyenne des couleurs qu'elle contient. Par exemple, on constate que la boîte contient des rouges de 3 à 249, des bleus de 25 à 230 et des verts de 50 à 240. Le rouge constitue le plus grand côté. On trouve par ailleurs que la valeur moyenne des rouges contenus dans la boîte est de 118,3. On va découper la boîtes en deux boîtes plus petites, l'une avec les rouges de 3 à 118 et l'autre de 119 à 249. Puis on recommence l'opération sur les nouvelles boîtes. On cherche sur l'ensemble des boîtes celle qui est la plus allongée. Et on la découpe suivant le même principe. On répète l'opération jusqu'à avoir autant de boîtes que de couleurs voulues (256 ou 236 ... ou 23). Chaque boîte représente une entrée dans la palette. On prend la valeur moyenne des pixels de la boîte pour définir la couleur de la palette. Il ne reste plus qu'à parcourir l'image et à déterminer pour chaque pixel dans quelle boîte il se trouve. Le numéro de la boîte est alors le numéro dans la palette. Le pixel qui est dans la boîte 53 aura la couleur 53 de la palette.

A chaque fois qu'on veut découper une boîte, il faut déterminer la valeur moyenne de la couleur correspondante. Par exemple, en parcourant l'image et en repérant les pixels dont la couleur est dans la boîte puis en les ajoutant au calcul de la moyenne. A répéter par le nombre de couleur qu'on veut obtenir. Ce qui pour une image importante, voir stockée sur un disque dur, risque d'être très long. Pour contourner ce problème, j'ai fait un tableau avec les 16 millions de couleurs possibles et je ne parcours l'image qu'une fois pour noter la fréquence d'apparition de chaque couleur. J'utilise ensuite ce tableau pour faire les calculs sur les boîtes. L'allocation d'un tableau de 16 millions d'entiers (64 Mo) n'est certainement pas optimale pour une petite image. La méthode ne devient intéressante que quand la taille de l'image dépasse celle du tableau.


III. Dans le code

Après avoir téléchargé la  librairie, on l'appelle dans notre projet :

uses LibTiffDelphi;
Pour la lecture d'une image Tiff :

var Source : PTiff; BitsPerSampleValue: Word; Width, Height : Cardinal; SourceLine, DestLine : array of byte; I, J : integer; begin // first step Source:=TIFFOpen(FileName,'r'); assert(Source<>nil,'Source File Missing'); try // checking file format assert(TIFFGetField(Source,TIFFTAG_BITSPERSAMPLE,@BitsPerSampleValue)=1, 'Corrupted Source File with TIFFTAG_BITSPERSAMPLE'); assert(BitsPerSampleValue=8,'Source File is not a 8bit color depth'); assert(TIFFGetField(Source,TIFFTAG_SAMPLESPERPIXEL,@BitsPerSampleValue)=1, 'Corrupted Source File with TIFFTAG_SAMPLESPERPIXEL'); assert(BitsPerSampleValue=3,'Source File as not 3 samples per value'); // reading sizes assert(TIFFGetField(Source,TIFFTAG_IMAGEWIDTH,@Width)=1,'Corrupted Source file with TIFFTAG_IMAGEWIDTH'); assert(TIFFGetField(Source,TIFFTAG_IMAGELENGTH,@Height)=1,'Corrupted Source file with TIFFTAG_IMAGELENGTH'); setLength(SourceLine,3*Width); // calculating the density FillChar(Density[0,0,0],16777216,0); for J:=0 to Height-1 do begin TIFFReadScanline(Source,@(SourceLine[0]),J,0); for I:=0 to Width-1 do inc(Density[SourceLine[3*I],SourceLine[3*I+1],SourceLine[3*I+2]]); end; [...] finally TIFFClose(Source); end;
Dans l'ordre, nous avons ouverture du fichier, récupération d'informations qui sont stockées dans les tags de l'image. Puis lecture du contenu de l'image de façon similaire au scanline d'un bitmap. On se retrouve presque à lire une image Tiff comme une image Bitmap.

Je vous passe les détails sur la détermination de la palette. Vous irez voir dans le code source.

Pour l'écriture d'une image Tiff :

// creating the tiff file Destination:=TIFFOpen(DestFileName,'w'); assert(Destination<>nil,'Can''t create Destination file'); try assert(TIFFSetField(Destination,TIFFTAG_IMAGEWIDTH,Width)=1,'Problem with TIFFTAG_IMAGEWIDTH'); assert(TIFFSetField(Destination,TIFFTAG_IMAGELENGTH,Height)=1,'Problem with TIFFTAG_IMAGELENGTH'); assert(TIFFSetField(Destination,TIFFTAG_BITSPERSAMPLE,8)=1,'Problem with TIFFTAG_BITSPERSAMPLE'); assert(TIFFSetField(Destination,TIFFTAG_SAMPLESPERPIXEL,1)=1,'Problem with TIFFTAG_SAMPLESPERPIXEL'); assert(TIFFSetField(Destination,TIFFTAG_ROWSPERSTRIP,Height)=1,'Problem with TIFFTAG_ROWSPERSTRIP'); assert(TIFFSetField(Destination,TIFFTAG_COMPRESSION,COMPRESSION_NONE)=1, 'Problem with TIFFTAG_COMPRESSION'); assert(TIFFSetField(Destination,TIFFTAG_PHOTOMETRIC,PHOTOMETRIC_PALETTE)=1, 'Problem with TIFFTAG_PHOTOMETRIC'); assert(TIFFSetField(Destination,TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)=1, 'Problem with TIFFTAG_PLANARCONFIG'); // setting the palette // palette must contain 256 colors (2^BitPerSample) SetLength(Red_Tbl,256); SetLength(Green_Tbl,256); SetLength(Blue_Tbl,256); for I:=0 to PaletteBuilder.NbColor-1 do begin MyColor:=PaletteBuilder.Color[I]; Red_Tbl[I]:=MyColor.X*256; Green_Tbl[I]:=MyColor.Y*256; Blue_Tbl[I]:=MyColor.Z*256; end; assert(TIFFSetField(Destination,TIFFTAG_COLORMAP, @(red_tbl[0]), @(green_tbl[0]), @(blue_tbl[0]))=1,'Problem setting the ColorMap'); PaletteBuilder.TableToPalette(Density); // transferring the picture itself setLength(DestLine,Width); for J:=0 to Height-1 do begin TIFFReadScanline(Source,@(SourceLine[0]),J,0); for I:=0 to Width-1 do DestLine[I]:=Density[SourceLine[3*I],SourceLine[3*I+1],SourceLine[3*I+2]]; TIFFWriteScanline(Destination,@(DestLine[0]),J,0); end; finally TiffClose(Destination); end;
Création de l'objet toujours sans problème. Là, il y a un peu plus de tags à fournir. Il faut enregistrer la palette dans le fichier Tiff. Et finir en enregistrant l'image elle-même toujours avec un scanline.


IV. Conclusion

Le programme utilisé ici comme exemple me permet de réduire en 256 couleurs des vues satellite que j'ai générées avec un  autre logiciel personnel. Le temps de calcul sur une image de 18000x16000 (800Mo) est de 13 minutes quand Photoshop a besoin d'une demi-heure et que Gimp n'arrive même pas à ouvrir l'image. Le résultat, en terme de qualité d'image, est tout à fait acceptable. Pour tenir compte de la sensibilité de l'oeil, il serait sans doute plus judicieux de travailler dans les espaces YCrCb ou TSV (au lieu de RVB) et de compter double les longueurs sur l'axe de la luminosité (Y ou T suivant le modèle).
Sur l'utilisation du Tiff, la traduction pour Delphi de LibTiff permet une gestion aisée des images Tiff. On peut aussi accéder à tous les tags contenus dans les images Tiff. Je suis par exemple en train de travailler à la récupération des tags GeoTiff pour l'étalonnage des vues spatiales et aériennes.

Le code source : source_tiff256.zip (5 ko).


Liste de mes articles :
Types énumérés, intervalle et ensemble
MMX avec Delphi 6 / Kylix
Préchargement de données dans le cache
MMX ( 2 ) avec Delphi 6 / Kylix
Instructions SIMD sur les réels
Internationaliser un projet Delphi
Installer D6 sous Windows 95
Tramage d'une image
Coder le PNG soi-même
Utiliser LibTiff avec Delphi
Ecrire une UDF FireBird avec Kylix


Les sources présentées sur cette page sont libres de droits, et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une oeuvre intellectuelle protégée par les droits d'auteurs. Copyright © 29/05/2005 Eric Sibert. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts. Cette page est déposée à la SACD.

Responsables bénévoles de la rubrique Delphi : Nono40 et Pedro - Contacter par EMail :
Vos questions techniques : forum d'entraide Delphi - Publiez vos articles, tutoriels et cours
et rejoignez-nous dans l'équipe de rédaction du club d'entraide des développeurs francophones
Nous contacter - Copyright © 2000-2008 www.developpez.com - Legal informations.