Créer une image avec des positions de latitude / longitude spécifiques à l'aide de GDAL?

9

J'ai un fichier ASCII avec latitude, longitude et data_val dans le format suivant.

35-13.643782N, 080-57.190157W, 118.6
...

J'ai un fichier image GeoTiff et je peux facilement le visualiser.

Je veux placer une "épingle" (peut être un point / drapeau / étoile ou ce qui est le plus simple) sur l'image à la position de latitude / longitude spécifique trouvée dans le fichier ASCII.

Voici ce que j'ai réussi à faire jusqu'à présent:

Mon image source ressemble à ceci:

Driver: GTiff/GeoTIFF
Files: /tmp/Charlotte SEC 100.tif
Size is 16867, 12358
Coordinate System is:
PROJCS["Lambert Conformal Conic",
    GEOGCS["NAD83",
        DATUM["North_American_Datum_1983",
            SPHEROID["GRS 1980",6378137,298.2572221010042,
                AUTHORITY["EPSG","7019"]],
            AUTHORITY["EPSG","6269"]],
        PRIMEM["Greenwich",0],
        UNIT["degree",0.0174532925199433],
        AUTHORITY["EPSG","4269"]],
    PROJECTION["Lambert_Conformal_Conic_2SP"],
    PARAMETER["standard_parallel_1",38.66666666666666],
    PARAMETER["standard_parallel_2",33.33333333333334],
    PARAMETER["latitude_of_origin",34.11666666666667],
    PARAMETER["central_meridian",-78.75],
    PARAMETER["false_easting",0],
    PARAMETER["false_northing",0],
    UNIT["metre",1,
        AUTHORITY["EPSG","9001"]]]
Origin = (-365041.822331817995291,240536.419747152860509)
Pixel Size = (42.334586069440391,-42.334898968590878)
Metadata:
  AREA_OR_POINT=Area
  TIFFTAG_DATETIME=2016:06:24 12:46:45
  TIFFTAG_RESOLUTIONUNIT=2 (pixels/inch)
  TIFFTAG_SOFTWARE=Adobe Photoshop CS5 Windows
  TIFFTAG_XRESOLUTION=300
  TIFFTAG_YRESOLUTION=300
Image Structure Metadata:
  COMPRESSION=LZW
  INTERLEAVE=BAND
