Reading data from boolean OLCI product Masks using snappy

Hi Again,

I’m trying to read in the Masks present in a subset OLCI reflectance product.
I first load the mask group:
Masks = sub_product.getGroup(‘Masks’)
I then access the mask I am interested in:
glintMask = Masks.get(‘quality_flags_sun_glint_risk’)

However this return an object of type org.esa.snap.core.datamodel.ProductNode. This type does not have the readPixel method as for object types org.esa.snap.core.datamodel.Band. This is an example of what I’d like to do but for the tie points:
lon = rp.getTiePointGrid(‘TP_longitude’).readPixels(0, 0, w, h, np.zeros(w * h, np.float32))

Thus I am struggling to read the data from the [boolean] Masks. Can you help to point to methods to read in the boolean masks?

Thanks!

Instead of getGroup(‘GroupName’) it is besser to use getMaskGroup()
This returns a ProductNodeGroup which will give you the masks you want.
The mask will have integer values, either 0 or 255

Hi Marko,

I’m still struggling to read in the Mask data to a numpy array.

Masks = sub_product.getMaskGroup(‘Masks’) > org.esa.snap.core.datamodel.ProductNodeGroup
landMask = Masks.get(‘quality_flags_land’) > org.esa.snap.core.datamodel.ProductNode
I don’t see any methods to readPixels for a ProductNode object. Can you help?

I know I can read the masks using flag codings from the Band ‘quality_flags’, but it would be easier I think to read them in directly from the boolean Masks group if possible.

If you let landMask be org.esa.snap.core.datamodel.Mask you have the readPixels() available. The values are integer (0|255) and not boolean.

HI Marko,

Sorry, but I can’t seem to be able to work out how to create the org.esa.snap.core.datamodel.Mask class to access the mask layer. Please would you be able to provide some more instructions how to turn the org.esa.snap.core.datamodel.ProductNode object into the org.esa.snap.core.datamodel.Mask object?

Thanks,
Mark.

Hi Marko, again, any advice on which method I can use from org.esa.snap.core.datamodel.Product (or other class object) to access an org.esa.snap.core.datamodel.mask object appreciated, .getband does not work for masks as far as I can tell… Thanks again!

After searching for days, I settled on a work around by reading in the L1 flag band, then accessing the flags using bitget function. However, it may be an issue that the mask layers are not read accessible… since I found no method to do so…

mask_group = product.getMaskGroup()
print(list(mask_group.getNodeNames()))

mymask = mask_group.get("mymask")

mymaskdata = ... # some numpy array allocation of type int32 and shape (height, width)
mymask.readPixels(0, 0, width, height, mymaskdata)

See

1 Like

Thanks Norman, however:

mask_group = product.getMaskGroup()
mymask = mask_group.get(‘quality_flags_land’)
mymask.readPixels(0, 0, width, height, np.zeros((h , w), np.float32))

Traceback (most recent call last):
File “”, line 1, in
mymask.readPixels(0, 0, width, height, np.zeros((h , w), np.float32))
AttributeError: ‘org.esa.snap.core.datamodel.ProductNode’ object has no attribute ‘readPixels’

Likely a bug.

It seems that mymask is interpreted as a ProductNode which does not have the readPixels methods.
Can you make it org.esa.snap.core.datamodel.Mask?

Was this ever resolved? When I try to make the node a mask as for example:

product = snappy.ProductIO.readProduct(product_path)
mask_group = product.getMaskGroup()
mymask = mask_group.get('quality_flags_land')
h = product.getSceneRasterHeight()
w = product.getSceneRasterWidth()
data = np.zeros(w * h, np.uint32)
im = snappy.Mask.getSourceImage(mymask)
im.getData().getPixels(0,0,w,h, data)
data.shape = h, w

data remains zeros

1 Like

Mmmh, strange. Didn’t know that this is not working.

What happens if you try this:
mymask.readPixels(0,0,w,h, data)

Maybe it is better to read from the mask directly and not from the underlying image.

1 Like

This has the problem that @MarkWilliamMatthews was describing:

AttributeError: 'org.esa.snap.core.datamodel.ProductNode' object has no attribute 'readPixels'

1 Like

Ah ok. The reason for the error is that Python doesn’t know that mymask is a Mask.
In Java mask_group.get(...) returns a ProductNode<Mask>. This information gets lost in Python.
It should be possible to cast it to a Mask.

from snappy import Mask
my_real_mask = jpy.cast(myMask, Mask)

Afterwards it should be possible to call readPixels on my_real_mask.

2 Likes

Works perfectly, thanks

Hi everyone. Does anything change about this? I’ve been trying to make it work and it doesn’t for me. Here is my code:

from snappy import ProductIO, Mask, jpy
import numpy as np

product = ProductIO.readProduct(path_to_product)
mask_group = product.getMaskGroup()
myMask = mask_group.get(“opaque_clouds_10m”)
height = product.getSceneRasterHeight()
width = product.getSceneRasterWidth()
databox = np.zeros(width * height, np.uint32)
castedMask = jpy.cast(myMask, Mask)
castedMask.readPixels(0, 0, width, height, databox)

I’ve tried with different masks, and all return zero arrays. I checked on the SNAP Desktop and the masks already have information. Any ideas?

Thanks in advanced.
Marcos.

Hi Marcos,

The code you mentioned does not work for me now either, I think since the new version of SNAP. We have been discussing that in this thread too, but no solution so far.

Thanks,

Sam

1 Like

Hi, shunt16, marfersel

I get the cloud mask successfully by casting Java ProductNode to Java Band, rather than Java Mask.
My version is SNAP9.0-snappy, and data is sentinel2

for example:

from snappy import Band
mask_java = jpy.cast(source_product.getMaskGroup().get(“opaque_clouds”), Band)

sentinel2 cloud mask

I don’t know if other posts have already solved this problem, hope this method can help you :slightly_smiling_face: