ALOS 卫星产品到 PNG 的转换问题(缺少旋转)

ALOS Satellite Product to PNG conversion issue (missing rotation)

我正在尝试使用 BEAM java API 导出 ALOS AVNIR-2 产品的 PNG quicklook。下图显示了产品的 RGB 预览,因为它出现在 beam 的 GUI 中。

如您所见,由于地理编码,图像不是直立的。我开发了一个非常简单的 java 程序来导出产品的快速浏览。

public static void main(String[] args) {

    String[] rgbBandNames = new String[3];
    rgbBandNames[0] = "radiance_3";
    rgbBandNames[1] = "radiance_2";
    rgbBandNames[2] = "radiance_1";

    try {
    //Product inputProduct = ProductIO.readProduct(args[0]);
        Product inputProduct = ProductIO.readProduct("C:\nfsdata\VOL-ALAV2A152763430-O1B2R_U");

        Band[] produtBands = inputProduct.getBands();
        Band[] rgbBands = new Band[3];

        int n = 0;
        for (Band band : produtBands) {
            if (band.getName().equals(rgbBandNames[0])) {
                rgbBands[0] = band;
            } else if (band.getName().equals(rgbBandNames[1])) {
                rgbBands[1] = band;
            } else if (band.getName().equals(rgbBandNames[2])) {
                rgbBands[2] = band;
            }

            n = n + 1;
        }

        ImageInfo outImageInfo = ProductUtils.createImageInfo(rgbBands, true, ProgressMonitor.NULL);
        BufferedImage outImage = ProductUtils.createRgbImage(rgbBands, outImageInfo, ProgressMonitor.NULL);

        ImageIO.write(outImage, "PNG", new File(inputProduct.getName() + ".png"));


    } catch (IOException e) {
        System.err.println("Error: " + e.getMessage());
    }
}

该程序可以运行,但我从中获得的每个 PNG 图像都是直立的 PNG 图像,如下所示。

现在,我知道不可能在 PNG 图像中包含地理编码信息。我只需要复制相同的 "rotation" 图像。 有什么想法吗?

我设法解决了我的问题。换句话说,我设法 从 ALOS AV2 O1B2R_U 产品中提取 quicklook,根据产品的地理编码信息旋转 (见下图)。

这是因为 ALOS AV2 O1B2R_U 产品的地理编码旋转 已经应用于栅格 。因此,为了成功导出 quicklook,必须从原生栅格中检索旋转并将其应用于输出图像。 为了将来参考,我想回顾一下我的解决方案并与社区分享。这是我的主要 class:

import com.bc.ceres.core.ProgressMonitor;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import org.esa.beam.framework.dataio.ProductIO;
import org.esa.beam.framework.datamodel.Band;
import org.esa.beam.framework.datamodel.ImageInfo;
import org.esa.beam.framework.datamodel.MapGeoCoding;
import org.esa.beam.framework.datamodel.Product;
import org.esa.beam.util.ProductUtils;

public static void main(String[] args) throws IOException {

    String inputProductPath = "path\to\input\product";
    String outputProductPath = "path\to\output\image";

    // Read the source product.
    Product inputProduct = ProductIO.readProduct(inputProductPath);

    // Extract the RGB bands.
    String[] bandNames = new String[3];
    Band[] bandData = new Band[3];

    bandNames[0] = "radiance_3";
    bandNames[1] = "radiance_2";
    bandNames[2] = "radiance_1";

    for (Band band : inputProduct.getBands()) {

        for (int i = 0; i < bandNames.length; i++) {

            if (band.getName().equalsIgnoreCase(bandNames[ i ])) {
                bandData[ i ] = band;
            }
        }
    }

    // Generate quicklook image.
    ImageInfo outImageInfo = ProductUtils.createImageInfo(bandData, true, ProgressMonitor.NULL);
    BufferedImage outImage = ProductUtils.createRgbImage(bandData, outImageInfo, ProgressMonitor.NULL);
    outImage = resize(outImage, WIDTH, 1200);

    // Extract the orientation.
    double orientation;
    if (inputProduct.getGeoCoding() != null) {
        orientation = -((MapGeoCoding) inputProduct.getGeoCoding()).getMapInfo().getOrientation();
    } else {
        orientation = 0.0;
    }
    outImage = rotate(outImage, orientation);

    // Write image.
    ImageIO.write(outImage, "PNG", new File(outputProductPath));
}

