# Transforms

Rasterio supports three primary methods for transforming of coordinates from image pixel (row, col) to and from geographic/projected (x, y) coordinates. The interface for performing these coordinate transformations is available in `rasterio.transforms` through one of `AffineTransformer`, `GCPTransformer`, or `RPCTransformer`. The methods `xy` and `rowcol` are responsible for converting between (row, col) -> (x, y) and (x, y) -> (row, col), respectively.

## Using Affine transformation matrix

`rasterio.transform.AffineTransformer` takes care of coordinate transformations given an Affine transformation matrix. For example

```>>> transform = Affine(300.0379266750948, 0.0, 101985.0, 0.0,
-300.041782729805, 2826915.0)
>>> transformer = rasterio.transform.AffineTransformer(transform)
>>> transformer.xy(0, 0)
(102135.01896333754, 2826764.979108635)
>>> transformer.rowcol(102135.01896333754, 2826764.979108635)
(0, 0)
```

This is approximately equivalent to

```>>> transform = Affine(300.0379266750948, 0.0, 101985.0, 0.0,
-300.041782729805, 2826915.0)
>>> transform * (0.5, 0.5)
(102135.01896333754, 2826764.979108635)
>>> ~transform * (102135.01896333754, 2826764.979108635)
(0.5, 0.5)
```

The dataset methods `xy` and `index` use `rasterio.transform` under the hood

```>>> with rasterio.open('RGB.byte.tif') as src:
print(src.xy(0, 0))
(102135.01896333754, 2826764.979108635)
```

## Using Ground Control Points

```>>> gcps = [GroundControlPoint(row=11521.5, col=0.5, x=-123.6185142817931, y=48.99561141948625, z=89.13533782958984, id='217', info=''),
GroundControlPoint(row=11521.5, col=7448.5, x=-122.8802747777599, y=48.91210259315549, z=89.13533782958984, id='234', info=''),
GroundControlPoint(row=0.5, col=0.5, x=-123.4809665720148, y=49.52809729106944, z=89.13533782958984, id='1', info=''),
GroundControlPoint(row=0.5, col=7448.5, x=-122.7345733674704, y=49.44455878004666, z=89.13533782958984, id='18', info='')]
>>> transformer = rasterio.transform.GCPTransformer(gcps)
>>> transformer.xy(0, 0)
(-123.478928146887, 49.52808986989645)
```

## Using Rational Polynomial Coefficients

For accuracy a height value is typically required when using `RPCTransformer`. By default, a value of 0 is assumed.

```>>> with rasterio.open('RGB.byte.rpc.vrt') as src:
transformer = rasterio.trasform.RPCTransformer(src.rpcs)
transformer.xy(0, 0)
(-123.47959047080701, 49.52794990575094)
```

A first order correction would be to use a mean elevation value for the image

```>>> with rasterio.open('RGB.byte.rpc.vrt') as src:
transformer = rasterio.trasform.RPCTransformer(src.rpcs)
transformer.xy(0, 0, zs=src.rpcs.height_off)
(-123.48096552376548, 49.528097381526386)
```

Better yet is to sample height values from a digital elevation model (DEM). `RPCTransformer` allows for options to be passed to `GDALCreateRPCTransformer`

```>>> with rasterio.open('RGB.byte.rpc.vrt') as src:
transformer = rasterio.trasform.RPCTransformer(src.rpcs, rpc_dem='vancouver-dem.tif')
transformer.xy(0, 0)
(-123.47954729595642, 49.5279448909449)
```

## Transformer Resources

The `AffineTransformer` is a pure Python class, however `GCPTransformer` and `RPCTransformer` make use of C/C++ GDAL objects. Explicit control of the transformer object can be achieved by use within a context manager or by calling `close()` method e.g.

```>>> with rasterio.transform.RPCTransformer(rpcs) as transform:
transform.xy(0, 0)
>>> transform.xy(0, 0)
ValueError: Unexpected NULL transformer
```

Note

If `RPC_DEM` is specified in `rpc_options`, GDAL will maintain an open file handle to the DEM until the transformer is closed.