[JAVA] Versuchen Sie, ein dreidimensionales Modell (PLY-Format) aus der numerischen topografischen Karte DSM der gesamten Präfektur Hyogo zu erstellen

1. Übersicht

Am vergangenen Wochenende hat die Präfektur Hyogo einen 3D-Datensatz mit einer Maschenweite von 1 m für alle Präfekturen veröffentlicht. Die öffentlichen Daten sind DSM, DEM, CS stereoskopische Zeichnung, die Lizenz ist C.C.4.0, "Es sind Daten, die für jeden Zweck sekundär verwendet werden können, also verwenden Sie sie bitte für verschiedene Zwecke."

Als dreidimensionaler Datensatz, der bisher veröffentlicht wurde, gibt es ein numerisches Höhenmodell (5 m Mesh DEM) von Nationales Landforschungsinstitut: Basic Map Information Site. Die numerische topografische Karte der gesamten Präfektur Hyogo weist jedoch die 25-fache Datendichte auf. Zusätzlich zu DEM ist DSM einschließlich Gebäuden und Wäldern für die Öffentlichkeit zugänglich. Damit wollte ich sofort ein dreidimensionales Modell von Städten und Wäldern erstellen. snapshot00.png

2. Was ist diesmal zu machen?

In der Präfektur Hyogo veröffentlichtes DSM ist ein Datensatz, der aus x-, y-Koordinaten und Höhenwerten des orthogonalen Koordinatensystems der 5. Ebene besteht. Ich möchte, dass Farbinformationen ein dreidimensionales Modell ergeben. Aus diesem Grund zunächst Kachel des Geografischen Instituts: [Neueste Fotos im ganzen Land](https://maps.gsi.go.jp/development/ ichiran.html # nahtloses Foto) Ruft die Farbinformationen jedes Netzes von der Bildkachel ab und erstellt ein Tool zum Konvertieren von DSM- in XYZ-RGB-Formatdaten. Erstellen Sie als Nächstes ein Werkzeug, das aus den Scheitelpunktdaten von XYZRGB eine Fläche generiert und ein dreidimensionales Modell im PLY-Format generiert. Für die Spezifikationen des PLY-Formats habe ich auf die folgende Site verwiesen.

3. Implementierung des DSM-> XYZ RGB-Konvertierungstools

(1) Prozessablauf

Der Verarbeitungsablauf ist wie folgt.

  1. Untersuchen Sie die x- und y-Koordinaten von DSM (5. System der orthogonalen Koordinatenebene) und erfassen Sie den Bereich der DSM-Punktgruppe. Machen.
  2. Konvertieren Sie den DSM-Punktgruppenbereich in einen rechteckigen Längen- und Breitengrad.
  3. Konvertieren Sie den rechteckigen Breiten- und Längengradbereich in Pixelkoordinaten und erfassen Sie die zu erfassenden Kachelkoordinaten.
  4. Holen Sie sich die Bildkachel der Koordinaten, die DSM entsprechen, und verketten Sie sie.
  5. Konvertieren Sie die DSM-Punktgruppenkoordinaten in Pixelkoordinaten und erfassen Sie die Farbinformationen des entsprechenden Pixels aus dem erfassten Luftbildbild. Machen.
  6. Ausgabe in eine Textdatei im Format "x y z r g b".

(2) Implementierung der Koordinatenumwandlungsklasse (ebenes orthogonales Koordinatensystem <-> Breite / Länge)

Implementieren Sie zunächst eine Klasse, die die xy-Koordinaten des orthogonalen Koordinatensystems der Ebene in Breiten- und Längengrade konvertiert. "Eine einfachere Berechnungsmethode für die Koordinatenumrechnung zwischen Breiten- und Längengradkoordinaten und ebenen orthogonalen Koordinaten in der Gauß-Krüger-Projektion ”Und die folgende Klasse erstellt.

LonlatXYT.java


import java.awt.geom.Point2D;

public class LonLatXY {
	private static final double a=6378137;
	private static final double rf=298.257222101;
	private static final double m0=0.9999;
	private static final double s2r=Math.PI/648000;
	private static final double n=0.5/(rf-0.5);
	private static final double n15=1.5*n;
	private static final double anh=0.5*a/(1+n);
	private static final double nsq=n*n;
	private static final double e2n=2*Math.sqrt(n)/(1+n);
	private static final double ra=2*anh*m0*(1+nsq/4+nsq*nsq/64);
	private static int jt=5;
	private static int jt2=2*jt;
	private static double ep=1.0;
	private static double[] e=getE();
	private static final double[] phi0=new double[]{0,33,33,36,33,36,36,36,36,36,40,44,44,44,26,26,26,26,20,26};
	private static final double[] lmbd0=new double[]{0,7770,7860,7930,8010,8060,8160,8230,8310,8390,8450,8415,8535,8655,8520,7650,7440,7860,8160,9240};
	private static double[] alp=getAlp();
	private static double[] beta=getBeta();
	private static double[] dlt=getDlt();


	private static double[] getAlp(){
		double[] alp=new double[6];
		alp[1]=(1.0/2.0+(-2.0/3.0+(5.0/16.0+(41.0/180.0-127.0/288.0*n)*n)*n)*n)*n;
		alp[2]=(13.0/48.0+(-3.0/5.0+(557.0/1440.0+281.0/630.0*n)*n)*n)*nsq;
		alp[3]=(61.0/240.0+(-103.0/140.0+15061.0/26880.0*n)*n)*n*nsq;
		alp[4]=(49561.0/161280.0-179.0/168.0*n)*nsq*nsq;
		alp[5]=34729.0/80640.0*n*nsq*nsq;
		return alp;
	}

	private static double[] getBeta(){
		double[] beta=new double[6];
		beta[1]=(1.0/2.0+(-2.0/3.0+(37.0/96.0+(-1.0/360.0-81.0/512.0*n)*n)*n)*n)*n;
		beta[2]=(1.0/48.0+(1.0/15.0+(-437.0/1440.0+46.0/105.0*n)*n)*n)*nsq;
		beta[3]=(17.0/480.0+(-37.0/840.0-209.0/4480.0*n)*n)*n*nsq;
		beta[4]=(4397.0/161280.0-11.0/504.0*n)*nsq*nsq;
		beta[5]=4583.0/161280.0*n*nsq*nsq;
		return beta;
	}

	private static double[] getDlt(){
		double[] dlt=new double[7];
		dlt[1]=(2.0+(-2.0/3.0+(-2.0+(116.0/45.0+(26.0/45.0-2854.0/675.0*n)*n)*n)*n)*n)*n;
		dlt[2]=(7.0/3.0+(-8.0/5.0+(-227.0/45.0+(2704.0/315.0+2323.0/945.0*n)*n)*n)*n)*nsq;
		dlt[3]=(56.0/15.0+(-136.0/35.0+(-1262.0/105.0+73814.0/2835.0*n)*n)*n)*n*nsq;
		dlt[4]=(4279.0/630.0+(-332.0/35.0-399572.0/14175.0*n)*n)*nsq*nsq;
		dlt[5]=(4174.0/315.0-144838.0/6237.0*n)*n*nsq*nsq;
		dlt[6]=601676.0/22275.0*nsq*nsq*nsq;
		return dlt;
	}

	private static double[] getE(){
		double[] e=new double[jt2+2];
		for(int k=1;k<=jt;k++){
			ep*=e[k]=n15/k-n;
			e[k+jt]=n15/(k+jt)-n;
		}
		return e;
	}

	public static Point2D xyToLonLat(int num,double xx,double yy){
		double x=yy;
		double y=xx;
		double xi=(x+m0*Merid(2*phi0[num]*3600*s2r))/ra;
		double xip=xi;
		double eta=y/ra;
		double etap=eta;
		double sgmp=1;
		double taup=0;
		for(int j=beta.length-1;j>0;j--){
			double besin=beta[j]*Math.sin(2*j*xi);
			double becos=beta[j]*Math.cos(2*j*xi);
			xip -=besin*Math.cosh(2*j*eta);
			etap -=becos*Math.sinh(2*j*eta);
			sgmp -=2*j*becos*Math.cosh(2*j*eta);
			taup +=2*j*besin*Math.sinh(2*j*eta);
		}
		double sxip=Math.sin(xip);
		double cxip=Math.cos(xip);
		double shetap=Math.sinh(etap);
		double chetap=Math.cosh(etap);
		double chi=Math.asin(sxip/chetap);
		double phi=chi;
		for(int j=dlt.length-1;j>=0;j--){
			phi +=dlt[j]*Math.sin(2*j*chi);
		}
		double nphi=(1-n)/(1+n)*Math.tan(phi);

		double lmbd=lmbd0[num]*60+Math.atan2(shetap, cxip)/s2r;
		double lat=phi/s2r/3600;
		double lon=lmbd/3600;
		return new Point2D.Double(lon,lat);
	}

	public static Point2D lonlatToXY(int num,double lon,double lat){
		double phirad=Math.toRadians(lat);
		double lmbddeg=Math.floor(lon);
		double lmbdmin=Math.floor(60.0*(lon-lmbddeg));
		double lmbdsec=lmbddeg*3600.0+lmbdmin*60.0+(lon-lmbddeg-lmbdmin/60)*3600.0;

		double sphi=Math.sin(phirad);
		double nphi=(1-n)/(1+n)*Math.tan(phirad);
		double dlmbd=(lmbdsec-lmbd0[num]*60.0)*s2r;
		double sdlmbd=Math.sin(dlmbd);
		double cdlmbd=Math.cos(dlmbd);
		double tchi=Math.sinh(atanh(sphi)-e2n*atanh(e2n*sphi));
		double cchi=Math.sqrt(1+tchi*tchi);
		double xip=Math.atan2(tchi, cdlmbd);
		double xi=xip;
		double etap=atanh(sdlmbd/cchi);
		double eta=etap;
		double sgm=1;
		double tau=0;
		for(int j=alp.length-1;j>0;j--){
			double alsin=alp[j]*Math.sin(2*j*xip);
			double alcos=alp[j]*Math.cos(2*j*xip);
			xi +=alsin*Math.cosh(2*j*etap);
			eta +=alcos*Math.sinh(2*j*etap);
			sgm +=2*j*alcos*Math.cosh(2*j*etap);
			tau +=2*j*alsin*Math.sinh(2*j*etap);
		}
		double x=ra*xi-m0*Merid(2*phi0[num]*3600*s2r);
		double y=ra*eta;
		return new Point2D.Double(x,y);
	}

	private static double Merid(double phi2) {
			double dc=2.0*Math.cos(phi2);
			double[] s=new double[jt2+2];
			double[] t=new double[jt2+2];
			s[1]=Math.sin(phi2);
			for(int i=1;i<=jt2;i++){
				s[i+1]=dc*s[i]-s[i-1];
				t[i]=(1.0/i-4.0*i)*s[i];
			}
			double sum=0.0;
			double c1=ep;
			int j=jt;
			while(j>0){
				double c2=phi2;
				double c3=2.0;
				int l=j;
				int m=0;
				while(l>0){
					c2 +=(c3/=e[l--])*t[++m]+(c3*=e[2*j-l])*t[++m];
				}
				sum +=c1*c1*c2 ; c1/=e[j--];
			}
			return anh*(sum+phi2);
	}

	private static double atanh(double v){
		return 0.5*Math.log((1.0+v)/(1.0-v));
	}
}

(3) Implementierung einer Luftbildkachelbild-Erfassungsklasse

Wir haben die folgende Klasse erstellt, um Kachelbilder von der Karte des Geographical Survey Institute zu erfassen und zu verbinden.

GSITileReader.java


import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import javax.imageio.ImageIO;

public class GSITileReader {
	private static final String base_url="https://cyberjapandata.gsi.go.jp/xyz/seamlessphoto/";
	private static final double L=85.05112877980659;

	public static BufferedImage getGSIImage(Rectangle2D plane,int map_num,int zoom,double scale)throws IOException{
		Shape sp=getLonLatShapeAtPlane(map_num, plane.getX(), plane.getY(), plane.getWidth(), plane.getHeight());
		Rectangle2D rect=sp.getBounds2D();
		long[] topLeft=lonlatToPixel(zoom,rect.getX(),rect.getY());
		long[] bottomRight=lonlatToPixel(zoom,rect.getX()+rect.getWidth(),rect.getY()+rect.getHeight());
		Set<Long> x=new HashSet<Long>();
		Set<Long> y=new HashSet<Long>();
		for(long i=topLeft[1];i<=bottomRight[1];i++){
			x.add((long)Math.ceil(i/256));
		}
		for(long i=bottomRight[2];i<=topLeft[2];i++){
			y.add((long)Math.ceil(i/256));
		}
		Long[] xx=x.toArray(new Long[x.size()]);
		Long[] yy=y.toArray(new Long[y.size()]);
		Arrays.sort(xx);
		Arrays.sort(yy);
		BufferedImage im=new BufferedImage(xx.length*256,yy.length*256,BufferedImage.TYPE_INT_RGB);
		Graphics2D g=im.createGraphics();
		for(int i=0;i<xx.length;i++){
			for(int j=0;j<yy.length;j++){
				try{
					String url=base_url+Integer.toString(zoom)+"/"+Long.toString(xx[i])+"/"+Long.toString(yy[j])+".jpg ";
					BufferedImage tmp=ImageIO.read(new URL(url));
					g.drawImage(tmp, i*256, j*256, null);
				}catch(IOException e){
					e.printStackTrace();
				}
			}
		}
		g.dispose();
		im=subImage(im,plane,(long)xx[0],(long)yy[0],map_num,zoom,scale);
		return im;
	}

	private static BufferedImage subImage(BufferedImage src,Rectangle2D rect,long minX,long minY,int num,int zoom,double scale){
		double xx=rect.getX();
		double yy=rect.getY();
		double ww=Math.abs(rect.getWidth());
		double hh=Math.abs(rect.getHeight());
		minX=minX*256;
		minY=minY*256;
		BufferedImage dst=new BufferedImage((int)(ww/scale),(int)(hh/scale),BufferedImage.TYPE_INT_RGB);
		System.out.println(dst.getWidth()+"/"+dst.getHeight());
		System.out.println(minX+"/"+minY);
		for(int i=0;i<dst.getWidth();i++){
			for(int j=0;j<dst.getHeight();j++){
				double x=xx+scale*i;
				double y=yy-scale*j;
				Point2D p=LonLatXY.xyToLonLat(num, x, y);
				long[] pc=lonlatToPixel(zoom, p.getX(), p.getY());
				int px=(int)(pc[1]-minX);
				int py=(int)(pc[2]-minY);
				int color=src.getRGB(px, py);
				dst.setRGB(i, j, color);
			}
		}
		return dst;
	}

	public static long[] lonlatToPixel(int zoom,double lon,double lat){
		long x=(long)(Math.pow(2, zoom+7)*(lon/180.0+1.0));
		long y=(long)((Math.pow(2, zoom+7)/Math.PI)*(-atanh(Math.sin(Math.toRadians(lat)))+atanh(Math.sin(Math.toRadians(L)))));
		return new long[]{(long)zoom,x,y};
	}

	private static double atanh(double v){
		return 0.5*Math.log((1.0+v)/(1.0-v));
	}

	public static AffineTransform createTfwTransform(Rectangle2D rectXY,BufferedImage img){
		double sx=rectXY.getWidth()/img.getWidth();
		double sy=rectXY.getHeight()/img.getHeight();
		double x=rectXY.getX();
		double y=rectXY.getY()+rectXY.getHeight();
		AffineTransform af=new AffineTransform(new double[]{sx,0,0,-sy,x,y});
        	return af;
	}

	public static Shape getLonLatShapeAtPlane(int num,double x,double y,double w,double h){
		Point2D p1=LonLatXY.xyToLonLat(num, x, y);
		Point2D p2=LonLatXY.xyToLonLat(num, x+w, y);
		Point2D p3=LonLatXY.xyToLonLat(num, x+w, y+h);
		Point2D p4=LonLatXY.xyToLonLat(num, x, y+h);
		GeneralPath gp=new GeneralPath();
		gp.moveTo(p1.getX(),p1.getY());
		gp.lineTo(p2.getX(), p2.getY());
		gp.lineTo(p3.getX(), p3.getY());
		gp.lineTo(p4.getX(), p4.getY());
		gp.closePath();
		return gp;
	}

	public static void outTfw(AffineTransform af,File out)throws IOException{
		BufferedWriter bw=new BufferedWriter(new FileWriter(out));
		bw.write(af.getScaleX()+"\n");
		bw.write(af.getShearX()+"\n");
		bw.write(af.getShearY()+"\n");
		bw.write(af.getScaleY()+"\n");
		bw.write(af.getTranslateX()+"\n");
		bw.write(af.getTranslateY()+"\n");
		bw.close();
	}
}

(4) XYZ RGB-Ausgabeklasse

Schließlich habe ich ein Tool zum Konvertieren von DSM in XYZRGB erstellt, z. B. die Eingabe / Ausgabe von Dateien. In dieser Klasse wird RGB von Pixeln, die DSM-Koordinaten entsprechen, aus dem aufgenommenen Luftbild ausgegeben und im XYZ-RGB-Format ausgegeben. Derzeit ist es möglich, andere als das 5. System der orthogonalen Koordinatenkoordinaten zu unterstützen.

XYZRgbCreator.java


import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;

import javax.imageio.ImageIO;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.TransferHandler;
import javax.swing.UIManager;

public class XYZRgbCreator {

	private JFrame frame;
	private JComboBox<String> zone;

	public XYZRgbCreator(){
		frame=new JFrame();
		frame.setTitle("XYZRGB");
		frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
		try {
			UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
			SwingUtilities.updateComponentTreeUI(frame);
		}catch(Exception e){
			try {
				UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
				SwingUtilities.updateComponentTreeUI(frame);
			}catch(Exception ee){
				ee.printStackTrace();
			}
		}
		WindowAdapter wa=new WindowAdapter(){
			@Override
			public void windowClosing(WindowEvent e) {
				close();
			}
		};
		frame.addWindowListener(wa);
		frame.getContentPane().setLayout(new BorderLayout());
		zone=new JComboBox<String>(new String[]{
				null,"Flugzeug rechtwinklig 01 System","Flugzeug rechtwinklig 02 System","Flugzeug rechtwinkliges 03-System","Flugzeug rechtwinkliges 04. System","Flugzeug rechtwinkliges 05. System","Flugzeug rechtwinkliges 06-System","Flugzeug rechtwinkliges 07. System","Flugzeug rechtwinkliges 08. System",
				"Flugzeug rechtwinkliges 09. System","Flugzeug rechtwinklig 10. System","Flugzeug rechtwinkliges 11. System","Flugzeug rechtwinkliges 12. System","Flugzeug rechtwinkliges 13. System","Flugzeug rechtwinkliges 14. System","Flugzeug rechtwinkliges 15. System","Flugzeug rechtwinkliges 16. System",
				"Flugzeug rechtwinkliges 17. System","Flugzeug rechtwinklig 18. System","Flugzeug rechtwinkliges 19. System"
			});
		zone.setSelectedIndex(5);
		frame.getContentPane().add(zone,BorderLayout.NORTH);
		JLabel label=new JLabel("DSM > XYZRGB");
		label.setFont(new Font(Font.SANS_SERIF,Font.BOLD,24));
		label.setVerticalAlignment(JLabel.CENTER);
		label.setHorizontalAlignment(JLabel.CENTER);
		JPanel jp=new JPanel(new BorderLayout());
		jp.add(label,BorderLayout.CENTER);
		frame.getContentPane().add(jp,BorderLayout.CENTER);
		frame.setSize(480,480);
		frame.setResizable(false);
		DropFileHandler handler=new DropFileHandler();
		label.setTransferHandler(handler);
		jp.setTransferHandler(handler);
	}

	private void close(){
		int id=JOptionPane.showConfirmDialog(frame, "Exit?", "Info", JOptionPane.YES_NO_OPTION,JOptionPane.INFORMATION_MESSAGE);
		if(id==JOptionPane.YES_OPTION){
			frame.setVisible(false);
			System.exit(0);
		}
	}

	private class DropFileHandler extends TransferHandler {
		private static final long serialVersionUID = 1L;
		@Override
		public boolean canImport(TransferSupport support) {
			if (!support.isDrop()) {
				return false;
			}
			if (!support.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
				return false;
			}
			return true;
		}

		@SuppressWarnings("unchecked")
		@Override
		public boolean importData(TransferSupport support) {
			if (!canImport(support)) {
		        return false;
		    }
			Transferable t = support.getTransferable();
			try {
				List<File> files = (List<File>) t.getTransferData(DataFlavor.javaFileListFlavor);
				for (File file : files){
					if(file.isDirectory())continue;
					try{
						process(file);
					}catch(IOException e){
						e.printStackTrace();
					}
				}
			} catch (UnsupportedFlavorException | IOException e) {
				e.printStackTrace();
			}
			return true;
		}
	}

	private void process(File f) throws IOException{
		if(!(f.getName().endsWith(".txt")||f.getName().endsWith(".xyz")))return;
		frame.repaint();
		int bwz=zone.getSelectedIndex();
		Rectangle2D rectXY=getBounds(f);
		BufferedImage img=GSITileReader.getGSIImage(rectXY,bwz,18,0.5);
		String name=f.getName().substring(0,f.getName().lastIndexOf("."));
		File dir=f.getParentFile();
		ImageIO.write(img, "jpg", new File(dir.getAbsolutePath()+"/"+name+".jpg "));
		AffineTransform af=new AffineTransform(new double[]{
				0.5,0,0,-0.5,rectXY.getX(),rectXY.getY()});
		GSITileReader.outTfw(af, new File(dir.getAbsolutePath()+"/"+name+".jgw"));
		try{
			af=af.createInverse();
			BufferedReader br=new BufferedReader(new FileReader(f));
			File out=new File(dir.getAbsolutePath()+"/"+name+"_color.txt");
			BufferedWriter bw=new BufferedWriter(new FileWriter(out));
			String line=null;
			String str=null;
			Rectangle2D imgRect=new Rectangle2D.Double(0, 0, img.getWidth(),img.getHeight());
			while((line=br.readLine())!=null){
				line=line.replaceAll(" ",",");
				String[] sp=line.split(",");
				double x=Double.parseDouble(sp[0]);
				double y=Double.parseDouble(sp[1]);
				Point2D p=af.transform(new Point2D.Double(x,y), new Point2D.Double());
				int xx=(int)Math.floor(p.getX());
				int yy=(int)Math.floor(p.getY());
				if(imgRect.contains(xx, yy)){
					int col=img.getRGB(xx, yy);
					Color color=new Color(col);
					str=line+" "+Integer.toString(color.getRed())+" "+Integer.toString(color.getGreen())+" "+Integer.toString(color.getBlue())+"\n";
				}else{
					str=line+" 0 0 0\n";
				}
				bw.write(str);
				bw.flush();
			}
			br.close();
			bw.close();
		}catch(Exception e){
			e.printStackTrace();
		}
	}

	private Rectangle2D getBounds(File f)throws IOException{
		double xmin=Double.MAX_VALUE;
		double xmax=-Double.MAX_VALUE;
		double ymin=Double.MAX_VALUE;
		double ymax=-Double.MAX_VALUE;
		BufferedReader br=new BufferedReader(new FileReader(f));
		String line=null;
		while((line=br.readLine())!=null){
			line=line.replaceAll(" ",",");
			String[] sp=line.split(",");
			double x=Double.parseDouble(sp[0]);
			double y=Double.parseDouble(sp[1]);
			xmin=Math.min(x, xmin);
			xmax=Math.max(x, xmax);
			ymin=Math.min(y, ymin);
			ymax=Math.max(y, ymax);
		}
		br.close();
		Rectangle2D ret=new Rectangle2D.Double(xmin,ymax,xmax-xmin+1,-(ymax-ymin)-1);
		return ret;
	}

	public static void main(String[] args){
		XYZRgbCreator gp=new XYZRgbCreator();
		gp.frame.setLocationRelativeTo(null);
		gp.frame.setVisible(true);
	}
}

(5) Leistungen

Wenn Sie XYZRgbCreator ausführen, wird das folgende Fenster angezeigt. Wenn Sie die DSM-Datei für die numerische Topographie der gesamten Präfektur Hyogo in das Fenster legen, wird der Prozess gestartet und die xyzrgb-Datei ausgegeben. Ursprünglich sollten die Fortschrittsinformationen des Prozesses angezeigt werden, diesmal wurde sie jedoch weggelassen.

999.jpg

4. Implementierung des RGBXYZ-> PLY-Konvertierungstools

Implementieren Sie anschließend ein Tool zum Konvertieren von XYZ-RGB-Dateien in PLY-Dateien. Das DSM-Modell ist ein dreidimensionales Strukturmodell, in dem nur die Oberfläche definiert ist, das als Oberflächenmodell bezeichnet wird. Daher 2D [Delaunay Division](https://ja.wikipedia.org/wiki/%E3%83%89%E3%83%AD%E3%83%8D%E3%83%BC%E5%9B Ich dachte, dass ein dreidimensionales Modell erzeugt werden könnte, indem% B3) ausgeführt und das dreieckige Polygon auf Fläche gesetzt wird. Delaunay split Ich habe die 2D-Delaunay-Triangulationsbibliothek "TINFOUR" verwendet. Ich habe die erforderlichen Informationen aus mvn repositiry: tinfour überprüft und sie in der POM-Datei zu Dependancis hinzugefügt.

(1) Prozessablauf

Der Verarbeitungsablauf ist wie folgt.

  1. Erstellen Sie eine Scheitelpunktliste aus den XYZ-Informationen der XYZ-RGB-Datei und eine Farbinformationsliste aus den RGB-Informationen.
  2. Übergeben Sie die Scheitelpunktliste an die IncrementalTin-Instanz und führen Sie eine zweidimensionale Delaunay-Aufteilung durch.
  3. Geben Sie die erforderlichen Elemente gemäß den PLY-Spezifikationen aus.
  4. Scheitelpunkt- und Farbinformationen ausgeben.
  5. Informationen zur Ausgabefläche.

(2) Implementierung der PlyCreator-Klasse

Implementieren Sie die PlyCreator-Klasse, die den obigen Prozess ausführt. Es ist ärgerlich, also implementiere ich es als Kommandozeilen-Tool.

PlyCreator.java


import java.awt.Color;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
import java.util.function.Consumer;

import org.tinfour.common.SimpleTriangle;
import org.tinfour.common.Vertex;
import org.tinfour.standard.IncrementalTin;
import org.tinfour.utils.TriangleCollector;

public class PlyCreator extends Observable{
	private List<Vertex> vertexs;
	private List<Color> colors;
	private IncrementalTin tin;

	public PlyCreator(){}

	private void outVertex(BufferedWriter bw)throws IOException{
		System.out.println("Scheitelpunktausgabe");
		for(Vertex v : vertexs){
			StringBuffer buf=new StringBuffer();
			buf.append(Float.toString((float)v.getX())+" ");
			buf.append(Float.toString((float)v.getY())+" ");
			buf.append(Float.toString((float)v.getZ())+" ");
			Color c=colors.get(v.getIndex());
			buf.append(Integer.toString(c.getRed())+" ");
			buf.append(Integer.toString(c.getGreen())+" ");
			buf.append(Integer.toString(c.getBlue())+"\n");
			writeBytes(bw,buf.toString());
		}
	}

	private void outFace(BufferedWriter bw)throws IOException{
		System.out.println("Gesichtsausgabe");
		Consumer<SimpleTriangle> cons=new Consumer<SimpleTriangle>() {
		    @Override
		    public void accept(SimpleTriangle arg){
				StringBuffer buf=new StringBuffer();
				buf.append("3");
				buf.append(" "+Integer.toString(arg.getVertexA().getIndex()));
				buf.append(" "+Integer.toString(arg.getVertexB().getIndex()));
				buf.append(" "+Integer.toString(arg.getVertexC().getIndex()));
				buf.append("\n");
				try{
					writeBytes(bw,buf.toString());
				}catch(IOException e){
					e.printStackTrace();
				}
		    }
		};
		TriangleCollector.visitSimpleTriangles(tin, cons);
	}

	private void writeBytes(BufferedWriter bw,String str)throws IOException{
		bw.write(str,0,str.length());
	}

	public void writePLY(File f)throws IOException{
		System.out.println("PLY-Ausgabe");
		Charset charset = Charset.forName("US-ASCII");
		BufferedWriter bw = Files.newBufferedWriter(f.toPath(),charset);
		writeBytes(bw,"ply\n");
		writeBytes(bw,"format ascii 1.0\n");
		writeBytes(bw,"element vertex "+Integer.toString(vertexs.size())+"\n");
		writeBytes(bw,"property float x\n");
		writeBytes(bw,"property float y\n");
		writeBytes(bw,"property float z\n");
		writeBytes(bw,"property uchar red\n");
		writeBytes(bw,"property uchar green\n");
		writeBytes(bw,"property uchar blue\n");
		writeBytes(bw,"element face "+Integer.toString(tin.countTriangles().getCount())+"\n");
		writeBytes(bw,"property list uchar int vertex_index\n");
		writeBytes(bw,"end_header\n");
		outVertex(bw);
		outFace(bw);;
		bw.close();
	}

	public void readXYZGRB(File f,String separator)throws IOException{
		System.out.println("Datei lesen");
		BufferedReader br=new BufferedReader(new FileReader(f));
		String line=null;
		vertexs=new ArrayList<Vertex>();
		colors=new ArrayList<Color>();
		int id=0;
		while((line=br.readLine())!=null){
			String[] sp=line.split(separator);
			Vertex v=new Vertex(
				Double.parseDouble(sp[0]),
				Double.parseDouble(sp[1]),
				Double.parseDouble(sp[2]),
				id++
			);
			vertexs.add(v);
			Color c=new Color(
				Integer.parseInt(sp[3]),
				Integer.parseInt(sp[4]),
				Integer.parseInt(sp[5])
			);
			colors.add(c);
		}
		br.close();
		System.out.println("TIN-Verarbeitung");
		tin=new IncrementalTin();
		tin.add(vertexs, null);
	}

	public static void main(String[] args){
		 PlyCreator pc=new  PlyCreator();
		 File in=new File(args[0]);
		 File out=new File(args[1]);
		 try{
			 pc.readXYZGRB(in, ",");
			 pc.writePLY(out);
		 }catch(Exception e){
			 e.printStackTrace();
		 }
	}
}

(3) Leistungen

Wenn die PlyCreator-Klasse mit der Eingabedatei (XYZRGB-Datei) und der Ausgabedatei (PLY-Datei) als Argument ausgeführt wird, wird ein dreidimensionales Modell im PLY-Format generiert. 898.jpg

Wenn Sie die PLY-Datei in einen 3D-Viewer wie MeshLab laden, wird das erstellte Modell angezeigt. Das Bild unten ist ein Modellbild, das von DSM in der Nähe der JR Sannomiya Station generiert wurde. snapshot02.png

5. Zusammenfassung

Ich erhielt die Farbinformationen von der Luftaufnahme des National Land Research Institute, konvertierte die numerische topografische Karte DSM der gesamten Präfektur Hyogo in eine XYZ-RGB-Datei und erstellte ein Modell im PLY-Format. Wenn Sie sich das Modell des Stadtgebiets ansehen, mag es etwas rau erscheinen, aber das Bild unten ist ein Modell des DSM des Waldgebiets von Sayo Town. Wenn es sich jedoch um ein 1-m-Netz handelt, ist es ein topografisches Modell, das den Unterschied im Baldachin in Abhängigkeit von der Waldfauna ausdrückt Kann erhalten werden. snapshot00.png

Auf der Website der Präfektur Hyogo: "Durch die Kombination dieser Daten und anderer Daten mit modernster Technologie bieten wir Ideen und Vorschläge zur Nutzung an, um die Bemühungen zur Lösung regionaler Probleme durch die Zusammenarbeit zwischen Privatsektor, Industrie, Wissenschaft und Regierung zu fördern. Wir rekrutieren. "Da jedoch DSM und DEM der gesamten Präfektur Hyogo für die Öffentlichkeit zugänglich sind, kann die numerische topografische Karte der gesamten Präfektur Hyogo für verschiedene Zwecke verwendet werden. Abgesehen von der Präfektur Hyogo veröffentlicht die Präfektur Shizuoka Punktgruppendaten in "Shizuoka-Punktwolkendatenbank", aber auch andere Präfekturen veröffentlichen solche öffentlichen Umfragedaten. Ich finde es interessant, wenn es Bewegung gibt.

Recommended Posts

Versuchen Sie, ein dreidimensionales Modell (PLY-Format) aus der numerischen topografischen Karte DSM der gesamten Präfektur Hyogo zu erstellen
Erstellen Sie eine U-Bahn-Karte von Tokio aus der CSV-Datei von station data.jp
Erstellen Sie eine Mehrschlüsselkarte mit einer Standardbibliothek