Lesen Sie die Daten der Shizuoka Prefecture Point Cloud DB mit Java und erstellen Sie Luftbilder und Höhen-PNGs.

■ Übersicht

Vor kurzem studiere ich geografische Informationsverarbeitung mit der Hälfte meiner Arbeit und der Hälfte meiner Hobbys. Als ich nach offenen Punktgruppendaten suchte, kam ich zu Shizuoka Prefecture Point Cloud DB. In Shizuoka Prefecture Point Cloud DB werden Daten im Las-Datensatz veröffentlicht. Lesen Sie daher Las in Java und Luftbild- und Höhendatenbild (Elevation PNG). ) Wurde generiert.

■ Höhen-PNG-Verarbeitung

Höhen-PNG, das in der Höhenkachel des National Land Research Institute verwendet wird wurde zur Digitalisierung der Höhe verwendet. Das Papier in der Höhe PNG ist hier. → "[PNG Altitude Tile - Berücksichtigung und Implementierung des für die Webnutzung geeigneten Altitude-Dateiformats (Yoshiharu Nishioka, Juri Nagatsu, Information Geology Vol. 26, Nr. 4, 2015)](https: //www.jstage.jst. go.jp/article/geoinformatics/26/4/26_155/_pdf) "

Die ElevationPngUtil-Klasse wurde unter Bezugnahme auf die Website des Geography Institute und das Papier erstellt.


import java.awt.Color;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

/**
 * Utility-Klasse Altitude PNG
 */
public class ElevationPngUtil {

	private static final int P8=256;
	private static final int P16=65536;
	private static final int P23=8388608;
	private static final int P24=16777216;
	private static final double U=0.01;

	private ElevationPngUtil(){}

 / * Höhe PNG NA-Wert * /
	public static int NA=P23;

 / * RGB-Werte in Int konvertieren * /
	private static int rgb2Int(int[] c){
		return new Color(c[0],c[1],c[2]).getRGB();
	}

	/**
 * Konvertieren Sie den Höhenwert in den Höhen-PNG-Pixelwert
 * @param z Höhenwert (m)
 * @return Altitude PNG Pixelwert
	 */
	public static int getRGB(double z){
		if(Double.isNaN(z))return P23;
		return rgb2Int(getRGBColor(z));
	}

 / * Höhenwert in RGB konvertieren: int [] * /
	private static int[] getRGBColor(double z){
		if(z<=0)return new int[]{128,0,0};
		int i=(int)Math.round(z*100);
		int r=i >> 16;
		int g=i-(r << 16) >> 8;
		int b=i-((r << 16)+(g << 8));
		return new int[]{r,g,b};
	}

	/**
 * Konvertieren Sie den PNG-Pixelwert in den Höhenwert
 * @param intColor Altitude PNG-Pixelwert
 * @return Höhenwert (m)
	 */
	public static double getZ(int intColor){
		Color c=new Color(intColor);
		int r=c.getRed();
		int g=c.getGreen();
		int b=c.getBlue();
		int x=r*P16+g*P8+b;
		if(x<P23){
			return U*(double)x;
		}else if(x>P23){
			return U*(double)(x-P24);
		}else{
			return Double.NaN;
		}
	}

	public static double[] getMinMaxZ(BufferedImage png){
		double min=Double.MAX_VALUE;
		double max=-Double.MAX_VALUE;
		for(int i=0;i<png.getWidth();i++){
			for(int j=0;j<png.getHeight();j++){
				double h=getZ(png.getRGB(i, j));
				if(Double.isNaN(h))continue;
				min=Math.min(h, min);
				max=Math.max(h, max);

			}
		}
		return new double[]{min,max};
	}

	/**
 * Konvertieren Sie das Höhen-PNG in ein Array von Höhen (double [] [])
	 * @param png
	 * @return
	 */
	public static double[][] imgToDouble(BufferedImage png){
		double[][] ret=new double[png.getWidth()][png.getHeight()];
		for(int i=0;i<ret.length;i++){
			for(int j=0;j<ret[i].length;j++){
				ret[i][j]=getZ(png.getRGB(i, j));
			}
		}
		return ret;
	}

