9

I have acquired Digital Elevation Maps(Height Map of Earth) of some area. My aim was to create Realistic Terrains.

Terrain Generation is no problem. I have practiced that using VC# & XNA framework.

The problem is that those Height Map Files are in GeoTIFF format which i don't know how to read. Nor do i have previous experience with reading any image files so that i could experiment something using little tips-bits available on internet about reading GeoTIFF files. So far i have been unsuccessful.

  • The geoTIFF files I have are 3601 x 3601 files.
  • Each file has two version, a decimal & num valued files.
  • Each file has data of every second of longitude & latitude of Geo-Coords along with Height Map i.e Lon, Lat, height from sea level

How to read these file :)

The files I have are from ASTER G-DEM Version-2 LINK TO OFFICIAL DESCRIPTION according to them GeoTIFF is pretty standard which is because some GeoTIFF Visualizers I dwonloaded are showing me the correct data.

I am gonna be using C#. I would appreciate if we talk in relation to this language.


E D I T

okay i got the libtiff and this what i have done,

using (Tiff tiff = Tiff.Open(@"Test\N41E071_dem.tif", r))
{
  int width   = tiff.GetField(TiffTag.IMAGEWIDTH)[0].ToInt();
  int height  = tiff.GetField(TiffTag.IMAGELENGTH)[0].ToInt();
  double dpiX = tiff.GetField(TiffTag.XRESOLUTION)[0].ToDouble();
  double dpiY = tiff.GetField(TiffTag.YRESOLUTION)[0].ToDouble(); 

  byte[] scanline        = new byte[tiff.ScanlineSize()]; 
  ushort[] scanline16Bit = new ushort[tiff.ScanlineSize() / 2];

  for (int i = 0; i < height; i++)
  {
    tiff.ReadScanline(scanline, i); //Loading ith Line                        
    MultiplyScanLineAs16BitSamples(scanline, scanline16Bit, 16,i);
  }
}

private static void MultiplyScanLineAs16BitSamples(byte[] scanline, ushort[] temp, ushort factor,int row)
{
  if (scanline.Length % 2 != 0)
  {
    // each two bytes define one sample so there should be even number of bytes
    throw new ArgumentException();
  }
  
  Buffer.BlockCopy(scanline, 0,   temp, 0, scanline.Length);

  for (int i = 0; i < temp.Length; i++)
  {                
    temp[i] *= factor;
    MessageBox.Show("Row:"+row.ToString()+"Column:"+(i/2).ToString()+"Value:"+temp[i].ToString());
  }
}

where i am displaying the message box, i am displaying the corresponding values, Am i doing it Right, i am asking this cuz this is my maiden experience with images & 8\16 bit problem. I think unlike the official tutorials of libtiff i should be using short instead of ushort because the images i am using are "GeoTIFF, signed 16 bits"

Michaël Polla
  • 3,511
  • 3
  • 23
  • 37
Moon
  • 19,518
  • 56
  • 138
  • 200
  • Just curious... the first result googling a bit: [Reading GeoTiff using .NET](http://gis.stackexchange.com/questions/6462/reading-geotiff-using-net) Have you tried? Are you looking other libraries? – Juan Mellado Mar 09 '12 at 11:02
  • i don't know how that one skipped, i did use libtif this time, please read my question again – Moon Mar 11 '12 at 10:40
  • @JuanMellado, now this post is the first result in google using search key term "geotiff reading in C#" – Graviton Dec 05 '18 at 02:05
  • lols............ – Moon Dec 08 '18 at 14:48

3 Answers3

12

There are some SDKs out there usable from C# to read GeoTIFF files:

UPDATE:

The spec for GeoTIFF can be found here - to me it seems that GeoTIFFs can contain different "subtypes" of information which in turn need to be interpreted appropriately...

Andy
  • 3,631
  • 2
  • 23
  • 32
Yahia
  • 69,653
  • 9
  • 115
  • 144
  • thankyou for the great references, please read my edited question. – Moon Mar 11 '12 at 10:39
  • i am displaying the imaging correctly now, i need to be sure that i am getting the values correctly and not changing them in any kind of implicit\explicit bit conversion. cuz this is sensitive, i will use this method to generate terrain which will be used in critical\sensitive applications. – Moon Mar 11 '12 at 10:42
  • @JunaidSaeed another point: To be really sure that your code works right you need to at least check your results against the results of other readers... – Yahia Mar 11 '12 at 11:09
  • @JunaidSaeed you are welcome :-) regarding "short versus ushort": since libtiff handles the big/littel endian stuff internally the only difference this makes is IF the MSB (most significant bit) is used - in your case: are there any sample with "negative height" (i.e. below 0) ? IF so THEN using `short[]` is necessary IMO – Yahia Mar 11 '12 at 11:14
  • @JunaidSaeed What I am not sure about is the factor of 16 you are using in multiplication... – Yahia Mar 11 '12 at 11:27
  • i think 16 is just for the amplification, and i don't have any negative heights, tough the documentation of providers say that there will be a value "-9999" which will be used very data is not available or void. – Moon Mar 11 '12 at 11:34
  • my point was in my code besides multiplication of 16, i shouldn't be doing any thing explicitly OR implicitly to change the data values, so for that i am good with this approach of reading, for checking with other readers, it's highly unlikely to find another reader, tough i will cross check the corresponding data with other similar Service Apps. – Moon Mar 11 '12 at 11:40
  • and thanks again, you don't have any idea how big of a deal it is for me. – Moon Mar 11 '12 at 11:40
  • @JunaidSaeed you are welcome :-) just curious: what sort of application are you developing ? – Yahia Mar 11 '12 at 11:54
  • currently, i am setting up multiple format DBs of Digital Elevation MAP of the Globe, it will be used not in 1 but enormous number of applications.. Digital Elevation Maps, use your imagination ;) – Moon Mar 11 '12 at 18:21
  • @JunaidSaeed wish you success :-) – Yahia Mar 11 '12 at 18:24
3

If the GeoTIFF contains tiles, you need a different approach. This is how to read a GeoTiff that contains 32bit floats with height data:

  int buffersize = 1000000;
  using (Tiff tiff = Tiff.Open(geotifffile, "r"))
  {
    int nooftiles = tiff.GetField(TiffTag.TILEBYTECOUNTS).Length;
    int width = tiff.GetField(TiffTag.TILEWIDTH)[0].ToInt();
    int height = tiff.GetField(TiffTag.TILELENGTH)[0].ToInt();
    byte[] buffer = new byte[buffersize];

    for (int i = 0; i < nooftiles; i++)
    {
      int size = tiff.ReadEncodedTile(i, buffer, 0, buffersize);
      float[,] data = new float[width, height];
      Buffer.BlockCopy(buffer, 0, data, 0, size); // Convert byte array to x,y array of floats (height data)
      // Do whatever you want with the height data (calculate hillshade images etc.)
    }
  }
nivs1978
  • 1,126
  • 14
  • 20
3

Here's a guy that did it without GDAL: http://build-failed.blogspot.com.au/2014/12/processing-geotiff-files-in-net-without.html

GDAL is available in NuGet, though.

metao
  • 2,784
  • 1
  • 18
  • 15