import rastereasy

Adapting spectral bands with optimal transport

Read images, info and plot them

image1=rastereasy.Geoimage('./data/demo/source.tif')
image2=rastereasy.Geoimage('./data/demo/target.tif')
image1.info()
image2.info()
- Size of the image:
   - Rows (height): 1000
   - Cols (width): 1000
   - Bands: 3
- Spatial resolution: 10.0  meters / degree (depending on projection system)
- Central point latitude - longitude coordinates: (41.88007631, -4.51648135)
- Driver: GTiff
- Data type: int16
- Projection system: EPSG:32630
- Nodata: -32768.0

- Given names for spectral bands: 
   {'1': 1, '2': 2, '3': 3}


- Size of the image:
   - Rows (height): 1000
   - Cols (width): 1000
   - Bands: 3
- Spatial resolution: 10.000728597449909  meters / degree (depending on projection system)
- Central point latitude - longitude coordinates: (41.88003619, -4.51641528)
- Driver: GTiff
- Data type: uint16
- Projection system: EPSG:32630

- Given names for spectral bands: 
   {'1': 1, '2': 2, '3': 3}
image1.colorcomp(extent='pixel', title='source image')
image2.colorcomp(extent='pixel', title = 'target image')
../_images/9c550afa32557d525727ef982ce56c330be36a09eb9b00804ae4a6b7ca9b6b47.png ../_images/540e1d2142e4e742ee1c3c550da24cd5a00b63d4c4cc5ce93a13b4bd49a170bf.png
image1.hist(superpose=True, title='histogram source image')
image2.hist(superpose=True, title='histogram target image')
../_images/39f77dd54aa0342a21c7b6dbe7ddea9c1b0abb4110f0cf92f65ebe7fabbbaab8.png ../_images/4a99ef1bb1403045bdc3fa99a9dc441d70e52bd48362454e5a11c7d74bae92ad.png

Domain adaptation. Two possibilities :

  1. return an adapted image (image1.adapt function)

  2. directly modify the image (image1.adapt function with inplace=True option)

help(image1.adapt)
Help on method adapt in module rastereasy.rastereasy:

adapt(imt, tab_source=None, nb=1000, mapping='gaussian', reg_e=0.1, mu=1.0, eta=0.01, bias=False, max_iter=20, verbose=True, sigma=1, inplace=False) method of rastereasy.rastereasy.Geoimage instance
    Adjust spectral characteristics to match a target image.
    
    This method adapts the spectral characteristics of the current image to match
    those of a target image using optimal transport methods. This is useful for
    harmonizing images from different sensors or acquisitions.
    
    Parameters
    ----------
    imt : Geoimage or numpy.ndarray
        Target image serving as a reference for spectral adjustment,
        or a NumPy array of shape (N, bands) containing N spectral samples.
    tab_source : numpy.ndarray, optional
        Required if `imt` is a NumPy array. Must be an array of shape (M, bands)
        containing spectral samples from the source image.
    nb : int, optional
        Number of random samples used to train the transport model.
        Default is 1000.
    mapping : str, optional
        Optimal transport method to use:
        - 'emd': Earth Mover's Distance (simplest)
        - 'sinkhorn': Sinkhorn transport with regularization (balanced)
        - 'mappingtransport': Mapping-based transport (flexible)
        - 'gaussian': Transport with Gaussian assumptions (default, robust)
        Default is 'gaussian'.
    reg_e : float, optional
        Regularization parameter for Sinkhorn transport.
        Default is 1e-1.
    mu : float, optional
        Regularization parameter for mapping-based methods.
        Default is 1e0.
    eta : float, optional
        Learning rate for mapping-based transport methods.
        Default is 1e-2.
    bias : bool, optional
        Whether to add a bias term to the transport model.
        Default is False.
    max_iter : int, optional
        Maximum number of iterations for iterative transport methods.
        Default is 20.
    verbose : bool, optional
        Whether to display progress information.
        Default is True.
    sigma : float, optional
        Standard deviation used for Gaussian transport methods.
        Default is 1.
    inplace : bool, default False
        If False, return a copy. Otherwise, do the adaptation in place and return None.
    
    Returns
    -------
        The image with adapted spectral characteristics or None if `inplace=True`
    
    Examples
    --------
    >>> # Basic spectral adaptation
    >>> image_adapt = image1.adapt(image2)
    >>> image_adapt.visu()  # Now spectrally similar to image2
    >>>
    >>> # Use specific transport method
    >>> image_adapt = image1.adapt(image2, mapping='sinkhorn', reg_e=0.01)
    >>> image_adapt.save("adapted_image.tif")
    >>>
    >>> # Adaptation using sample arrays
    >>> adapted_image = image1.adapt(tab_target, tab_source = tab_source, mapping='sinkhorn', reg_e=0.01)
    >>>
    >>> # Basic spectral adaptation and modify inplace the image
    >>> image1.adapt(image2, inplace=True)
    >>> image1.visu()  # Now spectrally similar to image2
    
    Notes
    -----
    - This method is useful for:
        - Harmonizing multi-sensor data
        - Matching images acquired under different conditions
        - Preparing time-series data for consistent analysis
    - Different mapping methods have different characteristics:
        - 'emd': Most accurate but slowest
        - 'sinkhorn': Good balance between accuracy and speed
        - 'mappingtransport': Flexible and can handle complex transformations
        - 'gaussian': Fastest and works well for most cases

