/*
* Copyright (C) 2015 by Array Systems Computing Inc. http://www.array.ca
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at your option)
* any later version.
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see http://www.gnu.org/licenses/
*/
package org.esa.s1tbx.fex.gpf.flood;
import org.esa.snap.core.datamodel.Band;
import org.esa.snap.core.datamodel.Mask;
import org.esa.snap.core.datamodel.Product;
import org.esa.snap.core.gpf.Operator;
import org.esa.snap.core.gpf.OperatorException;
import org.esa.snap.core.gpf.OperatorSpi;
import org.esa.snap.core.gpf.annotations.OperatorMetadata;
import org.esa.snap.core.gpf.annotations.SourceProduct;
import org.esa.snap.core.gpf.annotations.TargetProduct;
import org.esa.snap.core.util.ProductUtils;
import org.esa.snap.engine_utilities.datamodel.Unit;
import org.esa.snap.engine_utilities.gpf.OperatorUtils;
import java.awt.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
simple detection of water in slave where there wasn't any water in the master
*/
@OperatorMetadata(alias = "Flood-Detection",
category = "Radar/SAR Applications",
authors = "Jun Lu, Luis Veci",
copyright = "Copyright (C) 2016 by Array Systems Computing Inc.",
version = "1.0",
description = "Detect flooded area.", internal = true)
public class FloodDetectionOp extends Operator {
@SourceProduct(alias = "source")
private Product sourceProduct;
@TargetProduct
private Product targetProduct = null;
// @Parameter(description = "The list of source bands.", alias = "sourceBands",
// rasterDataNodeType = Band.class, label = "Source Bands")
private String[] sourceBandNames = null;
private final HashMap<String, String> targetBandNameToSourceBandName = new HashMap<>();
public static final String MASK_NAME = "_Flood";
@Override
public void initialize() throws OperatorException {
try {
targetProduct = new Product(sourceProduct.getName(),
sourceProduct.getProductType(),
sourceProduct.getSceneRasterWidth(),
sourceProduct.getSceneRasterHeight());
addSelectedBands();
ProductUtils.copyProductNodes(sourceProduct, targetProduct);
} catch (Throwable e) {
OperatorUtils.catchOperatorException(getId(), e);
}
}
/**
* Add the user selected bands to target product.
*
* @throws OperatorException The exceptions.
*/
private void addSelectedBands() throws OperatorException {
// if (sourceBandNames == null || sourceBandNames.length == 0) { // if user did not select any band
final Band[] bands = sourceProduct.getBands();
final List<String> bandNameList = new ArrayList<>(sourceProduct.getNumBands());
for (Band band : bands) {
if (band.getUnit() != null && (band.getUnit().startsWith(Unit.INTENSITY) || band.getUnit().startsWith(Unit.CLASS)))
bandNameList.add(band.getName());
}
sourceBandNames = bandNameList.toArray(new String[bandNameList.size()]);
//}
final Band[] sourceBands = new Band[sourceBandNames.length];
for (int i = 0; i < sourceBandNames.length; i++) {
final String sourceBandName = sourceBandNames[i];
final Band sourceBand = sourceProduct.getBand(sourceBandName);
if (sourceBand == null) {
throw new OperatorException("Source band not found: " + sourceBandName);
}
sourceBands[i] = sourceBand;
}
if(sourceBandNames.length == 0) {
throw new OperatorException("No calibrated bands founds");
}
for (Band srcBand : sourceBands) {
final String srcBandNames = srcBand.getName();
final String unit = srcBand.getUnit();
if (unit == null) {
throw new OperatorException("band " + srcBandNames + " requires a unit");
}
if (unit.contains(Unit.IMAGINARY) || unit.contains(Unit.REAL) || unit.contains(Unit.PHASE)) {
throw new OperatorException("Please select amplitude or intensity band");
}
final String targetBandName = srcBandNames + MASK_NAME;
targetBandNameToSourceBandName.put(targetBandName, srcBandNames);
ProductUtils.copyBand(srcBandNames, sourceProduct, targetProduct, true);
}
final Band mstBand = targetProduct.getBandAt(0);
final Band slvBand = targetProduct.getNumBands() > 1 ? targetProduct.getBandAt(1) : null;
final Band terrainMask = getFeatureBand(targetProduct, "Terrain_Mask");
final Band globCover = getFeatureBand(targetProduct, "GlobCover");
final Band homogeneity = getFeatureBand(targetProduct, "Homogeneity");
final Band energy = getFeatureBand(targetProduct, "Energy");
final boolean isdB = mstBand.getUnit().contains(Unit.DB);
//create Mask
String expression;
if(isdB) {
expression = "(" + mstBand.getName() + " < -13 )";
if (slvBand != null) {
expression = "!(" + mstBand.getName() + " < -13 )" +
" && (" + slvBand.getName() + " < -13 )";
}
} else {
expression = "(" + mstBand.getName() + " < 0.05 && " + mstBand.getName() + " > 0)";
if (slvBand != null) {
expression = "!(" + mstBand.getName() + " < 0.05 && " + mstBand.getName() + " > 0)" +
" && (" + slvBand.getName() + " < 0.05 && " + slvBand.getName() + " > 0)";
}
}
if (terrainMask != null) {
expression += " && " + terrainMask.getName() + " == 0";
}
if (globCover != null) {
expression += " && " + globCover.getName() + " != 210"; // existing water
}
if (energy != null) {
// expression += " && " + energy.getName() + " > 0.8";
} else if (homogeneity != null) {
// expression += " && " + homogeneity.getName() + " > 0.6";
}
final Mask mask = new Mask(mstBand.getName() + "_flood",
mstBand.getRasterWidth(),
mstBand.getRasterHeight(),
Mask.BandMathsType.INSTANCE);
mask.setDescription("Flood");
mask.getImageConfig().setValue("color", Color.BLUE);
mask.getImageConfig().setValue("transparency", 0.7);
mask.getImageConfig().setValue("expression", expression);
mask.setNoDataValue(0);
mask.setNoDataValueUsed(true);
targetProduct.getMaskGroup().add(mask);
}
private static Band getFeatureBand(final Product product, final String idStr) throws OperatorException {
for(String name : product.getBandNames()) {
if(name.contains(idStr)) {
return product.getBand(name);
}
}
return null;
}
/**
* Operator SPI.
*/
public static class Spi extends OperatorSpi {
public Spi() {
super(FloodDetectionOp.class);
}
}
}