pythongdalgeotiffosgeo

Find pixel coordinates from lat/long point in .geotiff using python and gdal


I have (lat,long) coordinate describing the position of a point in a .geotiff image.

I wish to find the equivalent pixel coordinates of the lat,long ones inside the image.

I succeded using gdaltransform from the command line with the following instruction :

gdaltransform -i -t_srs epsg:4326 /path/imagename.tiff
-17.4380493164062 14.6951949085676

But i would like to retrieve such type of equivalence from python code. I tried the following :

from osgeo import osr

source = osr.SpatialReference()
source.ImportFromUrl(path + TIFFFilename)

target = osr.SpatialReference()
target.ImportFromEPSG(4326)

transform = osr.CoordinateTransformation(target,source )

point_xy = np.array(transform.TransformPoint(-17.4380493164062,14.6951949085676))

But it returns this error :

NotImplementedError: Wrong number or type of arguments for overloaded function 'CoordinateTransformation_TransformPoint'.
  Possible C/C++ prototypes are:
    OSRCoordinateTransformationShadow::TransformPoint(double [3])
    OSRCoordinateTransformationShadow::TransformPoint(double [3],double,double,double)

What am i doing wrong ? I tried to work around this error but without any success. Is there an other way to do it ?

EDIT 1 :

I achieved a single transformation via gdaltransform commands in terminal :

gdaltransform -i -t_srs epsg:4326 /path/image.tiff
-17.4380493164062 14.6951949085676

As i need to retrieve the pixel in a pythonic way, i tried calling the command using subprocess like :

# TRY 1:
subprocess.run(['gdaltransform','-i',' -t_srs','epsg:4326','/pat/img.tiff\n'], stdout=subprocess.PIPE)
# TRY 2 :
cmd = '''gdaltransform -i -t_srs epsg:4326 /home/henri/Work/imdex_visio/AllInt/Dakar_X118374-118393_Y120252-120271_PHR1A_2016-03-10T11_45_39.781Z_Z18_3857.tiff
-17.4380493164062 14.6951949085676'''
subprocess.Popen(cmd,stdout=subprocess.PIPE, shell=True)

But it does not work. Maybe because of the way the command itself behaves, like not actually returning a result and ending itself, but displaying the result and staying busy.


Solution

  • According to the cookbook you are flipping the use of transform and point. You should call transform on the point given the transform, not the other way around. It also seems like you are flipping source and target, but you do that two times, so it will work.

    However I believe that target.ImportFromUrl(path + TIFFFilename) will not work. Instead you can extract the spatial reference from the geotiff using gdal.

    Something like the following should work

    from osgeo import osr, ogr, gdal
    
    # Extract target reference from the tiff file
    ds = gdal.Open(path + TIFFFilename)
    target = osr.SpatialReference(wkt=ds.GetProjection())
    
    source = osr.SpatialReference()
    source.ImportFromEPSG(4326)
    
    transform = osr.CoordinateTransformation(source, target)
    
    point = ogr.Geometry(ogr.wkbPoint)
    point.AddPoint(-17.4380493164062, 14.6951949085676)
    point.Transform(transform)
    print(point.GetX(), point.GetY())
    

    This provides you with the coordinates in your geotiffs reference, however this is not pixel coordinates.

    To convert the point to pixels you could use something like the following (the minus for the line might have to be flipped, based on where in the world you are)

    def world_to_pixel(geo_matrix, x, y):
        """
        Uses a gdal geomatrix (gdal.GetGeoTransform()) to calculate
        the pixel location of a geospatial coordinate
        """
        ul_x= geo_matrix[0]
        ul_y = geo_matrix[3]
        x_dist = geo_matrix[1]
        y_dist = geo_matrix[5]
        pixel = int((x - ul_x) / x_dist)
        line = -int((ul_y - y) / y_dist)
        return pixel, line
    

    So your final code would look something like

    from osgeo import osr, ogr, gdal
    
    
    def world_to_pixel(geo_matrix, x, y):
        """
        Uses a gdal geomatrix (gdal.GetGeoTransform()) to calculate
        the pixel location of a geospatial coordinate
        """
        ul_x= geo_matrix[0]
        ul_y = geo_matrix[3]
        x_dist = geo_matrix[1]
        y_dist = geo_matrix[5]
        pixel = int((x - ul_x) / x_dist)
        line = -int((ul_y - y) / y_dist)
        return pixel, line
    
    # Extract target reference from the tiff file
    ds = gdal.Open(path + TIFFFilename)
    target = osr.SpatialReference(wkt=ds.GetProjection())
    
    source = osr.SpatialReference()
    source.ImportFromEPSG(4326)
    
    transform = osr.CoordinateTransformation(source, target)
    
    point = ogr.Geometry(ogr.wkbPoint)
    point.AddPoint(-17.4380493164062, 14.6951949085676)
    point.Transform(transform)
    
    x, y = world_to_pixel(ds.GetGeoTransform(), point.GetX(), point.GetY())
    print(x, y)