1) Adaptation

image1_adapted = image1.adapt(image2,mapping='emd')
Fitting transport model using emd method...
Transforming data...
Adaptation complete.
image1_adapted.colorcomp(title='source image adapted to target image',extent='pixel')
image1_adapted.hist(superpose=True,title='Hist source image adapted to target image')
../_images/bd4ca2c236f77a8ba85bcd44ab9edf8b7f379d80fd4910abce102163b7a8dd22.png ../_images/da1fb7729da930d2b273de114c64a3426b12bf792f728783413840756c9ed0cb.png

2) By modifying the image directly inplace=True option

image1.colorcomp(title='image 1 before adaptation',extent='pixel')
image1.hist(superpose=True,xmin=0,xmax=5000,title = 'hist image 1 before adaptation')
../_images/c923dbb480f589897c8ae3b95081b6842a689a9842eccd421d78c5de25eea935.png ../_images/795bb536a98451db2d2adffd2b2ac7c5578403f5d28dfaa64f621bb2ad992d33.png
image1.adapt(image2,mapping='emd',inplace=True)
Fitting transport model using emd method...
Transforming data...
Adaptation complete.
image1.colorcomp(title='image 1 after adaptation',extent='pixel')
image1.hist(superpose=True,xmin=0,xmax=5000,title = 'hist image 1 after adaptation')
../_images/fdeed757eb6b346a90b35539d831524dca449d7226adfe21f3d714b6680f9f78.png ../_images/f3349683b110a490d3e9c66ab145c602b7c9bc0688e6f3c51029e33c9bc3e41e.png

2) By manually selecting the samples

Important for google colab

To use the interactive plotting features in Google Colab, a special two-step setup is required. Follow these steps in the exact order. Separating the commands into different cells and restarting the session is essential.

Step 1: Install Libraries

Run the following cell to install rastereasy and the necessary dependencies for interactive widgets.

!pip install rastereasy ipympl
from google.colab import output
output.enable_custom_widget_manager()

Step 2: Restart the Runtime

After the installation is complete, you must restart the runtime.

Go to the menu: Runtime > Restart runtime (or use the shortcut Ctrl+M).

Step 3: Run Your Code

After restarting, you can now enable the interactive mode and use the library in a new cell.

%matplotlib widget
import rastereasy
image1=rastereasy.Geoimage('./data/demo/source.tif')
image2=rastereasy.Geoimage('./data/demo/target.tif')
image1.info()
image2.info()
- Size of the image:
   - Rows (height): 1000
   - Cols (width): 1000
   - Bands: 3
- Spatial resolution: 10.0  meters / degree (depending on projection system)
- Central point latitude - longitude coordinates: (41.88007631, -4.51648135)
- Driver: GTiff
- Data type: int16
- Projection system: EPSG:32630
- Nodata: -32768.0

- Given names for spectral bands: 
   {'1': 1, '2': 2, '3': 3}


- Size of the image:
   - Rows (height): 1000
   - Cols (width): 1000
   - Bands: 3
- Spatial resolution: 10.000728597449909  meters / degree (depending on projection system)
- Central point latitude - longitude coordinates: (41.88003619, -4.51641528)
- Driver: GTiff
- Data type: uint16
- Projection system: EPSG:32630

- Given names for spectral bands: 
   {'1': 1, '2': 2, '3': 3}
# If google colab, do not forget to put `%matplotlib widget` before importing rastereasy
samples_source,_,_=image1.plot_spectra()
nootebook
# If google colab, do not forget to put `%matplotlib widget` before importing rastereasy
samples_target,_,_=image2.plot_spectra()
nootebook
print('size of sample source = ',len(samples_source))
print('size of sample target = ',len(samples_target))
size of sample source =  65
size of sample target =  58
import numpy as np
image1_adapted = image1.adapt(np.array(samples_target),np.array(samples_source),mapping='sinkhorn')
Fitting transport model using sinkhorn method...
Transforming data...
Adaptation complete.
image1_adapted.colorcomp(extent='pixel', title = 'image 1 after adaptation')
../_images/d1557d9a159c301513e9bbbaa2378da373ddf1376ab71703de40557c4ff3f959.png
image2.hist(superpose=True,xmin=0,xmax=5000,title = 'hist image 1 after adaptation')
image1_adapted.hist(superpose=True,xmin=0,xmax=5000,title = 'hist image 1 after adaptation')
../_images/210d426b539dc4528ebd02e642853519ee771d62c58e6c0496d5a2b64b4a4efe.png ../_images/a95318d7bc2476a29d54dcdcf09d06b0345401509fc0353cfefd998a995b5488.png