banniere

Le portail francophone de la géomatique


Toujours pas inscrit ? Mot de passe oublié ?
Nom d'utilisateur    Mot de passe              Toujours pas inscrit ?   Mot de passe oublié ?

Annonce

Rencontres QGIS 2025

L'appel à participation est ouvert jusqu'au 19 janvier 2025!

#1 Tue 06 July 2010 17:15

lukhan
Participant occasionnel
Date d'inscription: 5 Jul 2010
Messages: 11

API C GDAL : fonction GDALRasterIO et seuillage

Bonjour à tous,

J'essaye de réaliser un seuillage d'une image, plus exactement de créer un masque binaire sur une image : "1" si il y a une info, 0 sinon.

J'utilise la fonction GDALRasterIO() de la bibliothèque GDAL, et je traite ligne par ligne l'image grâce à un buffer; mais je n'obtiens pas le résultat escompté. J'ai du mal à savoir pourquoi ça ne fonctionne pas, et j'ai du mal à trouver de la doc ou des exemples sur l'utilisation de cette fonction pour travailler sur les pixels.

Voici un extrait de mon code :

Code:

  float *pafScanline;
  pafScanline = (float*)CPLMalloc(sizeof(float)*XSize);


  for (int i = 0; i<YSize; i++)
  {
    GDALRasterIO(band_mask, GF_Read, 0, i, XSize, 1, pafScanline, XSize, 1, GDALGetRasterDataType(band_mask), 0, 0);

    for(int k=0; k<XSize; k++)
    {      
      if(pafScanline[k] != 0)
        pafScanline[k] = 1;
    }
    // Ecriture
    GDALRasterIO(band_mask, GF_Write, 0, i, XSize, 1, pafScanline, XSize, 1, GDALGetRasterDataType(band_mask), 0, 0);
  }

  GDALClose (hDstDS);

Merci d'avance pour votre aide.

Hors ligne

 

#2 Tue 06 July 2010 17:36

rouault
Participant assidu
Date d'inscription: 26 Apr 2009
Messages: 168

Re: API C GDAL : fonction GDALRasterIO et seuillage

Aucune erreur flagrante ne me saute aux yeux.

Plusieurs points à vérifier (désolé si ça parait stupide. c'est comme les questions des téléopérateurs d'un SAV) :
1) Ton dataset est-il bien ouvert avec GA_Update ?
2) Comme tu utilises le même objet GDALRasterBand en lecture et en écriture, j'en déduis que tu veux modifier ton dataset en live, et non pas en lire un pour en écriture un autre ? Sinon y a un bug...
3) Le type natif de band_mask est-il bien GDT_Float32 ? Sinon il y a un bug. De toute façon pour plus de sécurité, il est préférable que tu remplaces GDALGetRasterDataType(band_mask) par GDT_Float32. C'est toi qui impose le type du buffer lu/écrit en cohérence avec sa déclaration. Ca n'a a priori rien à voir avec le type natif retourné par le driver du dataset.

Hors ligne

 

#3 Tue 06 July 2010 17:54

lukhan
Participant occasionnel
Date d'inscription: 5 Jul 2010
Messages: 11

Re: API C GDAL : fonction GDALRasterIO et seuillage

Merci de ton aide.

Je réponds point par point :

1) Ton dataset est-il bien ouvert avec GA_Update ?


Oui.

2) Comme tu utilises le même objet GDALRasterBand en lecture et en écriture, j'en déduis que tu veux modifier ton dataset en live, et non pas en lire un pour en écriture un autre ? Sinon y a un bug...


Oui, c'est le même. J'ai d'abord réalisé une copie du fichier d'origine grâce à GDALCreateCopy() et je travaille en live dans cette copie. Est-ce la méthode la plus optimisée ? Je ne pense pas, surtout que je souhaite travailler sur une seule bande d'une image multispectrale. Mais je n'ai pas trouvé d'autre méthode (je débute avec GDAL).

3) Le type natif de band_mask est-il bien GDT_Float32 ?


J'utilisais GDALGetRasterDataType(band_mask) en pensant à utiliser le type d'origine retourné par le driver...
Mais effectivement, maintenant ça fonctionne en remplacant par GDT_Float32. Merci beaucoup, je n'aurait pas trouvé tout seul.

L'idéal serait d'obtenir une image thématique codée sur 1 bit, mais je ne pense pas que ça soit possible d'après ce que j'ai compris dans la doc.

Hors ligne

 

#4 Tue 06 July 2010 18:07

Jeirhome
Membre
Lieu: Liverion
Date d'inscription: 22 Aug 2006
Messages: 4298
Site web

Re: API C GDAL : fonction GDALRasterIO et seuillage