Corner Coordinates:
Upper Left  ( -365041.822,  240536.420) ( 82d48'55.43"W, 36d13' 4.92"N)
Lower Left  ( -365041.822, -282638.262) ( 82d35'10.11"W, 31d30'17.00"N)
Upper Right (  349015.641,  240536.420) ( 74d51'46.40"W, 36d13'26.16"N)
Lower Right (  349015.641, -282638.262) ( 75d 4'55.60"W, 31d30'36.99"N)
Center      (   -8013.091,  -21050.921) ( 78d50'12.11"W, 33d55'36.35"N)
Band 1 Block=16867x1 Type=Byte, ColorInterp=Palette
  Color Table (RGB with 256 entries)
    0: 255,255,255,255
...

Voici ce que j'ai réussi à bricoler ensemble en Python:

from osgeo import gdal, osr

src_filename = '/tmp/Charlotte SEC 100.tif'
dst_filename = '/tmp/foo.tiff'

# Opens source dataset
src_ds = gdal.Open(src_filename)
format = "GTiff"
driver = gdal.GetDriverByName(format)

# Open destination dataset
dst_ds = driver.CreateCopy(dst_filename, src_ds, 0)

# Specify raster location through geotransform array
# (upperleftx, scalex, skewx, upperlefty, skewy, scaley)
# Scale = size of one pixel in units of raster projection
# this example below assumes 100x100
gt = [-365041.822, 100, 0, 240536.420, 0, -100]

# Set location
dst_ds.SetGeoTransform(gt)

# Get raster projection
epsg = 4269            # http://spatialreference.org/ref/sr-org/lambert_conformal_conic_2sp/
srs = osr.SpatialReference()
srs.ImportFromEPSG(epsg)
dest_wkt = srs.ExportToWkt()

# Set projection
dst_ds.SetProjection(dest_wkt)

# Close files
dst_ds = None
src_ds = None

Mais, je n'arrive pas à comprendre comment placer un "point rouge" à 35-13.643782N, 080-57.190157W

Je dois apprendre de nouveaux détails ici (nomenclature sur les SIG).

Brad Walker
la source
Le sujet que vous devrez peut-être étudier est le géoréférencement.
PolyGeo
Merci .. J'ai fait une recherche Google en utilisant le terme de géoréférencement. C'était utile. La moitié de la bataille consiste à savoir quels termes techniques utiliser.
Brad Walker
Je suis sûr que je manque quelque chose, mais avez-vous envisagé de convertir les données en KML ou quelque chose?
barrycarter
1
Vous devrez peut-être convertir vos coordonnées DD-MM.mmmmH en degrés décimaux. Vous devrez analyser les informations de l'hémisphère W ou S signifie une valeur négative (faites-le comme dernière étape). Les minutes doivent être divisées par 60 et ajoutées ou concaténées avec la partie degrés.
mkennedy

Réponses:

7

Votre gdalinfosortie montre que vous avez une seule bande GeoTIFF avec une table de couleurs (palette AKA). Je ne peux pas voir les valeurs dans cette table de couleurs, donc les commandes ci-dessous convertissent la seule bande + table de couleurs en GeoTIFF RVB à trois bandes. Les commandes supposent également que votre fichier ASCII a une ligne d'en-tête et des coordonnées en degrés décimaux, vous devrez peut-être modifier votre fichier si ce n'est pas le cas.

Contributions:

$ cat testlonlat.csv
LON,LAT
143.798425,-15.551485
143.827437,-15.535119
143.84561,-15.530017
143.859107,-15.54819
143.812347,-15.523641
143.853581,-15.534694
143.883337,-15.537669
143.885356,-15.561687
143.887694,-15.588468

$ gdalinfo testutm.tif
Driver: GTiff/GeoTIFF
Files: testutm.tif
Size is 1102, 959
Coordinate System is:
PROJCS["WGS 84 / UTM zone 54S",
    GEOGCS["WGS 84",
        DATUM["WGS_1984",
            SPHEROID["WGS 84",6378137,298.257223563,
                AUTHORITY["EPSG","7030"]],
            AUTHORITY["EPSG","6326"]],
        PRIMEM["Greenwich",0,
            AUTHORITY["EPSG","8901"]],
        UNIT["degree",0.0174532925199433,
            AUTHORITY["EPSG","9122"]],
        AUTHORITY["EPSG","4326"]],
    PROJECTION["Transverse_Mercator"],
    PARAMETER["latitude_of_origin",0],
    PARAMETER["central_meridian",141],
    PARAMETER["scale_factor",0.9996],
    PARAMETER["false_easting",500000],
    PARAMETER["false_northing",10000000],
    UNIT["metre",1,
        AUTHORITY["EPSG","9001"]],
    AXIS["Easting",EAST],
    AXIS["Northing",NORTH],
    AUTHORITY["EPSG","32754"]]
Origin = (798741.168775000027381,8282084.855279999785125)
Pixel Size = (10.000000000000000,-10.000000000000000)
Metadata:
  AREA_OR_POINT=Area
Image Structure Metadata:
  INTERLEAVE=BAND
Corner Coordinates:
Upper Left  (  798741.169, 8282084.855) (143d47' 4.96"E, 15d31'16.22"S)
Lower Left  (  798741.169, 8272494.855) (143d47' 9.15"E, 15d36'27.98"S)
Upper Right (  809761.169, 8282084.855) (143d53'14.43"E, 15d31'11.47"S)
Lower Right (  809761.169, 8272494.855) (143d53'18.78"E, 15d36'23.20"S)
Center      (  804251.169, 8277289.855) (143d50'11.83"E, 15d33'49.74"S)
Band 1 Block=1102x7 Type=Byte, ColorInterp=Palette
  Color Table (RGB with 256 entries)
    0: 120,112,136,255
    1: 96,104,88,255
    ...
    254: 76,124,140,255
    255: 232,228,236,255

Processus:

$ gdal_translate -expand rgb testutm.tif testutm_rgb.tif

$ ogr2ogr -f "GeoJSON" -dialect sqlite                      \
  -sql "select ST_buffer(Geometry,0.001) from testlonlat"   \
  -s_srs EPSG:4326 -t_srs EPSG:32754                        \
  /vsistdout/ CSV:testlonlat.csv -oo X_POSSIBLE_NAMES=Lon   \
  -oo Y_POSSIBLE_NAMES=Lat |  gdal_rasterize -b 1 -b 2 -b 3 \
  -burn 255 -burn 0 -burn 0 /vsistdin/ testutm_rgb.tif

La dernière commande effectue les opérations suivantes:

  • met en mémoire tampon le point Lon / Lat dans un polygone plus grand pour qu'il apparaisse mieux (vous pouvez ignorer cela si vous voulez juste un seul pixel coloré en rouge)
  • convertit de WGS84 Lat / Lon (EPSG: 4326) vers le même système de coordonnées que le raster (EPSG: 32754 qui est WGS 84 UTM Zone 54S, votre CRS sera différent)
  • écrit le polygone de sortie sous GeoJSON dans STDOUT et le redirige vers gdal_rasterize
  • brûle RVB 255,0,0 dans les bandes raster RVB 1, 2 et 3

Résultat:

entrez la description de l'image ici

user2856
la source
3

Vous avez un bon départ. gdal.CreateCopyprendra en charge le géoréférencement, vous n'avez donc pas à le définir une deuxième fois en utilisant la géotransformation et la projection.

Le processus complet transformera les coordonnées lon / lat en coordonnées XY de la référence spatiale raster. Ensuite, ces coordonnées XY seront transformées en indices de ligne, col du raster en utilisant la géotransformation inverse. Une valeur de pixel sera écrite à cette position.

from osgeo import gdal, osr
import numpy as np

src_filename = '/tmp/Charlotte SEC 100.tif'
dst_filename = '/tmp/foo.tiff'

# Opens source dataset
src_ds = gdal.Open(src_filename)
format = "GTiff"
driver = gdal.GetDriverByName(format)

# Open destination dataset
dst_ds = driver.CreateCopy(dst_filename, src_ds, 0)

# Get raster projection
epsg = 4269         # http://spatialreference.org/ref/sr-org/lambert_conformal_conic_2sp/
srs = osr.SpatialReference()
srs.ImportFromEPSG(epsg)

# Make WGS84 lon lat coordinate system
world_sr = osr.SpatialReference()
world_sr.SetWellKnownGeogCS('WGS84')

# Transform lon lats into XY
lonlat = [[0.,30.], [20., 30.], [25., 30.]]
coord_transform = osr.CoordinateTransformation(world_sr, srs)
newpoints = coord_transform.TransformPoints(lonlat) # list of XYZ tuples

# Make Inverse Geotransform  (try:except due to gdal version differences)
try:
    success, inverse_gt = gdal.InvGeoTransform(gt)
except:
    inverse_gt = gdal.InvGeoTransform(gt)

# [Note 1] Set pixel values
marker_array_r = np.array([[255]], dtype=np.uint8)
marker_array_g = np.array([[0]], dtype=np.uint8)
marker_array_b = np.array([[0]], dtype=np.uint8)
for x,y,z in newpoints:
    pix_x = int(inverse_gt[0] + inverse_gt[1] * x + inverse_gt[2] * y)
    pix_y = int(inverse_gt[3] + inverse_gt[4] * x + inverse_gt[5] * y)
    dst_ds.GetRasterBand(1).WriteArray(marker_array_r, pix_x, pix_y)
    dst_ds.GetRasterBand(2).WriteArray(marker_array_g, pix_x, pix_y)
    dst_ds.GetRasterBand(3).WriteArray(marker_array_b, pix_x, pix_y)

# Close files
dst_ds = None
src_ds = None

Note 1:

La commande gdal.RasterBand.WriteArray(array, xoff, yoff)fonctionne à partir du coin supérieur gauche. Dans cet exemple, je fournis un tableau 1x1 avec la valeur 255, donc xoffet yoffsont la ligne réelle, les indices col pour la position lon / lat. Si vous voulez écrire un carré 3x3, vous devez ajuster xoffet yoffen soustrayant 1. Vous devez également vous assurer que le type de données du tableau correspond à celui du raster. Parce que vous avez dit que vous vouliez un "point rouge", je suppose qu'il y a trois bandes de uint8.

Logan Byers
la source