	/**
 * Konvertieren Sie ein Array von Höhen (double [] []) in Höhen-PNG
	 * @param z
	 * @return
	 */
	public static BufferedImage doubleToImg(double[][] z){
		BufferedImage ret=new BufferedImage(z.length,z[0].length,BufferedImage.TYPE_INT_RGB);
		for(int i=0;i<z.length;i++){
			for(int j=0;j<z[i].length;j++){
				ret.setRGB(i, j, getRGB(z[i][j]));
			}
		}
		return ret;
	}

	/**
 * Subtraktion der Höhe PNG
 * @ param b1 Höhe PNG1
 * @ param b2 Höhe PNG2
 * @return Altitude PNG (Höhe PNG1-Höhe PNG2)
	 * @throws IllegalArgumentException
	 */
	public static BufferedImage subZImage(BufferedImage b1,BufferedImage b2)throws IllegalArgumentException{
		int w=b1.getWidth();
		int h=b1.getHeight();
		if(w==b2.getWidth()&&h==b2.getHeight()){
			BufferedImage ret=new BufferedImage(w,h,BufferedImage.TYPE_INT_RGB);
			for(int i=0;i<w;i++){
				for(int j=0;j<h;j++){
					double v1=getZ(b1.getRGB(i, j));
					double v2=getZ(b2.getRGB(i, j));
 					if(Double.isNaN(v1)||Double.isNaN(v2)){
						ret.setRGB(i, j, NA);
					}
					double v3=v1-v2;
					if(v3<0){
						ret.setRGB(i, j, NA);
					}else{
						ret.setRGB(i, j, getRGB(v3));
					}
				}
			}
			return ret;
		}else{
			throw new IllegalArgumentException("Image size is different");
		}
	}

	/**
 * Ausgabe von Höhen-PNG-Daten in Text
 * @param png Altitude PNG
 * @param af Affin-Konvertierung
 * @param out Ausgabedatei
	 * @throws IOException
	 */
	public static void output(BufferedImage png,AffineTransform af,File out) throws IOException{
		Point2D dst=new Point2D.Double();
		BufferedWriter bw=new BufferedWriter(new FileWriter(out));
		int n=1;
		int w=png.getWidth();
		int h=png.getHeight();
		for(int i=0;i<w;i++){
			for(int j=0;j<h;j++){
				dst=af.transform(new Point2D.Double(i,j), dst);
				double v=getZ(png.getRGB(i, j));
				if(Double.isNaN(h))continue;
				bw.write(Integer.toString(n++)+","+dst.getX()+","+dst.getY()+","+Double.toString(v)+"\n");
			}
			bw.flush();
		}
		bw.close();
	}
}

Las-Datensatz wird geladen

Ich habe "laszip4j" verwendet, um den Las-Datensatz zu laden. Die Lizenz für "laszip4j" lautet "GNU Lesser General Public License v2.1".

Ich habe eine LASFileReader-Klasse erstellt, die mehrere Las-Dateien liest und kombiniert und aus einer Gruppe von Punkten Luftbilder und DSMs generiert. Außerdem scheinen diese Punktgruppendaten das Koordinatensystem des ebenen rechten Winkelsystems zu sein.

import java.awt.Color;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.imageio.ImageIO;

import com.github.mreutegg.laszip4j.LASHeader;
import com.github.mreutegg.laszip4j.LASPoint;
import com.github.mreutegg.laszip4j.LASReader;

import net.termat.geo.ElevationPngUtil;

public class LASFileReader {
	private LASReader reader;
	private Rectangle2D bounds;
	private AffineTransform af;
	private BufferedImage img;
	private BufferedImage dem;
	private double[] minmaxZ;
	private Date date;
	private double xScalefactor;
	private double xOffset;
	private double yScalefactor;
	private double yOffset;
	private double zScalefactor;
	private double zOffset;
	private float basef=65536f;

