Danke für die Einladung, aighes.
Also ich mach das eigentlich schon seit Jahren… wundert mich, dass da sonst noch niemand drauf gekommen ist.
- Zunächst zerschneide ich die 6000x6000 Pixel GeoTIFFs in 1x1 Grad Teilstücke. Dafür verwende ich das kleine, angehängte Perl-Skript, was einfach eine Reihe von simplen ImageMagick-Kommandos ausführt und im Zweifelsfall noch eine Zeile oder Spalte Pixel vom nächsten benachbarten 6000x6000 GeoTIFF mit einbringt. Bei dem Skript rede ich mir mittlerweile ein, dass die meisten off-by-1 Bugs behoben sein sollten.
- Wenn ich ein 1x1 Grad Teilstück habe, bastle ich mit libgeotiff (genaugenommen geotiffcp) noch die Geo-Informationen dazu, so dass ich wieder ein GeoTIFF als Ausgabe hab. Das ist in meinem Perl-Skript mit drinnen.
- Dann schicke ich die kleinen GeoTIFFs durch das Programm DEM2Topo. Ist etwas rechenintensiv, geht aber unter Linux genausogut wie unter Windows. Als Ausgabe kommen Vektordaten im .mp Format raus. Gibt’s hier: http://people.uleth.ca/~brad.gom/dem2topo/
- Die .mp Dateien werden zum Abschluss noch durch mkgmap gejagt und fertig ist die topografische Karte. Mit den Parametern “–draw-priority=10000 --transparent” bekommt man die Höhenlinien transparent hin und dann bastle ich meist noch die computerteddy-Tiles dazu um eine vollständige Karte zu bekommen
Und wenn man ganz penibel ist, schreibt man sich noch ein kleines Progrämmchen, was die .mp Dateien durchforstet und die überstehenden Randartefakte von DEM2Topo wegschneidet. Ist etwa ein halber Pixel GeoTIFF an jeder Kante, wo die Höhenlinien der benachbarten tiles sich überlappen. Aber das führt hier wohl etwas zu weit…
#!/usr/bin/perl
# Cut CGIAR SRTM data into smaller tiles of e.g. 1x1 degree
# usage:
# cgiar2tile.pl [out.tif] [top] [left] [bottom] [right]
#
# Just a quick and dirty hack that may very well not work for you. If it does,
# there should be a one pixel boundary left all around the output image, so that
# contour line extractors can work properly as well. The geo-registration
# matches the current SRTM 4.1 release and is correct, if used for whole degree
# tiles.
# e.g.:
# cgiar2tile.pl 5101.tif 52 -2 51 -1
#
# Currently, the CGIAR data is expected to reside in the current working
# directory upon execution of the script. If a tile is missing, you will be
# told about that.
#
# Please note the two variables $verbose and $execute, that allow to turn
# on/off the messages and performing a dry run without actually executing the
# commands.
#
#
# written by Olaf Kaehler
#
# original versions date back to 2006
# latest significant changes 2009-09-22
# first released version 2011-10-11
$im_convert="convert -define quantum:format=signed";
$gt_geotifcp="geotifcp";
$verbose=100;
$execute=1;
$outfilename = "out.tif";
if ( $#ARGV == 4 ) {
$outfilename = shift;
}
$top=shift;
$left=shift;
$bottom=shift;
$right=shift;
sub getTileFilename($;$) {
my $tile_x=shift;
my $tile_y=shift;
my $tile_0x = $tile_x;
my $tile_0y = $tile_y;
$tile_0x=~s/^(.)$/0$1/;
$tile_0y=~s/^(.)$/0$1/;
# version 3/4 files
my $filename = "srtm_".$tile_0x."_".$tile_0y.".tif";
if ( -r $filename ) { return $filename; }
# version 2 files
$filename = "z_".$tile_x."_".$tile_y.".tif";
if ( -r $filename ) { return $filename; }
# version 1 files:
$filename = "s_".$tile_0x."_".$tile_0y.".tif";
if ( -r $filename ) { return $filename; }
printf "tile $tile_x $tile_y does not exist...\n";
return $filename;
}
sub pos2pixel($;$) {
my $lat=shift;
my $lon=shift;
$lat = 60-$lat;
$lon = 180+$lon;
$lat = $lat*1200;
$lon = $lon*1200;
return $lat,$lon;
}
sub pixel2tile($;$) {
my $pix_x = shift;
my $pix_y = shift;
$tile_x = $pix_x/6000;
$tile_x =~ s/\..*//;
$pix_x = $pix_x - $tile_x*6000;
$tile_y = $pix_y/6000;
$tile_y =~ s/\..*//;
$pix_y = $pix_y - $tile_y*6000;
# tiles start at 1,1
$tile_x+=1;
$tile_y+=1;
return ($tile_x,$tile_y,$pix_x,$pix_y);
}
sub createTIF($;$;$;$) {
$top=shift;
$left=shift;
$bottom=shift;
$right=shift;
# get pixels on global SRTM data image
($gpix1_y,$gpix1_x) = pos2pixel($top,$left);
($gpix2_y,$gpix2_x) = pos2pixel($bottom,$right);
# we usually want the pixel *center* coordinates inside the given boundaries
$gpix1_x = $gpix1_x-1;
$gpix1_y = $gpix1_y-1;
$gpix2_x = $gpix2_x+1;
$gpix2_y = $gpix2_y+1;
if ($verbose>=3) {
print "extracting pixels from $gpix1_x,$gpix1_y to $gpix2_x,$gpix2_y\n";
}
# get tiles and local coordinates within the tiles
($tile1_x,$tile1_y,$lpix1_x,$lpix1_y) = pixel2tile($gpix1_x,$gpix1_y);
($tile2_x,$tile2_y,$lpix2_x,$lpix2_y) = pixel2tile($gpix2_x,$gpix1_y);
($tile3_x,$tile3_y,$lpix3_x,$lpix3_y) = pixel2tile($gpix1_x,$gpix2_y);
($tile4_x,$tile4_y,$lpix4_x,$lpix4_y) = pixel2tile($gpix2_x,$gpix2_y);
if ($verbose>=3) {
print " left top is on tile $tile1_x,$tile1_y at $lpix1_x,$lpix1_y\n";
print "(right top is on tile $tile2_x,$tile2_y at $lpix2_x,$lpix2_y)\n";
print "(left bottom is on tile $tile3_x,$tile3_y at $lpix3_x,$lpix3_y)\n";
print " right bottom is on tile $tile4_x,$tile4_y at $lpix4_x,$lpix4_y\n";
}
# crop the necessary patches from all tiles
my %patches;
$x_page=0;
foreach $tile_x ($tile1_x..$tile4_x) {
$x_start=0;
$x_end=5999;
if ($tile_x==$tile1_x) { $x_start=$lpix1_x; }
if ($tile_x==$tile4_x) { $x_end=$lpix4_x; }
$x_size = $x_end - $x_start + 1;
$y_page=0;
foreach $tile_y ($tile1_y..$tile4_y) {
$y_start=0;
$y_end=5999;
if ($tile_y==$tile1_y) { $y_start=$lpix1_y; }
if ($tile_y==$tile4_y) { $y_end=$lpix4_y; }
$y_size = $y_end - $y_start + 1;
$s_img=getTileFilename($tile_x,$tile_y);
if ($verbose>=2) {
print "from $s_img: ($x_start,$y_start) - ($x_end,$y_end)\n";
}
$patchname="tmp_c".scalar(keys %patches).".tif";
$cmdline = $im_convert." ".
$s_img." ".
"-crop ".$x_size."x".$y_size."+".$x_start."+".$y_start." ".
$patchname;
my $retval=0;
if ($verbose>=1) { print " $cmdline\n"; }
if ($execute>=1) { system $cmdline; $retval=$?; }
print "success: $retval\n";
if ($retval == 0) { $patches{$patchname} = $x_size."x".$y_size."+".$x_page."+".$y_page; }
$y_page += $y_size;
}
$x_page += $x_size;
}
# create mosaic of all the small patches
$cmdline = "$im_convert -page ".$x_page."x".$y_page."+0+0";
foreach $i (keys %patches) {
$cmdline = $cmdline." -page ".$patches{$i}." $i";
}
$cmdline = $cmdline." -mosaic tmp_c.tif";
if ($verbose>=1) { print " $cmdline\n"; }
if ($execute>=1) { system $cmdline; }
}
sub createGEO($;$) {
$top=shift;
$left=shift;
if ($execute>=1) { open($FILE, ">tmp_c.geo"); }
else { $FILE=stdout; }
print $FILE
"Geotiff_Information:\n".
" Version: 1\n".
" Key_Revision: 1.0\n".
" Tagged_Information:\n".
" ModelTiepointTag (2,3):\n".
" 0 0 0 \n".
#" ".($left-0.0004166)." ".($top+0.0004166)." 0 \n".
#" ".$left." ".$top." 0 \n".
" ".($left-0.000833333333)." ".($top+0.000833333333)." 0 \n".
" ModelPixelScaleTag (1,3):\n".
" 0.000833333333 0.000833333333 0 \n".
" End_Of_Tags.\n".
" Keyed_Information:\n".
" GTModelTypeGeoKey (Short,1): ModelTypeGeographic\n".
" GTRasterTypeGeoKey (Short,1): RasterPixelIsArea\n".
' GTCitationGeoKey (Ascii,218): "IMAGINE GeoTIFF Support\nCopyright 1991 - 2001 by ERDAS, Inc. All Rights Reserved\n@(#)$RCSfile: egtf.c $ $Revision: 1.9.2.9 $ $Date: 2002/10/28 15:14:13EST $\nProjection Name = GCS_WGS_1984\nUnits = dd\nGeoTIFF Units = dd"'."\n".
" GeographicTypeGeoKey (Short,1): GCS_WGS_84\n".
" GeogAngularUnitsGeoKey (Short,1): Angular_Degree\n".
" End_Of_Keys.\n".
" End_Of_Geotiff.\n";
$cmdline = $gt_geotifcp." -g tmp_c.geo -c none tmp_c.tif $outfilename";
if ($verbose>=1) { print " $cmdline\n"; }
if ($execute>=1) { system $cmdline; }
}
if ($verbose>=2) {
print "extracting area from $top,$left to $bottom,$right\n";
}
createTIF($top,$left,$bottom,$right);
createGEO($top,$left);