Introduction
TIFF and GeoTIFF files are widely used for storing raster imagery. While TIFFs are general-purpose image formats, GeoTIFFs include georeferencing metadata, which makes them essential for GIS and remote sensing.
This guide covers how to read .tif files in Python using different libraries—depending on whether you're handling satellite data, scientific TIFFs, or just standard images.
Goal: Load .tif files efficiently and explore or manipulate raster content in Python.
1. rasterio (Best for GeoTIFF)
The rasterio package is designed for reading and writing geospatial raster datasets (GeoTIFF, NetCDF, etc.). It reads georeferencing metadata like CRS, bounds, transform, and nodata values.
Installation
1 | pip install rasterio |
Code Example
1 2 3 4 5 6 | import rasterio with rasterio.open("your_file.tif") as src: data = src.read(1) # Read the first band print(data.shape) # Dimensions (height, width) print(src.profile) # Metadata |
Key Notes
src.read(1): Read the first band (common for grayscale or single-band rasters).src.read(): Reads all bands, returns a 3D array(bands, rows, cols).src.crs: Coordinate reference system.src.transform: Affine transformation matrix (used for geolocation).src.bounds: Bounding box in spatial coordinates.
Best for: satellite imagery, climate data, DEMs, fire detection maps, and any raster with CRS.
2. tifffile (For scientific or multi-page TIFFs)
tifffile is great for reading high-dimensional, multi-page, or microscopy TIFF images. It’s not geospatial-aware but extremely fast and flexible.
Installation
1 | pip install tifffile |
Code Example
1 2 3 4 | import tifffile as tiff img = tiff.imread("your_file.tif") print(img.shape) |
Key Notes
- Supports multi-page TIFFs and stacked images.
- Efficient with large scientific image data (bioimaging, astronomy).
- No support for CRS or affine transforms.
Best for: microscopy, hyperspectral, or scientific imaging.
3. Pillow (For simple image viewing)
The Pillow (PIL) library is good for basic image manipulation and display. It can load TIFFs but not specialized metadata.
Installation
1 | pip install pillow |
Code Example
1 2 3 4 5 6 | from PIL import Image import numpy as np img = Image.open("your_file.tif") array = np.array(img) print(array.shape) |
Key Notes
- Supports many image formats (PNG, JPEG, TIFF).
- Does not handle CRS or geospatial context.
- Good for thumbnails, filters, or quick previews.
Best for: simple non-geospatial TIFFs or pre-processing.
4. OpenCV (For fast image operations)
OpenCV is a powerful computer vision library that can load TIFFs quickly for image processing tasks.
Installation
1 | pip install opencv-python |
Code Example
1 2 3 4 | import cv2 img = cv2.imread("your_file.tif", cv2.IMREAD_UNCHANGED) print(img.shape) |
Key Notes
- Handles multi-band images (to an extent).
- Doesn’t understand geospatial metadata.
- Fast I/O, used for image processing pipelines.
Best for: edge detection, object tracking, filters, CV tasks.
5. Which One Should You Use?
| Purpose | Best Tool |
|---|---|
| Geospatial raster (GeoTIFF) | ✅ rasterio |
| Scientific TIFF (microscopy) | ✅ tifffile |
| Standard image viewing/editing | ✅ Pillow |
| Image processing / CV pipelines | ✅ OpenCV |
6. Example: Natural Earth GeoTIFF Visualization
Here’s how to read and visualize a GeoTIFF file from Natural Earth, such as:
NE1_HR_LC_SR_W_DR.tif– 10m resolution raster containing shaded relief, land cover, and water drainages.
Step 1: Load and inspect
1 2 3 4 5 6 7 | import rasterio with rasterio.open("NE1_HR_LC_SR_W_DR.tif") as src: r = src.read(1) # Red g = src.read(2) # Green b = src.read(3) # Blue print(src.profile) |
Output shape:
(10800, 21600)— a 3-band RGB raster, resolution approx 10 arc-minutes (\~20 km at the equator)
Step 2: Display with matplotlib
1 2 3 4 5 6 7 8 9 10 | import numpy as np import matplotlib.pyplot as plt rgb = np.dstack((r, g, b)) plt.figure(figsize=(14, 7)) plt.imshow(rgb) plt.title("Natural Earth Shaded Relief (RGB)") plt.axis('off') plt.show() |

Step 3: Downsample if needed
1 2 3 4 5 6 7 8 9 | from skimage.transform import resize rgb_small = resize(rgb, (1080, 2160), preserve_range=True).astype(np.uint8) plt.figure(figsize=(12, 6)) plt.imshow(rgb_small) plt.title("Downsampled Natural Earth Image") plt.axis('off') plt.show() |
Step 4: Plot with Coordinates using cartopy
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import cartopy.crs as ccrs import cartopy.feature as cfeature with rasterio.open("NE1_HR_LC_SR_W_DR.tif") as src: rgb = np.dstack([src.read(i) for i in [1, 2, 3]]) extent = [src.bounds.left, src.bounds.right, src.bounds.bottom, src.bounds.top] plt.figure(figsize=(16, 8)) ax = plt.axes(projection=ccrs.PlateCarree()) ax.imshow(rgb, extent=extent, transform=ccrs.PlateCarree()) ax.add_feature(cfeature.BORDERS) ax.add_feature(cfeature.COASTLINE) ax.set_title("Natural Earth Base Map with Borders") plt.show() |
7. References
| Library | Link |
|---|---|
| Pillow | https://pillow.readthedocs.io/ |
| Rasterio | https://rasterio.readthedocs.io/ |
| tifffile | https://pypi.org/project/tifffile/ |
| OpenCV | https://docs.opencv.org/ |
| Natural Earth Data | https://www.naturalearthdata.com/ |
