Verwenden Sie die PROJ.4-Bibliothek, um mithilfe von Bodenkontrollpunkten von lokalen Koordinatensystemkoordinaten in ein globales Koordinatensystem zu transformieren?

9

Ich habe eine Punktwolke, deren Koordinaten sich auf ein lokales Koordinatensystem beziehen. Ich habe auch Bodenkontrollpunkte mit GPS-Werten. Kann ich diese lokalen Koordinaten mit PROJ.4 oder einer anderen Bibliothek in ein globales Koordinatensystem konvertieren?

Jeder Code in Python für das oben genannte Problem wäre eine große Hilfe.

user18953
quelle
Code erwartet?
Huckfinn
GPS-Koordinaten sind normalerweise WGS84, daher sind sie wahrscheinlich bereits global. Befinden sich die Bodenkontrollpunkte in einer lokalen Projektion mit einem anderen Datum als dem GPS (z. B. NAD83), muss das Datum konvertiert werden. PROJ4 unterstützt meines Wissens Datumsverschiebungen.
Oyvind
Hier ist eine ähnliche Frage, aber mit viel mehr Details: gis.stackexchange.com/questions/357910 .
trusktr

Antworten:

7

Sie scheinen eine affine Transformation zwischen Ihrem lokalen Koordinatensystem und einem georeferenzierten Koordinatensystem durchzuführen .

Affine Transformationen liegen allen Koordinatensystemen zugrunde und können durch die folgende Matrixgleichung dargestellt werden.

|x_1 y_1 1| |a d|   |x'_1 y'_1|
|x_2 y_2 1| |b e| = |x'_2 y'_2|
|x_3 y_3 1| |c f|   |x'_3 y'_3|
input     transform.  output
coords    matrix      coords
(n x 3)   (3 x 2)     (n x 2)

Sie haben jedoch ein zweistufiges Problem.

  1. Finden Sie die Transformationsmatrix aus bekannten Paarungen von Eingabe- und Ausgabekoordinaten (Ihre GPS-Punkte und ihre jeweiligen Positionen in Ihrem lokal definierten Raster).
  2. Verwenden Sie diese Transformationsmatrix, um Ihre Punktwolke zu georeferenzieren.

Proj.4 zeichnet sich durch # 2 aus: Übertragung zwischen georeferenzierten Koordinatensystemen mit bekannten Transformationsmatrizen. Es kann meines Wissens nicht verwendet werden, um eine Transformationsmatrix aus Punktdaten zu finden. Sie können das Ganze jedoch problemlos ausführen, indem Sie in Numpy eine leichte lineare Algebra (eine Matrixinversion der kleinsten Quadrate) verwenden. Ich habe eine Version dieser Klasse verwendet, um Daten aus mehreren Feldstudien zu reduzieren:

import numpy as N 

def augment(a):
    """Add a final column of ones to input data"""
    arr = N.ones((a.shape[0],a.shape[1]+1))
    arr[:,:-1] = a
    return arr

class Affine(object):
    def __init__(self, array=None):
        self.trans_matrix = array

    def transform(self, points):
        """Transform locally projected data using transformation matrix"""
        return N.dot(augment(N.array(points)), self.trans_matrix)

    @classmethod
    def from_tiepoints(cls, fromCoords, toCoords):
        "Produce affine transform by ingesting local and georeferenced coordinates for tie points"""
        fromCoords = augment(N.array(fromCoords))
        toCoords = N.array(toCoords)
        trans_matrix, residuals, rank, sv = N.linalg.lstsq(fromCoords, toCoords)

        affine =  cls(trans_matrix) # Setup affine transform from transformation matrix
        sol = N.dot(fromCoords,affine.trans_matrix) # Compute model solution
        print "Pixel errors:"
        print (toCoords - sol)
        return affine

Es kann als solches verwendet werden:

transform = Affine.from_tiepoints(gps_points_local,gps_points_geo)
projected_data = transform.transform(local_point_cloud)

