Sentinel 2 product to RGB png patches in Python using snappy


I am quite new with the snappy API. I would like to implement a python script that transforms Sentinel2 RGB images (encoded in uint16) into small RGB png files (encoded in 8bits).

I managed to export a part of an image with the snap HMI (following the differents SNAP tutorials). So I was wondering if the method that can save images into png is reachable from snappy in python ?

So long, I managed to open and read the several bands corresponding to the Blue, Green and Red channels in uint16 thanks to the readRasterData(x,y,w,h,ouput) method (the readPixels method only returning float instead of uint16).

I also tried the createRgbImage methods but I did not managed to limit the opening to an area of pixels for the moment.
Is there any way to open from a python script several bands corresponding to a small area of the Sentinel image and then save the product as a png file ?

Here is my code so far :

> import snappy
> import numpy as np
> from snappy import GPF
> from snappy import jpy
> from snappy import ProductUtils
> from snappy import ProductData

> imageIO = jpy.get_type('javax.imageio.ImageIO')
> HashMap = jpy.get_type('java.util.HashMap')

> GPF.getDefaultInstance().getOperatorSpiRegistry().loadOperatorSpis()

> filename = 'path_to_the_XML_file.xml'
> File = jpy.get_type('')
> reader = snappy.ProductIO.getProductReader("SENTINEL-2-MSI-20M-UTM30N")
> prod = snappy.ProductIO.readProduct(File(filename))

> B = prod.getBand('B2')
> G = prod.getBand('B3')
> R = prod.getBand('B4')

> RGB = [R, G, B]
> RES = []
> for i in range(len(RGB)):
>        Band = ProductData.createInstance(np.zeros((1000, 1000), np.uint16))
>        RGB[i].readRasterData(0, 0, 1000, 1000, Band)
>        RES.append(Band)

What I am searching now is a function that would take the list RES and save it into a RGB png file.

Best regards

Have a look at this thread:

In addition you are probably interested in the following snippet:

image_info = ProductUtils.createImageInfo(bands, true, ProgressMonitor.NULL);
image_rgb = ImageManager.getInstance().createColoredBandImage(bands, image_info, 0);

I’ve updated the example on github. Now it writes also an rgb image.

If you want to use only a certain region of the product you should use the Subset operator to tailor the scene to the region beforehand. For S2 data you need to resample them too, because of their multi-resolution nature.

Roughly written this resampling and subsetting would look like:

from snappy import (HashMap, Rectangle, ProductIO, GPF)

source = ProductIO.readProduct('G:/path/to/S2/data')

parameters = HashMap()
parameters.put('referenceBand', 'B2')
resampled = GPF.createProduct('Resample', parameters, source)

parameters.put('geoRegion', 'POLYGON((15.786082 45.30223, 11.798364 46.118263, 10.878688 43.61961, 14.722727 42.85818, 15.786082 45.30223))')
# or
parameters.put('region', Rectangle(0,0,1000,1000))
result = GPF.createProduct('Subset', parameters, resample)

ProductIO.writeProduct(result, 'target_filepath.dim', 'BEAM-DIMAP')

There might be errors in the script, I just wrote it down with out further testing. But I think you get the idea.
For getting the possible parameter names you can use the command line tool gpt.
For general help

> gpt -h

For a specific operator like subset

> gpt Subset -h

1 Like

Thank you very much for your very complete answer.

I was getting to the conclusion that GPF.createProduct was the solution and I was struggling with the parameters. Now it is much clearer.

I test those solutions right away.