I have 5 numpy arrays of shape nx, ny
lons.shape = (nx,ny)
lats.shape = (nx,ny)
reds.shape = (nx,ny)
greens.shape = (nx,ny)
blues.shape = (nx,ny)
The reds, greens and blues arrays contain values that range from 0–255 and the lat/lon arrays are latitude/longitude pixel coordinates.
My question is how do I write this data to a geotiff?
I ultimately want to plot the image using basemap.
Here is the code I have so far, however I get a huge GeoTIFF file (~500MB) and it comes up blank (just a black image). Also note that nx, ny = 8120, 5416.
from osgeo import gdal
from osgeo import osr
import numpy as np
import h5py
import os
os.environ['GDAL_DATA'] = "/Users/andyprata/Library/Enthought/Canopy_64bit/User/share/gdal"
# read in data
input_path = '/Users/andyprata/Desktop/modisRGB/'
with h5py.File(input_path+'red.h5', "r") as f:
red = f['red'].value
lon = f['lons'].value
lat = f['lats'].value
with h5py.File(input_path+'green.h5', "r") as f:
green = f['green'].value
with h5py.File(input_path+'blue.h5', "r") as f:
blue = f['blue'].value
# convert rgbs to uint8
r = red.astype('uint8')
g = green.astype('uint8')
b = blue.astype('uint8')
# set geotransform
nx = red.shape[0]
ny = red.shape[1]
xmin, ymin, xmax, ymax = [lon.min(), lat.min(), lon.max(), lat.max()]
xres = (xmax - xmin) / float(nx)
yres = (ymax - ymin) / float(ny)
geotransform = (xmin, xres, 0, ymax, 0, -yres)
# create the 3-band raster file
dst_ds = gdal.GetDriverByName('GTiff').Create('myGeoTIFF.tif', ny, nx, 3, gdal.GDT_Float32)
dst_ds.SetGeoTransform(geotransform) # specify coords
srs = osr.SpatialReference() # establish encoding
srs.ImportFromEPSG(3857) # WGS84 lat/long
dst_ds.SetProjection(srs.ExportToWkt()) # export coords to file
dst_ds.GetRasterBand(1).WriteArray(r) # write r-band to the raster
dst_ds.GetRasterBand(2).WriteArray(g) # write g-band to the raster
dst_ds.GetRasterBand(3).WriteArray(b) # write b-band to the raster
dst_ds.FlushCache() # write to disk
dst_ds = None # save, close
A GeoTIFF is a TIF file that ends in a three letter . tif extension just like other TIF files, but a GeoTIFF contains additional tags that provide projection information for that image as specified by the GeoTIFF standard.
GeoTIFFs files are raster image file types that are commonly used to store satellite and aerial imagery data, along with geographic metadata that describes the location in space of the image.
GeoTIFF is a public domain metadata standard that enables georeferencing information to be embedded within an image file. The GeoTIFF format embeds geospatial metadata into image files such as aerial photography, satellite imagery, and digitized maps so that they can be used in GIS applications.
I think the issue is when you create the Dataset, you pass it GDT_Float32. For standard images with pixel ranges 0-255, you need GDT_Byte. Float requires values to be between 0-1 typically.
I took your code and randomly generated some data so I could test the rest of your API. I then created some dummy coordinates around Lake Tahoe.
Here is the code.
#!/usr/bin/env python
from osgeo import gdal
from osgeo import osr
import numpy as np
import os, sys
# Initialize the Image Size
image_size = (400,400)
# Choose some Geographic Transform (Around Lake Tahoe)
lat = [39,38.5]
lon = [-120,-119.5]
# Create Each Channel
r_pixels = np.zeros((image_size), dtype=np.uint8)
g_pixels = np.zeros((image_size), dtype=np.uint8)
b_pixels = np.zeros((image_size), dtype=np.uint8)
# Set the Pixel Data (Create some boxes)
for x in range(0,image_size[0]):
for y in range(0,image_size[1]):
if x < image_size[0]/2 and y < image_size[1]/2:
r_pixels[y,x] = 255
elif x >= image_size[0]/2 and y < image_size[1]/2:
g_pixels[y,x] = 255
elif x < image_size[0]/2 and y >= image_size[1]/2:
b_pixels[y,x] = 255
else:
r_pixels[y,x] = 255
g_pixels[y,x] = 255
b_pixels[y,x] = 255
# set geotransform
nx = image_size[0]
ny = image_size[1]
xmin, ymin, xmax, ymax = [min(lon), min(lat), max(lon), max(lat)]
xres = (xmax - xmin) / float(nx)
yres = (ymax - ymin) / float(ny)
geotransform = (xmin, xres, 0, ymax, 0, -yres)
# create the 3-band raster file
dst_ds = gdal.GetDriverByName('GTiff').Create('myGeoTIFF.tif', ny, nx, 3, gdal.GDT_Byte)
dst_ds.SetGeoTransform(geotransform) # specify coords
srs = osr.SpatialReference() # establish encoding
srs.ImportFromEPSG(3857) # WGS84 lat/long
dst_ds.SetProjection(srs.ExportToWkt()) # export coords to file
dst_ds.GetRasterBand(1).WriteArray(r_pixels) # write r-band to the raster
dst_ds.GetRasterBand(2).WriteArray(g_pixels) # write g-band to the raster
dst_ds.GetRasterBand(3).WriteArray(b_pixels) # write b-band to the raster
dst_ds.FlushCache() # write to disk
dst_ds = None
Here is the output. (Note: The goal is to produce colors, not terrain!)
Here is the image in QGIS, validating the projection.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With