L'idéal serait d'obtenir une image thématique codée sur 1 bit, mais je ne pense pas que ça soit possible d'après ce que j'ai compris dans la doc.


Tout dépend du driver utilisé.

Il me semble que le tiff supporte ce genre d'image (d'ailleurs, c'est le sujet de la section 3 de la TIFF 6.0 Specification : "Bilevel Images").

Mais peut-être que gdal ne supporte pas ce genre d'opération et qu'il faille utiliser une autre bibliothèque de manipulation d'image (gdal étant spécifique aux données géographiques).


Jérôme Cuinet
L'avantage de la Chine, c'est que le soleil se couche plus tard !

Hors ligne

 

#5 Tue 06 July 2010 18:13

lukhan
Participant occasionnel
Date d'inscription: 5 Jul 2010
Messages: 11

Re: API C GDAL : fonction GDALRasterIO et seuillage

Je travaille plutôt avec des fichiers ERDAS Imagine (*.img).

Comme la création de ce masque est une des étapes d'un traitement, je souhaiterais privilégier l'optimisation en créant une image codée sur 1 bit, et ainsi autant que faire se peut limiter les accès au disque-dur.

Hors ligne

 

#6 Tue 06 July 2010 18:20

rouault
Participant assidu
Date d'inscription: 26 Apr 2009
Messages: 168

Re: API C GDAL : fonction GDALRasterIO et seuillage

OK, je pense qu'il faudrait que tu utilises 2 dataset :
* un ouvert en lecture uniquement (de type GDT_Float32)
* l'autre pour créer ton masque que tu crées à partir de rien avec GDALCreate(driver, filename, xsize, ysize, nbands, datatype, options ) et que tu écris. Le mieux est de prendre datatype = GDT_Byte. Si tu utilises GTiff comme driver, tu peux passer l'option NBITS=1 pour forcer la création d'une image sur 1 bit (par contre le buffer de manipulation vis à vis de GDAL reste du GByte. Le passage de 8bit->1bit est fait en interne dans le driver GTiff), avec éventuellement un type de compression. Par ex :

Quelque chose dans le goût de :

Code:

#include "cpl_string.h"

char** papszOptions = NULL;
papszOptions = CSLAddString(papszOptions, "NBITS=1");
papszOptions = CSLAddString(papszOptions, "COMPRESS=PACKBITS");
GDALDriverH hDriver = GDALGetDriverByName("GTiff");
GDALDatasetH hDstDS = GDALCreate(hDriver, "out.tif", XSize, YSize, 1, GDT_Byte, papszOptions);
GDALRasterBandH hDstBand = GDALGetRasterBand(hDstDS, 1);
CSLDestroy(papszOptions);

float *pafScanline;
pafScanline = (float*)CPLMalloc(sizeof(float)*XSize);
GByte* pabyScanline;
pabyScanline = (GByte*)CPLMalloc(sizeof(GByte)*XSize);

  for (int i = 0; i<YSize; i++)
  {
    GDALRasterIO(hSrcBand, GF_Read, 0, i, XSize, 1, pafScanline, XSize, 1, GDT_Float32, 0, 0);

    for(int k=0; k<XSize; k++)
    {      
      pabyScanline[k] =(pafScanline[k] != 0);
    }
    // Ecriture
    GDALRasterIO(hDstBand, GF_Write, 0, i, XSize, 1, pabyScanline, XSize, 1, GDT_Byte, 0, 0);
  }

  GDALClose (hDstDS);

La doc des options du format GeoTIFF : http://gdal.org/frmt_gtiff.html

Attention tous les visualisateurs de TIFF ne gèrent pas forcément toutes les différentes options disponibles dans le driver GDAL...

Edit : Ah je viens de voir que tu es intéressé par le format Imagine, mais bon c'est quasiment la même chose. Tu peux utiliser NBITS=1 mais et COMPRESSED=YES par exemple, cf http://gdal.org/frmt_hfa.html

Dernière modification par rouault (Tue 06 July 2010 18:22)

Hors ligne

 

#7 Tue 06 July 2010 18:23

lukhan
Participant occasionnel
Date d'inscription: 5 Jul 2010
Messages: 11

Re: API C GDAL : fonction GDALRasterIO et seuillage

Ok, je regarde de ce côté là et je vous tiens au courant...

Hors ligne

 

#8 Wed 07 July 2010 09:50

lukhan
Participant occasionnel
Date d'inscription: 5 Jul 2010
Messages: 11

Re: API C GDAL : fonction GDALRasterIO et seuillage

Tout fonctionne comme prévu.

Merci beaucoup !

Hors ligne

 

Pied de page des forums

Powered by FluxBB