Hello !

Ce weekend je me suis posé des questions pour avoir le meilleurs rendu
possible des données SRTM.
Je trouve que l'image disponible sur la page
http://wiki.openstreetmap.org/wiki/HikingBikingMaps donne un bon rendu
de ces donnée mais n'est viable que pour de petites échelles !
Les que l'on s'éloigne trop les courbe de niveau ne donne pas quelque
chose de satisfaisant !
Il faux donc ce rapprocher de rendu comme celui-ci :
http://www.openstreetmap.org/?lat=43.469&lon=5.096&zoom=9&layers=00B0FTF
Qui es déjà très bien mais est loin d'être parfais surtout en altitudes :
- Les Alpes : 
http://www.openstreetmap.org/?lat=45.846&lon=7.203&zoom=9&layers=00B0FTF
- L'Himalaya (on ne voie plus qu'un énorme plafond blanc) :
http://www.openstreetmap.org/?lat=-71.5&lon=31.8&zoom=3&layers=00B0FTF

A cela je voie 2 problèmes :
- La dernière couleurs est affectée a une altitude de 3500 ce qui es
trop bas pour des très hautes altitude.
- Je pesse que mettre une couleur blanche en altitude ne sois pas une
bonne idée, cela fais panser à la neige mais ça à l'inconvénient de ne
pas s'adapter a toutes les chaîne de montagnes.  Je pensse que c'est
mieus d'utiliser une coulleur rouge comme sur l'image su site de
MapNik (http://www.mapnik.org/).

J'ai fais quelque essais pour arriver à en résultat qui me satisfais
sans toutefois être parfais :
http://img158.imageshack.us/my.php?image=testyf7.png

Pour cela j'ai utiliser une fichier scale.txt comme celui-ci :
8000   246 153 96
2000   247 199 152
600   242 243 159
200    134 201 116
-500   255 255 255
-10000 17 110 176
-32767 0 0 0

et j'ai en quelque sorte mergé les 2 programme hillshade et
color-relief pour avoir une image avec des couleurs pour le relief et
des ombres (voire attachement en espérant que cela passe !).
que j'ai exécuter avec la commande :
color-shade "${X%%.hgt.zip}"-warped.tif scale.txt
"${X%%.hgt.zip}"-color-shade.tif -z 2 -s 1.8 -a 0.2

Je n'ai pas réussi à résoudre correctement le problème des données
manquantes  (j'ai fais en hack pour diminuer le problème) et pourtant
il est corrigé sur OpenCycleMap. Es-ce que quelqu'un sais comment ?


Que-ce que vois en penser ?
Es-ce que vous avez des remarques ?
Que faire pour aller plus loin ?


CU
Stéphane


2009/1/9 sylvain letuffe <sylv...@letuffe.org>:
>
>> Oui mais justement sans gestion de canal alpha, on risque d'avoir des
>> très moches effets de crènelages, nop ?
>
> Y'a pas que les problèmes de crénelage si IE le supporte mal, avec mes essais,
> si on ne place pas de canal alpha (param fill-opacity) sur les forêts, les
> prairies (et même certaines icones sans canal alpha qui sont répétées en
> motif), bref, toutes les surfaces, ça se pose par dessus les courbes de
> niveau et c'est sacrément moche.
>
> j'espère avoir un peu de temps pour rapidement faire l'essai et ré-écrouler ma
> bécanne ;-)
>
> Je vais pouvoir mettre 1Go de cache à la poubelle qui avait été
> douloureusement accouchés au fûr et à mesure des navigations
>
> --
> sly
>
> _______________________________________________
> Talk-fr mailing list
> Talk-fr@openstreetmap.org
> http://lists.openstreetmap.org/listinfo/talk-fr
>



-- 
Stéphane Brunner
mail : stephane.brun...@gmail.com
messageries instantanées : stephane.brun...@gmail.com (http://talk.google.com)
--------------------------------------
http://www.ubuntu-fr.org - Distribution Linux
http://fr.wikipedia.org - Encyclopédie communautaire
http://mozilla-europe.org - Navigateur internet / Client de messagerie
http://framasoft.net - Annuaire de logiciel libre (gratuit)
http://jeuxlibres.net - Jeux Libres (gratuit)
http://openstreetmap.org - Cartographie libre (en développement)
--------------------------------------
Il existe 10 sortes de personnes : celles qui connaissent le binaire,
et les autres.
--------------------------------------
Si un jour on te reproche que ton travail n'est pas un travail de
professionnel, dis toi que :
Des amateurs ont construit l'arche de Noé, et des professionnels le Titanic.
/****************************************************************************
 * color-hillshade.cpp
 * Author: Stéphane Brunner, Matthew Perry, Paul Surgeon
 * License : 
 Copyright 2005 Matthew T. Perry, 2005 Paul Surgeon, 2008 Stéphane Brunner
 Licensed under the Apache License, Version 2.0 (the "License"); 
 you may not use this file except in compliance with the License. 
 You may obtain a copy of the License at 
 
 http://www.apache.org/licenses/LICENSE-2.0 
 
 Unless required by applicable law or agreed to in writing, software 
 distributed under the License is distributed on an "AS IS" BASIS, 
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 See the License for the specific language governing permissions and 
 limitations under the License.

 * calculates a shaded relief image from a gdal-supported raster DEM
 
 CHANGELOG
 * updated nodata handling so that 0 is nodata and 1 - 255 are the shade values
 ****************************************************************************/

#include <iostream>
#include <stdlib.h>
#include <math.h>
#include <fstream>
#include <list>
#include "gdal_priv.h"
#include "stringtok.h"

using namespace std;

struct SColor
{
  int Red;
  int Green;
  int Blue;
};

struct SColorPoint
{
  int Elevation;
  SColor Color;
};

vector<SColorPoint*> ColorPointList;

//=============================================================================
void ReadColorScale(const string& ScaleFileName)
{
  ifstream ScaleFile;
  string Buffer;
  list<string> StringList;
  SColorPoint* TempColorPoint;

  ScaleFile.open(ScaleFileName.c_str(), ios::in);

  if (!ScaleFile.is_open())
  {
    cout << "Error opening color scale file : " << ScaleFileName << endl;
    exit (1);
  }

  while (!ScaleFile.eof())
  {
    StringList.clear();
    getline(ScaleFile, Buffer);

    // Strip spaces in case we have a blank line
    while (Buffer[0] == ' ')
    {
      Buffer.erase(0);
    }

    // If not a blank line
    if (Buffer != "")
    {
      TempColorPoint = new SColorPoint;
      stringtok(StringList, Buffer, " ");
      list<string>::iterator i = StringList.begin();
      TempColorPoint->Elevation = atoi(string(*i).c_str());
      i++;
      TempColorPoint->Color.Red = atoi(string(*i).c_str());
      i++;
      TempColorPoint->Color.Green = atoi(string(*i).c_str());
      i++;
      TempColorPoint->Color.Blue = atoi(string(*i).c_str());

      ColorPointList.push_back(TempColorPoint);
    }
  }

  ScaleFile.close();
}

//=============================================================================
// Given an elevation calculate a color based on the color points table
// At the moment we're only doing linear color gradients
//=============================================================================
SColor GetColor(float Elevation)
{
  SColor Color = {0,0,0};
  SColorPoint* LowerColorPoint = NULL;
  SColorPoint* UpperColorPoint = NULL;
  SColorPoint* TempColorPoint;
  float TempElev;
  float DiffFactor;

  // Find closest pair of color points that the elevation falls between
  // Lower color point
  TempElev = -64000;
  for (unsigned int i = 0; i < ColorPointList.size(); i++)
  {
    TempColorPoint = ColorPointList[i];
    if ((TempColorPoint->Elevation <= Elevation) && (TempElev < TempColorPoint->Elevation))
    {
      TempElev = TempColorPoint->Elevation;
      LowerColorPoint = TempColorPoint;
    }
  }
  // Upper color point
  TempElev = 64000;
  for (unsigned int i = 0; i < ColorPointList.size(); i++)
  {
    TempColorPoint = ColorPointList[i];
    if ((TempColorPoint->Elevation >= Elevation) && (TempElev > TempColorPoint->Elevation))
    {
      TempElev = TempColorPoint->Elevation;
      UpperColorPoint = TempColorPoint;
    }
  }

  // I should change the following clipping logic to use the color scale instead
  // Return blue
  if (LowerColorPoint == NULL)
  {
    Color.Red = 150;
    Color.Green = 150;
    Color.Blue = 255;
    return Color;
  }

  // Return white
  if (UpperColorPoint == NULL)
  {
    Color.Red = 255;
    Color.Green = 255;
    Color.Blue = 255;
    return Color;
  }

  // Work out the factor the elevation is between the lower and upper color point elevations
  // If the upper and lower color points point to the same color point object then
  // it means that the elevation falls exactly on a color point
  if (LowerColorPoint != UpperColorPoint)
  {
    DiffFactor = (Elevation - LowerColorPoint->Elevation) / (UpperColorPoint->Elevation - LowerColorPoint->Elevation);
    Color.Red   = (int)((UpperColorPoint->Color.Red - LowerColorPoint->Color.Red) * DiffFactor) + LowerColorPoint->Color.Red;
    Color.Green = (int)((UpperColorPoint->Color.Green - LowerColorPoint->Color.Green) * DiffFactor) + LowerColorPoint->Color.Green;
    Color.Blue  = (int)((UpperColorPoint->Color.Blue - LowerColorPoint->Color.Blue) * DiffFactor) + LowerColorPoint->Color.Blue;
  }
  else
  {
    Color.Red   = LowerColorPoint->Color.Red;
    Color.Green = LowerColorPoint->Color.Green;
    Color.Blue  = LowerColorPoint->Color.Blue;
  }

  return Color;
}

int main(int argc, char* argv[])
{
  GDALDataset* poDataset;
  double       adfGeoTransform[6];
  float*       RowRed;
  float*       RowGreen;
  float*       RowBlue;
  float        InPixel;
  int          i;
  int          j;
  const char*  Format = "GTiff";
  SColor       TempColor;

  if (argc < 3)
  {
    cout << "color-shade generates a color relief map from any GDAL-supported elevation raster and a shaded relief map from any GDAL-supported elevation raster.";
    cout << "The final result is the multiplication of the booth maps." << endl;
    cout << endl << "Usage:" << endl;
    cout << "color-shade <input_dem> <input_color_scale> <output_relief_map>" << endl;
    cout << "[-a addFactor (0..1, default 0)]" << endl;
    cout << "                 [-z ZFactor (default=1)] [-s scale* (default=1)]" << endl;
    cout << "                 [-az Azimuth (default=315)] [-alt Altitude (default=45)]" << endl << endl;

    cout << "Notes about color relief map (input_color_scale):" << endl;
    cout << "The input color scale is a file containing a set of elevation points (in meters)" << endl;
    cout << "and colors. Typically only a small number of elevation and color sets will be needed" << endl;
    cout << "and the rest will be interpolated by color-relief." << endl;
    cout << "Example color scale file with 4000 meters set to white and 0 meters set to green:" << endl;
    cout << "4000 255 255 255" << endl;
    cout << "0 0 255 0" << endl << endl;
    cout << "Using true black (0 0 0) as your RGB values will yield blank/null cells." << endl;
    cout << "Note that to remove nodata from the output, set the DEM's nodata value to rgb of 0 0 0:" << endl;
    cout << "-32767 0 0 0" << endl << endl;
    cout << "See the accompanying \"scale.txt\" file for a decent example." << endl << endl;

    cout << "Notes about shaded relief map:" << endl;
    cout << "   Scale for Feet:Latlong use scale=370400, for Meters:LatLong use scale=111120" << endl << endl;;

    cout << "Notes map meging:" << endl;
    cout << "   The add factor can be use to add some britness." << endl;
    cout << "   the used calcul: result = colorPixel * (addFactor + shadePixel / 256.0)." << endl << endl;

    exit(1);
  }

  const char* InFilename = argv[1];
  const string ScaleFilename = argv[2];
  const char* OutFilename = argv[3];

  // Open and read color scale file
  ReadColorScale(ScaleFilename);

  GDALAllRegister();

  // Open dataset and get raster band
  poDataset = (GDALDataset*) GDALOpen(InFilename, GA_ReadOnly);
  if(poDataset == NULL)
  {
    cout << "Couldn't open dataset " << InFilename << endl;
  }

  GDALRasterBand *poBand;
  poBand = poDataset->GetRasterBand(1);
  poDataset->GetGeoTransform(adfGeoTransform);

  // Get variables from input dataset
  const int nXSize = poBand->GetXSize();
  const int nYSize = poBand->GetYSize();
  RowRed    = (float *) CPLMalloc(sizeof(float)*nXSize);
  RowGreen  = (float *) CPLMalloc(sizeof(float)*nXSize);
  RowBlue   = (float *) CPLMalloc(sizeof(float)*nXSize);

  // Create the output dataset and copy over relevant metadata
  GDALDriver *poDriver;
  poDriver = GetGDALDriverManager()->GetDriverByName(Format);
  GDALDataset      *poDS;
  GDALRasterBand   *poBandRed;
  GDALRasterBand   *poBandGreen;
  GDALRasterBand   *poBandBlue;
  char**           Options = NULL;

  poDS = poDriver->Create(OutFilename,nXSize,nYSize,3,GDT_Byte,Options);
  poDS->SetGeoTransform(adfGeoTransform);
  poDS->SetProjection(poDataset->GetProjectionRef());

  poBandRed = poDS->GetRasterBand(1);
  poBandRed->SetNoDataValue(0);
  poBandGreen = poDS->GetRasterBand(2);
  poBandGreen->SetNoDataValue(0);
  poBandBlue = poDS->GetRasterBand(3);
  poBandBlue->SetNoDataValue(0);


  const float radiansToDegrees = 180.0 / 3.14159;
  const float degreesToRadians = 3.14159 / 180.0;
  float       *win;
  float       *shadeBuf;
  float       x;
  float	      y;
  float       aspect;
  float	      slope;
  float       cang;
  int         n;
  int         containsNull;
  const char *pszFormat = "GTiff";
  float       z = 1.0;
  float       scale = 1.0;
  float       az = 315.0;
  float       alt = 45.0;
  float       add = 0;

  for ( int iArg = 4; iArg < argc; iArg++ )
  {
    if( EQUAL(argv[iArg],"-a") ||
          EQUAL(argv[iArg],"-add"))
      add = atof(argv[iArg+1]);
    if( EQUAL(argv[iArg],"-z") )
      z = atof(argv[iArg+1]);
    if( EQUAL(argv[iArg],"-s") ||
          EQUAL(argv[iArg],"-scale"))
      scale = atof(argv[iArg+1]);
    if( EQUAL(argv[iArg],"-az") ||
          EQUAL(argv[iArg],"-azimuth"))
      az = atof(argv[iArg+1]);
    if( EQUAL(argv[iArg],"-alt") ||
          EQUAL(argv[iArg],"-altitude"))
      alt = atof(argv[iArg+1]);
  }

  GDALAllRegister();

  /* -------------------------------------
   * Get variables from input dataset
   */
  const double   nsres = adfGeoTransform[5];
  const double   ewres = adfGeoTransform[1];
  const float    inputNullValue = (float) poBand->GetNoDataValue( );
  const float    nullValue = 0.0;
  shadeBuf       = (float *) CPLMalloc(sizeof(float)*nXSize);
  win            = (float *) CPLMalloc(sizeof(float)*9);

  /* -----------------------------------------
   * Create the output dataset and copy over relevant metadata
   */
  poDriver = GetGDALDriverManager()->GetDriverByName(pszFormat);
  char **papszOptions = NULL;


  /* ------------------------------------------
   * Move a 3x3 window over each cell 
   * (where the cell in question is #4)
   *
   *                 0 1 2
   *                 3 4 5
   *                 6 7 8
   *
   */
  for ( i = 0; i < nYSize; i++) {
    for ( j = 0; j < nXSize; j++) {
      containsNull = 0;

      // Exclude the edges
//      if (i == 0 || j == 0 || i == nYSize-1 || j == nXSize-1 )
//      {
        // We are at the edge so write nullValue and move on
//        shadeBuf[j] = nullValue;
//        continue;
//      }

      // For the edges
      if (i == 0)
      {
        if (j == 0)
        {
          poBand->RasterIO( GF_Read, j, i, 2, 2,
               win, 2, 2, GDT_Float32,
               0, 0 );
          win[8] = win[3];
          win[7] = win[2];
          win[5] = win[1];
          win[4] = win[0];
          win[0] = 2*win[4] - win[8];
          win[1] = 2*win[4] - win[7];
          win[2] = 2*win[5] - win[8];
          win[3] = 2*win[4] - win[5];
          win[6] = 2*win[7] - win[8];
        }
        else if (j == nXSize-1)
        {
          poBand->RasterIO( GF_Read, j-1, i, 2, 2,
               win, 2, 2, GDT_Float32,
               0, 0 );
          win[5] = win[3];
          win[4] = win[2];
          win[2] = win[1];
          win[1] = win[0];
          win[0] = 2*win[1] - win[2];
          win[3] = 2*win[4] - win[5];
          win[6] = 2*win[4] - win[8];
          win[7] = 2*win[4] - win[1];
          win[8] = 2*win[5] - win[2];
        }
        else
        {
          poBand->RasterIO( GF_Read, j-1, i, 3, 2,
               win, 3, 2, GDT_Float32,
               0, 0 );
          win[8] = win[5];
          win[7] = win[4];
          win[5] = win[3];
          win[4] = win[2];
          win[2] = win[1];
          win[1] = win[0];
          win[0] = 2*win[1] - win[2];
          win[3] = 2*win[4] - win[5];
          win[6] = 2*win[7] - win[8];
        }
      }
      else if (i == nYSize-1)
      {
        if (j == 0)
        {
          poBand->RasterIO( GF_Read, j, i-1, 2, 2,
               win, 2, 2, GDT_Float32,
               0, 0 );
          win[7] = win[3];
          win[6] = win[2];
          win[4] = win[1];
          win[3] = win[0];
          win[0] = 2*win[3] - win[6];
          win[1] = 2*win[4] - win[7];
          win[2] = 2*win[4] - win[6];
          win[5] = 2*win[4] - win[3];
          win[8] = 2*win[7] - win[6];
        }
        else if (j == nXSize-1)
        {
          poBand->RasterIO( GF_Read, j-1, i-1, 2, 2,
               win, 2, 2, GDT_Float32,
               0, 0 );
          win[4] = win[3];
          win[3] = win[2];
          win[1] = win[1];
          win[0] = win[0];
          win[2] = 2*win[1] - win[0];
          win[5] = 2*win[4] - win[3];
          win[6] = 2*win[3] - win[0];
          win[7] = 2*win[4] - win[1];
          win[8] = 2*win[4] - win[0];
        }
        else
        {
          poBand->RasterIO( GF_Read, j-1, i-1, 3, 2,
               win, 3, 2, GDT_Float32,
               0, 0 );
          win[7] = win[5];
          win[6] = win[4];
          win[4] = win[3];
          win[3] = win[2];
          win[1] = win[1];
          win[0] = win[0];
          win[2] = 2*win[1] - win[0];
          win[5] = 2*win[4] - win[3];
          win[8] = 2*win[7] - win[6];
        }
      }
      else
      {
        if (j == 0)
        {
          poBand->RasterIO( GF_Read, j, i-1, 2, 3,
               win, 2, 3, GDT_Float32,
               0, 0 );
          win[8] = win[5];
          win[7] = win[4];
          win[6] = win[3];
          win[5] = win[2];
          win[4] = win[1];
          win[3] = win[0];
          win[0] = 2*win[3] - win[6];
          win[1] = 2*win[4] - win[7];
          win[2] = 2*win[5] - win[8];
        }
        else if (j == nXSize-1)
        {
          poBand->RasterIO( GF_Read, j-1, i-1, 2, 3,
               win, 2, 3, GDT_Float32,
               0, 0 );
          win[5] = win[5];
          win[4] = win[4];
          win[3] = win[3];
          win[2] = win[2];
          win[1] = win[1];
          win[0] = win[0];
          win[6] = 2*win[3] - win[0];
          win[7] = 2*win[4] - win[1];
          win[8] = 2*win[5] - win[2];
        }
        else
        {
          // Read in 3x3 window
          poBand->RasterIO( GF_Read, j-1, i-1, 3, 3,
               win, 3, 3, GDT_Float32,
               0, 0 );
        }
      }


      // Check if window has null value
      for ( n = 0; n <= 8; n++) {
        if(win[n] == inputNullValue) {
          containsNull = 1;
          break;
        }
      }

      if (containsNull == 1) {
        // We have nulls so write nullValue and move on
        shadeBuf[j] = nullValue;
        continue;
      } else {
        // We have a valid 3x3 window.

        /* ---------------------------------------
         * Compute Hillshade
         */

        // First Slope ...
        x = ((z*win[0] + z*win[3] + z*win[3] + z*win[6]) -
                    (z*win[2] + z*win[5] + z*win[5] + z*win[8])) /
                    (8.0 * ewres * scale);

        y = ((z*win[6] + z*win[7] + z*win[7] + z*win[8]) -
                    (z*win[0] + z*win[1] + z*win[1] + z*win[2])) /
                    (8.0 * nsres * scale);

        slope = 90.0 - atan(sqrt(x*x + y*y))*radiansToDegrees;

        // ... then aspect...
        aspect = atan2(x,y);

        // ... then the shade value
        cang = sin(alt*degreesToRadians) * sin(slope*degreesToRadians) +
                       cos(alt*degreesToRadians) * cos(slope*degreesToRadians) *
                       cos((az-90.0)*degreesToRadians - aspect);

        if (cang <= 0.0) 
          cang = 1.0;
        else
          cang = 1.0 + (254.0 * cang);

          shadeBuf[j] = cang;

      }

      poBand->RasterIO(GF_Read, j, i, 1, 1, &InPixel, 1, 1, GDT_Float32, 0, 0);

      // reduce missing data impact
      if (shadeBuf[j] == nullValue && j != 0) {
        RowRed[j]   = RowRed[j-1];
        RowGreen[j] = RowGreen[j-1];
        RowBlue[j]  = RowBlue[j-1];
      } else {
        TempColor = GetColor(InPixel);
        float facteur = add + shadeBuf[j] / 256.0;
        RowRed[j]   = TempColor.Red * facteur;
        RowGreen[j] = TempColor.Green * facteur;
        RowBlue[j]  = TempColor.Blue * facteur;
      }
    }

    // Write lines to output raster
    poBandRed->RasterIO(GF_Write, 0, i, nXSize, 1, RowRed, nXSize, 1, GDT_Float32, 0, 0);
    poBandGreen->RasterIO(GF_Write, 0, i, nXSize, 1, RowGreen, nXSize, 1, GDT_Float32, 0, 0);
    poBandBlue->RasterIO(GF_Write, 0, i, nXSize, 1, RowBlue, nXSize, 1, GDT_Float32, 0, 0);

  }

  delete poDS;

  return 0;

}
_______________________________________________
Talk-fr mailing list
Talk-fr@openstreetmap.org
http://lists.openstreetmap.org/listinfo/talk-fr

Répondre à