¿Usa la biblioteca PROJ.4 para transformar las coordenadas del sistema de coordenadas local en un sistema de coordenadas global utilizando puntos de control de tierra?

9

Tengo una nube de puntos cuyas coordenadas son con respecto a un sistema de coordenadas local. También tengo puntos de control de tierra con valores de GPS. ¿Puedo convertir estas coordenadas locales en un sistema de coordenadas global usando PROJ.4 o cualquier otra biblioteca?

Cualquier código en Python para el problema mencionado anteriormente sería de gran ayuda.

usuario18953
fuente
¿Algún código esperado?
huckfinn
Las coordenadas GPS son normalmente WGS84, por lo que probablemente ya sean globales. Si los puntos de control de tierra están en una proyección local, con un dato diferente al del GPS (por ejemplo, NAD83), el dato debe convertirse. PROJ4 admite cambios de datos hasta donde yo sé.
Oyvind
Aquí hay una pregunta similar, pero con mucho más detalle: gis.stackexchange.com/questions/357910 .
trusktr

Respuestas:

7

Parece que está buscando realizar una transformación afín entre su sistema de coordenadas local y un sistema de coordenadas georreferenciado.

Affine transforma debajo de todos los sistemas de coordenadas y puede representarse mediante la ecuación matricial a continuación.

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

Sin embargo, tiene un problema de dos pasos.

  1. Encuentre la matriz de transformación a partir de pares conocidos de coordenadas de entrada y salida (sus puntos GPS y sus ubicaciones respectivas en su cuadrícula definida localmente).
  2. Use esta matriz de transformación para georreferenciar su nube de puntos.

El proyecto 4 sobresale en el n. ° 2: transferencia entre sistemas de coordenadas georreferenciadas con matrices de transformación conocidas. Que yo sepa, no se puede utilizar para encontrar una matriz de transformación a partir de datos de puntos. Sin embargo, puede hacer todo fácilmente usando un poco de álgebra lineal ligera (una inversión de matriz de mínimos cuadrados) en Numpy. He usado una versión de esta clase para reducir los datos de varios estudios de campo:

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

Se puede usar como tal:

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

projected_coordinatesahora está en WGS84, UTM o cualquier sistema de coordenadas que haya grabado con su GPS. Una característica importante de este método es que se puede usar con cualquier número de puntos de conexión (3 o más) y gana precisión a medida que se usan más puntos de conexión. Básicamente, estás encontrando el mejor ajuste a través de todos tus puntos de empate.

Daven Quinn
fuente
¡Hola! ¿Menciona que Proj (Proj4) no puede manejar la parte de transformación personalizada? ¿ Eso significa que técnicamente no hay una respuesta pura de Proj para la pregunta en gis.stackexchange.com/questions/357910 ?
trusktr
0

Estuve atrapado en el mismo problema hace unas semanas, descubrí un script de Python que puede ayudar. Solución original de aquí

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
fuente