	/**
	 *
 * @param f Las File Array
 * @param mPerPixel 1 Pixel Länge (m)
	 * @throws Exception
	 */
	public static void outputLasDataUnion(File[] f,double mPerPixel)throws Exception{
		List<LASFileReader> list=new ArrayList<LASFileReader>();
		Rectangle2D rect=null;
		for(int i=0;i<f.length;i++){
			if(i==0){
				LASFileReader la=new LASFileReader(f[i],mPerPixel);
				rect=la.getBounds();
				list.add(la);
			}else{
				LASFileReader la=new LASFileReader(f[i],mPerPixel);
				rect=rect.createUnion(la.getBounds());
				list.add(la);
			}
		}
		AffineTransform af=new AffineTransform(new double[]{mPerPixel,0,0,-mPerPixel,rect.getX(),rect.getY()+rect.getHeight()});
		double width=Math.ceil(rect.getWidth())/mPerPixel;
		double height=Math.ceil(rect.getHeight())/mPerPixel;
		BufferedImage img=new BufferedImage((int)width,(int)height,BufferedImage.TYPE_INT_RGB);
		BufferedImage dem=new BufferedImage((int)width,(int)height,BufferedImage.TYPE_INT_RGB);
		for(int i=0;i<dem.getWidth();i++){
			for(int j=0;j<dem.getHeight();j++){
				dem.setRGB(i, j, ElevationPngUtil.NA);
			}
		}
		for(LASFileReader al : list){
			al.createImage(img,dem,af.createInverse());
		}
		String path=f[0].getAbsolutePath();
		File pf=new File(path.replace(".las", "_photp.jpg "));
		File df=new File(path.replace(".las", "_org.png "));
		ImageIO.write(img, "jpg", pf);
		ImageIO.write(dem, "png", df);
	}

	/**
	 *
 * @param f Las Datei
 * @param mPerPixel 1 Pixel Länge (m)
	 * @throws Exception
	 */
	public LASFileReader(File f,double mPerPixel)throws IOException{
		reader = new LASReader(f);
		readHeader();
		af=new AffineTransform(new double[]{mPerPixel,0,0,-mPerPixel,bounds.getX(),bounds.getY()+bounds.getHeight()});
		double width=Math.ceil(bounds.getWidth())/mPerPixel;
		double height=Math.ceil(bounds.getHeight())/mPerPixel;
		img=new BufferedImage((int)width,(int)height,BufferedImage.TYPE_INT_RGB);
		dem=new BufferedImage((int)width,(int)height,BufferedImage.TYPE_INT_RGB);
		for(int i=0;i<(int)width;i++){
			for(int j=0;j<(int)height;j++){
				dem.setRGB(i, j, ElevationPngUtil.NA);
			}
		}
	}

	/**
 * Holen Sie sich Las Datenbereich
	 * @return
	 */
	public Rectangle2D getBounds() {
		return bounds;
	}

	/*
 * Header lesen
	 */
	private void readHeader(){
		LASHeader h=reader.getHeader();
		bounds=new Rectangle2D.Double(h.getMinX(),h.getMinY(),h.getMaxX()-h.getMinX(),h.getMaxY()-h.getMinY());
		minmaxZ=new double[]{h.getMinZ(),h.getMaxZ()};
		Calendar cal=Calendar.getInstance();
		cal.set(Calendar.YEAR, (int)h.getFileCreationYear());
		cal.set(Calendar.DAY_OF_YEAR, (int)h.getFileCreationDayOfYear());
		date=cal.getTime();
		xOffset=h.getXOffset();
		xScalefactor=h.getXScaleFactor();
		yOffset=h.getYOffset();
		yScalefactor=h.getYScaleFactor();
		zOffset=h.getZOffset();
		zScalefactor=h.getZScaleFactor();
	}

