Snappy - copy bands from source product and write to a new band

Hi, I’m using snappy, and I want to write a product that contains

  • some bands copied from a source product
  • metadata and tie-point-grids copied from the same source product
  • a new custom band from data in a numpy array

I have been trying with ProductUtils.copyBand() and targetBand.WritePixels() - I can get one or the other to work separately, but not both.

It feels like this shouldn’t be difficult to implement - is anybody able to provide a simplest case working example?

1 Like

To give you an idea - here is roughly what I’m working with (going round in circles trying permutations of).

W = source.getBandAt(0).getRasterWidth()
H = source.getBandAt(0).getRasterHeight()
targetP = snappy.Product('new_product','new_type',W,H)
targetP.setProductReader(ProductIO.getProductReader('BEAM-DIMAP'))
targetP.setProductWriter(ProductIO.getProductWriter('BEAM-DIMAP'))
ProductUtils.copyMetadata(source,targetP)
ProductUtils.copyTiePointGrids(source,targetP)
ProductUtils.copyBand(bandname,source,bandname,targetP,True)
targetB = targetP.addBand('new_band', snappy.ProductData.TYPE_FLOAT32)
targetB.setUnit(new_band_unit)
targetP.writeHeader('new_product_file.dim')
targetB.writePixels(0,0,W,H,data_array)
targetP.closeIO()
1 Like

I now have a working example, but would still be great if anyone could come up with a cleaner solution or help me to understand what is going on behind the scenes.

Here is my solution:

W = source.getBandAt(0).getRasterWidth()
H = image.getBandAt(0).getRasterHeight()
targetP = snappy.Product(‘new_product’,‘new_type’,W,H)
ProductUtils.copyMetadata(source,targetP)
ProductUtils.copyTiePointGrids(source,targetP)
targetP.setProductWriter(ProductIO.getProductWriter(‘BEAM-DIMAP’))
ProductUtils.copyBand(bandname,source,bandname,targetP,True)
targetP.setProductReader(ProductIO.getProductReader(‘BEAM-DIMAP’))
ProductIO.writeProduct(targetP,‘OUTFILE.dim’,‘BEAM-DIMAP’)

targetB = targetP.addBand(‘newband’, snappy.ProductData.TYPE_FLOAT32)
targetB.setUnit(new_band_unit)
targetP.setProductWriter(ProductIO.getProductWriter(‘BEAM-DIMAP’))
targetP.writeHeader(‘OUTFILE.dim’)
targetB.writePixels(0,0,W,H,data_array)
targetP.closeIO()

1 Like

Hi,
I followed this topic because I’m trying to add a band from one product to another product, I tried to reply (where obviously I needed to) this script, but it doesn’t seem the correct approach. In my case, I would like to write the band (it’s only one band product) contained in “ascending_displacement” as another band of “descending_displacement”. This is my script:

file1 = “path.dim” #here i put the path of the file
descending_displacement = snappy.ProductIO.readProduct(file1)
file2 = “path.dim”
ascending_displacement = snappy.ProductIO.readProduct(file2)

width_d = descending_displacement.getSceneRasterWidth()
height_d = descending_displacement.getSceneRasterHeight()
name_d = descending_displacement.getName()
description_d = descending_displacement.getDescription()
band_names_d = descending_displacement.getBandNames()

width_a = ascending_displacement.getSceneRasterWidth()
height_a = ascending_displacement.getSceneRasterHeight()
name_a = ascending_displacement.getName()
description_a = ascending_displacement.getDescription()
band_names_a = ascending_displacement.getBandNames()

target = snappy.Product(“new_product”,“new_type”, width_a, height_a)
ProductUtils.copyMetadata(ascending_displacement, target)
ProductUtils.copyTiePointGrids(ascending_displacement, target)
target.setProductWriter(ProductIO.getProductWriter(“BEAM-DIMAP”))
ProductUtils.copyBand(band_names_a, target, descending_displacement, True)
target.setProductReader(ProductIO.getProductReader(“BEAM-DIMAP”))

output = “path+name” #here I put the path of destination of the new data and its name
ProductIO.writeProduct(target, output, “BEAM-DIMAP”)

What I am doing wrong?
Thank you in advance!

What’s wrong with the result? Is there an error?
Are you missing bands from the ascending?

Hi marpet,
the error I encounter is

ProductUtils.copyBand(band_names_a, target, descending_displacement, True)
RuntimeError: no matching Java method overloads found

The problem is that band_names_a is an array but the copyBand method requires a single band name.
You can iterate over band_names_a

I will try. Thank you a lot!!

@marpet hello again, and sorry for disturbing
I’m trying another approach, that seems to partially work. It consists on the usage of .tif files of the datasets “ascending_subset” and “descending_subset” in order to build an array in which insert my bands. When I run the code, a serie of errors starts to run in the terminal (“SEVERE: org.esa.snap.core.util.SystemUtils$SnapImagingListener: JAI error occurred: ‘Problem occurs when computing a tile by the owner.’ at com.sun.media.jai.util.SunTileScheduler@3d2202d0
java.lang.NullPointerException”), but then the product is created anway. When I open it on SNAP, in fact, the two band in the single product appear but it’s impossible to open the product because of the error “Unable to read the file”.

Here’s the code (I precise that the two input products have got the same dimensions of height and width)

ascending_subset = snappy.ProductIO.readProduct(path_file)
descending_subset = snappy.ProductIO.readProduct(path_file)

ascending_tif = file.tif
descending_tif = file.tif

ascending = gdal.Open(ascending_tif)
descending = gdal.Open(descending_tif)

band_ascending = ascending.GetRasterBand(1)
band_descending = descending.GetRasterBand(1)

ascending_array = np.array(ascending.ReadAsArray())
descending_array = np.array(descending.ReadAsArray())

product = snappy.Product(“title”, “subtitle”, width1, height1)
writer = snappy.ProductIO.getProductWriter(‘BEAM-DIMAP’)
product.setProductWriter(writer)
ProductUtils.copyMetadata(ascending_subset, product)
ProductUtils.copyTiePointGrids(ascending_subset, product)
ProductUtils.copyBand(“displacement_as”, ascending_subset, product, True)
band1 = product.addBand(“displacement_ascending”, snappy.ProductData.TYPE_FLOAT64)

product.setProductReader(ProductIO.getProductReader(“BEAM-DIMAP”))
product.setProductWriter(writer)
ProductUtils.copyMetadata(descending_subset,product)
ProductUtils.copyTiePointGrids(descending_subset, product) #copia dei dati del discendente
ProductUtils.copyBand(“displacement_des”, descending_subset, product, True)
band2 = product.addBand(“displacement_descending”, snappy.ProductData.TYPE_FLOAT64)

product.setProductReader(ProductIO.getProductReader(“BEAM-DIMAP”))
writer = snappy.ProductIO.getProductWriter(‘BEAM-DIMAP’)
product.setProductWriter(writer)
product.writeHeader(“displacement.dim”)
#band1.setPixels(0, 0, width, height, ascending_array) – set as a comment because when I run it the error “RuntimeError: no matching Java method overloads found”
band1.writePixels(0, 0, width, height, ascending_array)
#band2.setPixels(0, 0, width, height, descending_array)
band2.writePixels(0, 0, width, height, descending_array)

output = output_path
snappy.ProductIO.writeProduct(product, output, “BEAM-DIMAP”)

I don’t know why the final product exists, with the new bands, but they can’t be read.

Thank you in advance!