一旦从源产品中提取了 quicklook 的旋转角度(参见上面的代码),就必须将其应用于输出图像 (BufferedImage)。在上面的代码中,使用了两个简单的图像处理函数:resize(...) 和 rotate(...),它们的定义见下文。

    /**
 * Resizes the image {@code tgtImage} by setting one of its dimensions
 * (width or height, specified via {@code tgtDimension}) to {@code tgtSize}
 * and dynamically calculating the other one in order to preserve the aspect
 * ratio.
 *
 * @param tgtImage The image to be resized.
 * @param tgtDimension The selected dimension: {@code ImageUtil.WIDTH} or
 * {@code ImageUtil.WIDTH}.
 * @param tgtSize The new value for the selected dimension.
 *
 * @return The resized image.
 */
public static BufferedImage resize(BufferedImage tgtImage, short tgtDimension, int tgtSize) {

    int newWidth = 0, newHeight = 0;

    if (HEIGHT == tgtDimension) {
        newHeight = tgtSize;
        newWidth = (tgtImage.getWidth() * tgtSize) / tgtImage.getHeight();
    } else {
        newHeight = (tgtImage.getHeight() * tgtSize) / tgtImage.getWidth();
        newWidth = tgtSize;
    }

    Image tmp = tgtImage.getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH);
    BufferedImage outImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGemoticon;

    Graphics2D g2d = outImage.createGraphics();
    g2d.drawImage(tmp, 0, 0, null);
    g2d.dispose();

    return outImage;
}

/**
 * Rotates the image {@code tgtImage} by {@code tgtAngle} degrees clockwise.
 *
 * @param tgtImage The image to be rotated.
 * @param tgtAngle The rotation angle (expressed in degrees).
 *
 * @return The resized image.
 */
public static BufferedImage rotate(BufferedImage tgtImage, double tgtAngle) {

    int w = tgtImage.getWidth();
    int h = tgtImage.getHeight();

    AffineTransform t = new AffineTransform();
    t.setToRotation(Math.toRadians(tgtAngle), w / 2d, h / 2d);

    Point[] points = {
        new Point(0, 0),
        new Point(w, 0),
        new Point(w, h),
        new Point(0, h)
    };

    // Transform to destination rectangle.
    t.transform(points, 0, points, 0, 4);

    // Get destination rectangle bounding box
    Point min = new Point(points[0]);
    Point max = new Point(points[0]);
    for (int i = 1, n = points.length; i < n; i++) {
        Point p = points[ i ];
        double pX = p.getX(), pY = p.getY();

        // Update min/max x
        if (pX < min.getX()) {
            min.setLocation(pX, min.getY());
        }
        if (pX > max.getX()) {
            max.setLocation(pX, max.getY());
        }

        // Update min/max y
        if (pY < min.getY()) {
            min.setLocation(min.getX(), pY);
        }
        if (pY > max.getY()) {
            max.setLocation(max.getX(), pY);
        }
    }

    // Determine new width, height
    w = (int) (max.getX() - min.getX());
    h = (int) (max.getY() - min.getY());

    // Determine required translation
    double tx = min.getX();
    double ty = min.getY();

    // Append required translation
    AffineTransform translation = new AffineTransform();
    translation.translate(-tx, -ty);
    t.preConcatenate(translation);

    AffineTransformOp op = new AffineTransformOp(t, null);
    BufferedImage outImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGemoticon;
    op.filter(tgtImage, outImage);

    return outImage;
}