paidiver / paidiverpy

Create pipelines for preprocessing image data for biodiversity analysis.
Apache License 2.0
3 stars 0 forks source link

Scaling and georeferencing #8

Open soutobias opened 2 months ago

soutobias commented 2 months ago

What:

GeoTIFF generation involves creating georeferenced images that embed spatial information within the image metadata. These images can be accurately positioned on a map or within a Geographic Information System (GIS).

Why:

GeoTIFFs are essential for conveying spatial information in a standardized format. They allow images to be integrated into GIS platforms, enabling users to visualize and analyze the spatial relationships between images and other geographic data layers.

How:

If the camera's coordinates are known, you can use ray tracing (as described in section 4.3.4) to convert the image's four corners into georeferenced coordinates. These coordinates are then embedded in the GeoTIFF file's metadata, allowing for precise geospatial referencing.

Python Code Example:

  1. Generating GeoTIFF from Image and Coordinates:

    from osgeo import gdal, osr
    
    def create_geotiff(image_path, output_path, ulx, uly, lrx, lry):
        """
        Create a GeoTIFF from an image with specified georeferenced corner coordinates.
    
        Parameters:
        - image_path: Path to the input image.
        - output_path: Path to save the GeoTIFF.
        - ulx, uly: Upper left corner coordinates (x, y).
        - lrx, lry: Lower right corner coordinates (x, y).
        """
    
        # Open the input image
        src_ds = gdal.Open(image_path)
        if src_ds is None:
            raise ValueError(f"Could not open {image_path}")
    
        # Get the image dimensions
        width = src_ds.RasterXSize
        height = src_ds.RasterYSize
    
        # Calculate the pixel size
        pixel_width = (lrx - ulx) / width
        pixel_height = (uly - lry) / height
    
        # Define the GeoTransform
        geotransform = [ulx, pixel_width, 0, uly, 0, -pixel_height]
    
        # Create the output GeoTIFF file
        driver = gdal.GetDriverByName('GTiff')
        dst_ds = driver.Create(output_path, width, height, src_ds.RasterCount, gdal.GDT_Byte)
    
        # Set the GeoTransform and Projection
        dst_ds.SetGeoTransform(geotransform)
        srs = osr.SpatialReference()
        srs.SetWellKnownGeogCS('WGS84')  # Assuming WGS84 coordinate system
        dst_ds.SetProjection(srs.ExportToWkt())
    
        # Copy over each band from the source to the destination
        for i in range(1, src_ds.RasterCount + 1):
            band = src_ds.GetRasterBand(i)
            dst_ds.GetRasterBand(i).WriteArray(band.ReadAsArray())
    
        # Save and close the GeoTIFF file
        dst_ds = None
        src_ds = None
        print(f"GeoTIFF saved to {output_path}")
    
    # Example usage:
    ulx, uly = 300000, 5000000  # Upper left corner coordinates
    lrx, lry = 300500, 4999500  # Lower right corner coordinates
    create_geotiff('input_image.jpg', 'output_image.tiff', ulx, uly, lrx, lry)
  2. Calculating Corner Coordinates Using Ray Tracing:

    If you have the camera's position, altitude, and angles, you can calculate the georeferenced coordinates of the image corners using ray tracing.

    import numpy as np
    
    def ray_trace_corners(camera_pos, altitude, h_angle, v_angle, image_width, image_height, n_medium):
        """
        Calculate the georeferenced coordinates of image corners using ray tracing.
    
        Parameters:
        - camera_pos: (x, y) coordinates of the camera.
        - altitude: Height of the camera above the ground (or seabed).
        - h_angle: Horizontal field of view (degrees).
        - v_angle: Vertical field of view (degrees).
        - image_width: Image width in pixels.
        - image_height: Image height in pixels.
        - n_medium: refractive index of the medium where the image was taken. Typically, 1.33 for seawater.
    
        Returns:
        - ulx, uly, lrx, lry: Georeferenced coordinates of upper-left and lower-right corners.
        - Area of the image in square meter
        """
    
        # Convert angles to radians
        h_angle_rad = np.radians(h_angle)
        v_angle_rad = np.radians(v_angle)
    
        # Account for any refractive index
        h_angle_rad = arcsin((1/n_medium) * sin(h_angle_rad))
        v_angle_rad = arcsin((1/n_medium) * sin(v_angle_rad))
    
        # Calculate the ground footprint of the image
        ground_width = 2 * altitude * np.tan(h_angle_rad / 2)
        ground_height = 2 * altitude * np.tan(v_angle_rad / 2)
    
        # Calculate pixel size in meters
        pixel_width = ground_width / image_width
        pixel_height = ground_height / image_height
    
        # Calculate the corner coordinates
        ulx = camera_pos[0] - (ground_width / 2)
        uly = camera_pos[1] + (ground_height / 2)
        lrx = camera_pos[0] + (ground_width / 2)
        lry = camera_pos[1] - (ground_height / 2)
    
        # Calculate area
        area = ground_width + ground_height
    
        return ulx, uly, lrx, lry, area
    
    # Example usage:
    camera_pos = (300000, 5000000)  # Camera position in projected coordinates
    altitude = 100  # Altitude in meters
    h_angle = 60  # Horizontal field of view in degrees
    v_angle = 45  # Vertical field of view in degrees
    image_width = 1920  # Image width in pixels
    image_height = 1080  # Image height in pixels
    
    ulx, uly, lrx, lry = ray_trace_corners(camera_pos, altitude, h_angle, v_angle, image_width, image_height)
    print(f"Upper-left corner: ({ulx}, {uly})")
    print(f"Lower-right corner: ({lrx}, {lry})")
  3. Creating the GeoTIFF with Computed Coordinates:

    Using the coordinates calculated above, you can generate a GeoTIFF as shown in the first example:

    create_geotiff('input_image.jpg', 'output_image.tiff', ulx, uly, lrx, lry)

What to expect:

The result of this process is a GeoTIFF image with georeferenced coordinates embedded in its metadata. This allows the image to be accurately placed within a GIS, enabling spatial analysis and visualization.

What makes it difficult:

LoicVA commented 2 months ago

Not only georeferencing but area calculation as well that can be done without the georeferencing (camera pos. = 0,0). Hence I changed the title of that one. I integrated an extra step for integrating the refractive index. Hope that will not mess up the script.