projected_coordinatesbefindet sich jetzt in WGS84, UTM oder einem anderen Koordinatensystem, das Sie von Ihrem GPS aufgezeichnet haben. Ein Hauptmerkmal dieser Methode ist, dass sie mit einer beliebigen Anzahl von Verbindungspunkten (3 oder mehr) verwendet werden kann und mit zunehmender Anzahl von Verbindungspunkten an Genauigkeit gewinnt. Sie finden im Wesentlichen die beste Passform für alle Ihre Verbindungspunkte.

Daven Quinn
quelle
Hallo! Sie erwähnen, dass Proj (Proj4) den benutzerdefinierten Transformationsteil nicht verarbeiten kann? Bedeutet das, dass es technisch keine reine Proj-Antwort auf die Frage unter gis.stackexchange.com/questions/357910 gibt ?
trusktr
0

Ich war vor ein paar Wochen in demselben Problem gefangen und habe ein Python-Skript gefunden, das helfen kann. Ursprüngliche Lösung von hier

import pyproj
import math
import numpy as np
from statistics import mean
import scipy.optimize as optimize

#This function converts the numbers into text
def text_2_CRS(params):
    # print(params)  # <-- you'll see that params is a NumPy array
    x_0, y_0, gamma, alpha, lat_0, lonc = params # <-- for readability you may wish to assign names to the component variables
    pm = '+proj=omerc +lat_0='+ str(lat_0) +' +lonc='+ str(lonc) +' +alpha=' + str(alpha) + ' +gamma=' + str(
        gamma) + ' +k=0.999585495 +x_0=' + str(x_0) + ' +y_0=' + str(y_0) + ' +ellps=GRS80 +units=m +no_defs'
    return pm

#Optimisation function
def convert(params):
    pm = text_2_CRS(params)
    trans_points = []
    #Put your control points in mine grid coordinates here
    points_local = [[5663.648, 7386.58],
                    [20265.326, 493.126],
                    [1000, -10000],
                    [-1000, -10000],
                    [1331.817, 2390.206],
                    [5794, -1033.6],
                    ]
    # Put your control points here mga here
    points_mga = [[567416.145863305, 7434410.3451835],
                  [579090.883705669, 7423265.25196681],
                  [557507.390559793, 7419390.6658927],
                  [555610.407664593, 7420021.64968145],
                  [561731.125709093, 7431037.98474379],
                  [564883.285081307, 7426382.75146683],
                  ]
    for i in range(len(points_local)):
        #note that EPSG:28350 is MGA94 Zone 50
        trans = pyproj.transform(pyproj.Proj(pm), pyproj.Proj("EPSG:28350"), points_local[i][0], points_local[i][1])
        trans_points.append(trans)
    error = []
    #this finds the difference between the control points
    for i in range(len(points_mga)):
        x1 = trans_points[i][0]
        y1 = trans_points[i][1]
        x2 = points_mga[i][0]
        y2 = points_mga[i][1]
        error.append(math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2))

    print("Current Params are: ")
    with np.printoptions(precision=3, suppress=True):
        print(params)
    print("Current average error is: " + str(mean(error)) + " meters")
    print("String to use is: " + pm)
    print('')

    return mean(error)


#Add your inital guess
x_0 = 950
y_0 = -1200
gamma = -18.39841101
alpha=-0
lat_0 = -23.2583926082939
lonc = 117.589084840039


#define your control points
points_local = [[5663.648,7386.58],
          [20265.326,493.126],
          [1000,-10000],
          [-1000,-10000],
          [1331.817,2390.206],
          [5794,-1033.6],
          ]

points_mga = [[567416.145863305,7434410.3451835],
          [579090.883705669,7423265.25196681],
          [557507.390559793,7419390.6658927],
          [555610.407664593,7420021.64968145],
          [561731.125709093,7431037.98474379],
          [564883.285081307,7426382.75146683],
          ]


params = [x_0, y_0, gamma,alpha, lat_0, lonc]

error = convert(params)

print(error)

result = optimize.minimize(convert, params, method='Powell')
if result.success:
    fitted_params = result.x
    print(fitted_params)
else:
    raise ValueError(result.message)
Garth Cooper
quelle