Aus dem PNG-Höhenbild, das in "Lesen Sie die Daten der Shizuoka Prefecture Point Cloud DB mit Java und erstellen Sie Luftbild- und Höhen-PNG." erstellt wurde. , "Erstellung von Baumhöhendaten unter Verwendung von Luftlaser-Vermessungsdaten", eingeführt am National Land Research Institute Versuchen Sie, den Baldachin zu erkennen.
Das in "Lesen Sie die Daten der Shizuoka Prefecture Point Cloud DB mit Java und erstellen Sie Luftbild- und Höhen-PNG." erstellte Höhen-PNG ist DSM. Da es zu entsprechen scheint (digitales Oberflächenmodell), ist es notwendig, die Daten des Geländeteils von hier zu extrahieren. Betrachtet man den "Aerial Laser Survey Mechanism" auf der Website des National Land Research Institute, im Waldgebiet, wird der Laser durch Bäume usw. blockiert. Es kann nicht erreichen, und es scheint, dass es ankommen kann. Aus diesem Grund haben wir diesmal ein 2-m-Netz für das Höhen-PNG festgelegt und den Punkt mit der niedrigsten Höhe in jedem Netz als Höhe der Bodenoberfläche betrachtet. Ich habe die folgende DemMeshImterpolationProcesser-Klasse erstellt und ein Höhen-PNG generiert, das DEM entspricht. ImageProcessingObservable ist eine Observable-Schnittstelle zur Überprüfung des Fortschritts.
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Observable;
import javax.imageio.ImageIO;
public class DemMeshImterpolationProcesser extends Observable implements ImageProcessingObservable{
private double[][] dem;
private Cell[][] cell;
private BufferedImage image;
private String message;
public DemMeshImterpolationProcesser(BufferedImage img){
dem=ElevationPngUtil.imgToDouble(img);
image=new BufferedImage(img.getWidth(),img.getHeight(),BufferedImage.TYPE_INT_RGB);
}
public BufferedImage getImage(){
return image;
}
public void drawMinH(){
for(int i=0;i<cell.length;i++){
for(int j=0;j<cell[i].length;j++){
cell[i][j].setRGB(ElevationPngUtil.getRGB(cell[i][j].getMinH()));
}
}
}
public void createImageCell(int size){
int ww=dem.length;
int hh=dem[0].length;
cell=new Cell[ww/size][hh/size];
int x=0;
int y=0;
for(int i=0;i<cell.length;i++){
for(int j=0;j<cell[i].length;j++){
cell[i][j]=new Cell();
cell[i][j].x=new int[size];
cell[i][j].y=new int[size];
for(int m=0;m<size;m++){
cell[i][j].y[m]=y;
y=(y+1)%hh;
}
for(int m=0;m<size;m++){
cell[i][j].x[m]=x+m;
}
if(y==0)x=x+size;
}
}
}
public void output(File f)throws Exception{
ImageIO.write(image, "png", f);
Update ("Ausgabe beenden");
}
protected void update(String mes){
message=mes;
setChanged();
notifyObservers();
}
@Override
public String progress() {
return message;
}
protected class Cell{
int[] x;
int[] y;
double getMinH(){
double min=Double.MAX_VALUE;
for(int i=0;i<x.length;i++){
for(int j=0;j<y.length;j++){
if(Double.isNaN(dem[x[i]][y[j]])||dem[x[i]][y[j]]<0)continue;
min=Math.min(min, dem[x[i]][y[j]]);
}
}
if(min==Double.MAX_VALUE){
return 0;
}else{
return min;
}
}
void setRGB(int rgb){
for(int i=0;i<x.length;i++){
for(int j=0;j<y.length;j++){
image.setRGB(x[i], y[j], rgb);
}
}
}
}
}
Dies ist das oben erzeugte DEM-Höhen-PNG. (Das Folgende ist ein JPG mit reduzierter Größe.) Nach dem Erzeugen des Höhen-PNG wurde es mit einem 5 × 5-Garcian-Filter geglättet.
Da das zuletzt erstellte Höhen-PNG viele Pixel ohne Daten enthält, habe ich eine TIN generiert und diese interpoliert. "Tinfour" wurde verwendet, um die TIN zu erstellen und zu interpolieren. Die Lizenz für "Tinfour" ist "die Apache-Lizenz, Version 2.0".
/**
* TIN-Erzeugung
*/
public void process(){
for(int i=0;i<img.getWidth();i++){
for(int j=0;j<img.getHeight();j++){
int rgb=img.getRGB(i, j);
double hh=ElevationPngUtil.getZ(rgb);
if(Double.isNaN(hh))continue;
Vertex v=new Vertex(i,j,hh,index++);
list.add(v);
}
}
tin=new IncrementalTin();
tin.add(list, null);
}
/**
* Interpolation durch TIN
* @return
*/
public BufferedImage interpolation(){
BufferedImage ret=new BufferedImage(img.getWidth(),img.getHeight(),BufferedImage.TYPE_INT_RGB);
setInitVal(ret);
TriangularFacetInterpolator tfi=new TriangularFacetInterpolator(tin);
VertexValuatorDefault vvd=new VertexValuatorDefault();
double n=img.getWidth()*img.getHeight();
for(int i=0;i<img.getWidth();i++){
for(int j=0;j<img.getHeight();j++){
double hh=tfi.interpolate(i, j, vvd);
if(hh>0)ret.setRGB(i, j, ElevationPngUtil.getRGB(hh));
}
}
return ret;
}
Das durch TIN geschichtete DSM-Höhen-PNG ist wie folgt. (Das Folgende ist ein JPG mit reduzierter Größe.)
Das Höhenmodell (DCHM) der Höhe von Bäumen usw. wird durch Subtrahieren von DEM von DSM erhalten. Das DCHM-Höhen-PNG, das durch Subtrahieren der DEM-Höhendaten von den DSM-Höhendaten erstellt wurde, ist wie folgt. (Das Folgende ist ein JPG mit reduzierter Größe.)
Die aus DCHM-Höhen-PNG erstellte Höhenkarte (Baumhöhenkarte) lautet wie folgt.
"Aerial Laser Survey Mechanism" führt eine Methode zur Erkennung des Maximalwertpunkts mit einem 3-m-Netz ein. Dieses Mal habe ich einen Suchkreis mit einem Radius von 2,0 m festgelegt und die Scheitelpunktposition mit dem folgenden Code ermittelt.
private void findPeaks(){
for(double z=highH;z>=lowH;z=z-1){
double dv=(++vv)/nn*100;
for(int i=0;i<width;i++){
for(int j=0;j<height;j++){
if(ck[i][j]!=0)continue;
if(val[i][j]>=z){
Ellipse2D e=new Ellipse2D.Double(i-this.radius, j-this.radius, this.radius*2, this.radius*2);
if(isHiMax(e,val[i][j])){
setPeak(e);
points.add(new Point3d(e.getCenterX(),e.getCenterY(),val[i][j]));
}
}
}
}
}
}
private boolean isHiMax(Ellipse2D e,double v){
int xs=(int)Math.max(e.getX(), 0);
int ys=(int)Math.max(e.getY(), 0);
int xe=(int )Math.min(e.getX()+e.getWidth(), width);
int ye=(int)Math.min(e.getY()+e.getHeight(),height);
for(int i=xs;i<xe;i++){
for(int j=ys;j<ye;j++){
if(val[i][j]>v)return false;
}
}
return true;
}
private void setPeak(Ellipse2D e){
int xs=(int)Math.max(e.getX(), 0);
int ys=(int)Math.max(e.getY(), 0);
int xe=(int )Math.min(e.getX()+e.getWidth(), width);
int ye=(int)Math.min(e.getY()+e.getHeight(),height);
for(int i=xs;i<xe;i++){
for(int j=ys;j<ye;j++){
if(ck[i][j]!=0)continue;
if(e.contains(i, j))ck[i][j]=1;
}
}
}
Die oben erkannten HCHM-Spitzenpunkte (Position des stehenden Baums?) Sind wie folgt. 12392 Peakpunkte (stehende Baumposition?) Wurden im Bereich des Bildes (674 mx 600 m) erkannt.
Die Boronoi-Division wurde unter Verwendung von "Tinfour" mit dem HCHM-Peakpunkt als Position des Baums durchgeführt.
public List<ThiessenPolygon> process(){
BoundedVoronoiBuildOptions options = new BoundedVoronoiBuildOptions();
options.enableAutomaticColorAssignment(true);
BoundedVoronoiDiagram diagram = new BoundedVoronoiDiagram(vertList, options);
List<ThiessenPolygon> polyList=diagram.getPolygons();
return polyList;
}
Die folgenden Ergebnisse der Boronoi-Division werden angezeigt. Bei Vergrößerung scheinen die Schatten und Spitzen / Bereiche des Baldachins, die auf dem Foto zu sehen sind, grob geteilt zu sein.
Um zu bestätigen, ob der Peak richtig erkannt wird, habe ich die als Baldachin geschätzten DCHM-Pixelinformationen mit Jyz3d visualisiert. Ich habe einige Stellen überprüft, aber der Peak wurde in der in der folgenden Abbildung gezeigten Form festgestellt.
Ich habe versucht, die Baumhöhe usw. mit Java aus den Daten der Cloud-DB der Präfektur Shizuoka zu analysieren, aber irgendwie konnte ich das so erkennen. Da es keine Verifizierungsdaten gibt, liegt es im Spielbereich, aber es ist schwierig für Laubbäume usw., aber ich hatte das Gefühl, dass es möglich war, die Anzahl der Bäume und des Baldachins zu erkennen, wie dies beim Pflanzen von Zedern usw. der Fall ist. In "Erstellung von Baumhöhendaten unter Verwendung von Luftlaser-Vermessungsdaten" sind "Baumhöhendaten durch Luftlaser-Vermessung die Punktgruppendichte. Mit Ausnahme der Daten von immergrünen Nadelwäldern mit hohen Werten stimmen diese im Allgemeinen nicht mit den gemessenen Werten einzelner Bäume überein. "Wenn Sie jedoch den Durchschnittswert im Bereich von etwa 30 Quadratmetern nehmen, ist die Korrelation besser. ] Wird angegeben.
Wenn die Ergebnisse von Umfragen und Umfragen allgemeiner verfügbar gemacht werden, z. B. Shizuoka Prefecture Point Cloud DB, ist dies für verschiedene Zwecke nützlich.
Recommended Posts