	/**
 * Bilderzeugung
 * @param img Luftbild
 * @param dem Höhen-PNG-Bild
 * @param bei Affin-Konvertierung
	 */
	public void createImage(BufferedImage img,BufferedImage dem,AffineTransform at){
	    for (LASPoint p : reader.getPoints()) {
	    	double x=xScalefactor*(double)p.getX()+xOffset;
	    	double y=yScalefactor*(double)p.getY()+yOffset;
	    	double z=zScalefactor*(double)p.getZ()+zOffset;
	    	Point2D px=at.transform(new Point2D.Double(x,y), new Point2D.Double());
	    	float r=((float)p.getRed())/basef;
	    	float g=((float)p.getGreen())/basef;
	    	float b=((float)p.getBlue())/basef;
	    	int col=new Color(r,g,b).getRGB();
	    	img.setRGB((int)px.getX(), (int)px.getY(), col);
	    	dem.setRGB((int)px.getX(), (int)px.getY(), ElevationPngUtil.getRGB(z));
	    }
	}

	/**
 * Bilderzeugung
	 */
	public void createImage(){
		AffineTransform at=null;
		try{
			at=af.createInverse();
		}catch(Exception e){e.printStackTrace();}
	    for (LASPoint p : reader.getPoints()) {
	    	double x=xScalefactor*(double)p.getX()+xOffset;
	    	double y=yScalefactor*(double)p.getY()+yOffset;
	    	double z=zScalefactor*(double)p.getZ()+zOffset;
	    	Point2D px=at.transform(new Point2D.Double(x,y), new Point2D.Double());
	    	float r=((float)p.getRed())/basef;
	    	float g=((float)p.getGreen())/basef;
	    	float b=((float)p.getBlue())/basef;
	    	int col=new Color(r,g,b).getRGB();
	    	img.setRGB((int)px.getX(), (int)px.getY(), col);
	    	dem.setRGB((int)px.getX(), (int)px.getY(), ElevationPngUtil.getRGB(z));
	    }
	}
}

■ Ergebnisse

Punktgruppendaten, die von Shizuoka Prefecture Point Cloud DB heruntergeladen wurden (diesmal werden die Daten von 30XXX00010025-1.las bis 30XXX00010025-6.las verwendet), mit der Klasse LASFileReader. Die Verarbeitung erzeugt das folgende Luftbild und das PNG-Höhenbild. 01.jpg

■ Zukunft

Wenn es öffentliche Daten wie Shizuoka Prefecture Point Cloud DB gibt, denke ich, dass sie auch auf Bürgerebene für verschiedene Initiativen verwendet werden können.

Dieses Mal wurden die Punktgruppendaten des Waldgebiets in "[Erstellung von Baumhöhendaten unter Verwendung von Luftlaser-Vermessungsdaten](https: //www.gsi.go.)" Verwendet, das vom National Land Research Institute eingeführt wurde. Dies liegt daran, dass ich die Überdachungsanalyse des Waldgebiets unter Bezugnahme auf "jp / chirijoho / chirijoho40069.html)" ausprobieren wollte.

Lesen Sie die Daten der Shizuoka Prefecture Point Cloud DB mit Java und versuchen Sie, die Baumhöhe usw. zu ermitteln.

Recommended Posts

Lesen Sie die Daten der Shizuoka Prefecture Point Cloud DB mit Java und erstellen Sie Luftbilder und Höhen-PNGs.
Lesen Sie die Daten der Shizuoka Prefecture Point Cloud DB mit Java und versuchen Sie, die Baumhöhe zu ermitteln.
Fensteraggregation von Sensordaten mit Apache Flink und Java 8
[Java] Vereinfachen Sie die Implementierung der Datenverlaufsverwaltung mit Reladomo
Lesen Sie die ersten 4 Bytes der Java-Klassendatei und geben Sie CAFEBABE aus
Der Suchtpunkt bei der Durchführung der Basisauthentifizierung mit Java URLConnection
Ich habe die Daten der Reise (Tagebuchanwendung) in Java erhalten und versucht, sie # 001 zu visualisieren