Call ProductSet-Reader and Create Stack in Snap

Hi everyone,

Thank you in advance!

I am still new to SNAP and am now trying to co-register images with ‘create stack’ using the snap python binding. I have a pipeline to preprocess single files using snap (apply orbit-radiometric calibration-terrain flattening-terrain correction), and can then otherwise align these nicely using the xml graphs approach-but ideally would like to continue in python.

To do individual files, I start with ProductIO:
ProductIO.readProduct(file_path)

But for the ‘create-stack’ I would like to read multiple files (ideally in a list) using the ‘ProductSet-Reader’.
*Edit: I think have found Operator().ProductSetReaderOp()
but it throws as error (see code below)

I would be grateful if you could guide me how to:

  1. Call the product set reader while passing a list of files (such as file locations or preprocessed products)
  2. Call the ‘create stack’ method taking the product-set as input

Something along the lines of:

from snappy import ProductIO, GPF, jpy, Operator

GPF.getDefaultInstance().getOperatorSpiRegistry().loadOperatorSpis()
HashMap = jpy.get_type('java.util.HashMap')

files_list = ['C:\myGRDH_file1.dim', 'C:\myGRDH_file2.dim']`

#read set of products or files
product_set = Operator().ProductSetReaderOp(files_list)

 #********
#gives error:
'RuntimeError: no constructor found (missing JType attribute '__jinit__')'
#**************

#create stack
params = HashMap()
params.put('resamplingType', None)
params.put('initialOffsetMethod', 'Product Geolocation')
params.put('extent', 'Master')
        
create_stack = GPF.createProduct('CreateStack', params, product_set)

Much appreciated,

I think you don’t need the ProductSetReader.

Try the following code to init the product set:

files_list = ['C:\myGRDH_file1.dim', 'C:\myGRDH_file2.dim']
product_set=[]
for file in files_list:
  product_set.append(ProductIO.readProduct(file))

Thank you that was so simple! The create stack also worked nicely.

For anyone else, heres the test script (remember you need to use preprocessed files for the stack to work!):

from snappy import ProductIO, GPF, jpy

GPF.getDefaultInstance().getOperatorSpiRegistry().loadOperatorSpis()
HashMap = jpy.get_type('java.util.HashMap')

#collection of preprocessed files
f1 = 'C:\\preprocess_20170110_144233.dim'
f2 = 'C:\\preprocess_20170110_143826.dim'
f3 = 'C:\\preprocess_20170110_143428.dim'

processed_files = [f1,f2,f3]

product_set=[]

for f in processed_files:
    product_set.append(ProductIO.readProduct(f))
      
#define the stack parameters
params = HashMap()
params.put('resamplingType', None)
params.put('initialOffsetMethod', 'Product Geolocation')
params.put('extent', 'Master')

#make the stack    
create_stack = GPF.createProduct('CreateStack', params, product_set)

#write the stack
ProductIO.writeProduct(create_stack, 'C:\\create_stack', 'BEAM-DIMAP')
2 Likes

Thanks for the script. Can anyone tell me how to select the master product (in the stack)?

The master product ist the first one you specify in the product_set

Thank you for your response. Unfortunately this does not appear to be the case - in a stack sorted by time, the master product is chosen from the middle of the input stack! I can’t seem to force the first (earliest) product to be the master.

As an additional curiosity, does anyone know why the following code results in incorrects sorts:

product_set.sort(key=lambda p: p.getStartTime())

This seems to work though:

product_set.sort(key=lambda p: p.getStartTime().getAsDate())

The first sort is not correct because getStartTime() returns a java ProductData.UTC Object. I think python can’t handle this properly. The getAsDate returns a Date object. For some reason this works, as you say. But I wonder why. To be save you should use p.getStartTime().getAsDate().getTime(). This return a long value. The time in ms.

Thanks. Any idea why (even with a sorted stack) the create_stack() operator may pick a master which is not the first product in the list?

Unfortunately this doesn’t work:

ProductSet = [snappy.ProductIO.readProduct(file) for file in glob.glob(os.path.join(IN_DIR, "*.dim"))]
# sort by StartTime
ProductSet.sort(key=lambda p: p.getStartTime().getAsDate().getTime())
for p in ProductSet:
    print p.getStartTime()

25-DEC-2014 17:49:09.560596
16-AUG-2016 17:49:06.465367
17-JUL-2015 17:49:00.746402
12-APR-2015 17:48:55.988695
29-JUL-2015 17:49:01.456319
11-JUN-2015 17:48:59.587962
24-APR-2015 17:48:56.502041
06-APR-2016 17:49:16.091671
07-MAR-2015 17:48:55.059984
23-JUL-2016 17:49:05.113932
05-JUN-2016 17:49:02.443688
19-MAR-2015 17:48:55.351507
04-AUG-2016 17:49:06.042239
30-APR-2016 17:49:17.159144
13-MAR-2016 17:49:15.373838
25-JAN-2016 17:49:15.408738

As far as I can tell .getStartTime().getAsDate() is ok though.

I think regarding the master product my first answer was a bit to quick and lazy. It seems to be more complicated.
Maybe @lveci can say more about it.

If the masterBandNames parameter specifies specific bands then the master product will be the first product containing the band names. If none are specified then the first product in the list is used.

Thanks for your reply. Here’s what I did:

  1. Ordered the products (each of which contains a single band) by date.
  2. Rename the bands in the products incrementally (0000, 0001, 0002…)
  3. Call CreateStack with params.put('masterBands', '0000')

This results in:

RuntimeError: org.esa.snap.core.gpf.OperatorException: Operator 'CreateStackOp': Value for 'Master Band' is invalid: '0000'

However I can set masterBands to any other bandname (e.g. 0001, 0002…) and it works fine! The only band I cannot select as the master is the one I want to use?!

1 Like

Dear all,

I am new to snappy and I am facing the same issue (snappy create a non-chronological stack). My workflow includes corregister stack, however I tried the solutions proposed in the post and also played a little bit with the parameters of the createStackOp (https://github.com/senbox-org/s1tbx/blob/master/s1tbx-op-insar/src/main/java/org/esa/s1tbx/insar/gpf/coregistration/CreateStackOp.java).

Could you find any solution?

here you find the piece of code:

Band_list_VV = []

for folder in os.listdir(pathOut + “\VV\”)[::2]:
gc.enable()
file = folder.replace(".data", “.dim”)
Band_list_VV.append(ProductIO.readProduct(pathOut + “\VV\” + file))

parameters = HashMap()
parameters.put(‘resamplingType’, None)
parameters.put(‘masterBands’, Band_list_VV[0].getBandAt(0).getName())
parameters.put(‘sourceBands’, Band_list_VV[1].getBandAt(0).getName())
parameters.put(‘initialOffsetMethod’, ‘Product Geolocation’)
parameters.put(‘extent’, ‘Master’)
VV_stack = GPF.createProduct(‘CreateStack’, parameters, Band_list_VV)

Here I got an error:

RuntimeError: org.esa.snap.core.gpf.OperatorException: Operator ‘CreateStackOp’: Value for ‘Slave Bands’ is invalid: ‘DOY_20170217’

also tried:

parameters.put(‘masterBandNames’, Band_list_VV[0].getBandAt(0).getName())
parameters.put(slaveBandNames’, Band_list_VV[1].getBandAt(0).getName())

However all of them get to the same non-order stack. When I run it in the GUI it works fine, but I’m processing 70 S-1 images and the plan is adding every 12 days a new image automatically.

Thanks in advance.