0

BEAM Java APIを使用して ALOS AVNIR-2 プロダクトの PNG クイックルックをエクスポートしようとしています。次の図は、beam の GUI に表示される製品の RGB プレビューを示しています。

ジオコーディング情報に従ってローテーションされた ALOS 衛星プロダクトのクイックルック。

ご覧のとおり、ジオコーディングのため、画像は直立していません。製品のクイックルックをエクスポートするための非常に単純な 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 画像です。

ALOS 衛星プロダクトのクイックルック、直立。

これで、PNG 画像内にジオコーディング情報を含めることはできないことがわかりました。画像の同じ「回転」を再現するだけで済みます。何か案が?

4

1 に答える 1

1

私は自分の問題を解決することができました。つまり、ALOS AV2 O1B2R_U プロダクトからクイックルックを抽出し、プロダクトのジオコーディング情報に従って回転させることができました(下の画像を参照)。

ジオコーディング情報に従ってローテーションされた ALOS 衛星プロダクトのクイックルック。

これは、ALOS AV2 O1B2R_U プロダクトでは、ジオコーディングの回転がラスターに既に適用されているためです。結果として、クイックルックを正常にエクスポートするには、ネイティブ ラスターから回転を取得し、出力画像に適用する必要があります。今後の参考のために、ソリューションをまとめてコミュニティと共有したいと思います。これは私のメインクラスです:

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));
}

クイックルックの回転角度がソース プロダクトから抽出されたら (上記のコードを参照)、出力画像 (BufferedImage) に適用する必要があります。上記のコードでは、resize(...) と rotate(...) の 2 つの単純な画像操作関数が使用されています。これらの定義については以下を参照してください。

    /**
 * 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;
}
于 2015-09-23T15:39:16.150 に答える