Usando a biblioteca PROJ.4 para transformar de coordenadas locais do sistema de coordenadas em global, usando pontos de controle de solo?

9

Eu tenho uma nuvem de pontos cujas coordenadas estão em relação a um sistema de coordenadas local. Eu também tenho pontos de controle de solo com valores de GPS. Posso converter essas coordenadas locais em um sistema de coordenadas global usando o PROJ.4 ou qualquer outra biblioteca?

Qualquer código em Python para o problema mencionado acima seria uma grande ajuda.

user18953
fonte
Algum código esperado?
217142 Huckfinn
As coordenadas de GPS são normalmente WGS84, portanto, provavelmente já são globais. Se os pontos de controle de solo estiverem em uma projeção local, com um dado diferente do GPS (por exemplo, NAD83), o dado deve ser convertido. O PROJ4 suporta mudanças de dados até onde eu sei.
Oyvind
Aqui está uma pergunta semelhante, mas com muito mais detalhes: gis.stackexchange.com/questions/357910 .
trusktr

Respostas:

7

Você parece estar tentando conduzir uma transformação afiada entre o sistema de coordenadas local e um sistema de coordenadas georreferenciadas.

Afim transforma todos os sistemas de coordenadas de forma subjacente e pode ser representado pela equação da matriz abaixo.

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

No entanto, você tem um problema de duas etapas.

  1. Encontre a matriz de transformação a partir de pares conhecidos de coordenadas de entrada e saída (seus pontos de GPS e seus respectivos locais na grade definida localmente).
  2. Use essa matriz de transformação para georreferenciar sua nuvem de pontos.

O Projeto 4 destaca-se em # 2: transferência entre sistemas de coordenadas georreferenciadas com matrizes de transformação conhecidas. No meu conhecimento, não é possível encontrar uma matriz de transformação a partir de dados pontuais. No entanto, você pode fazer a coisa toda facilmente usando alguma álgebra linear leve (uma inversão de matriz dos mínimos quadrados) em Numpy. Eu usei uma versão desta classe para reduzir dados de vários estudos 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

Pode ser usado como tal:

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

projected_coordinatesagora está no WGS84, UTM ou em qualquer sistema de coordenadas gravado pelo seu GPS. Uma característica importante desse método é que ele pode ser usado com qualquer número de pontos de empate (3 ou mais) e, com precisão, quanto mais pontos de empate forem usados. Você está essencialmente encontrando o melhor ajuste em todos os seus pontos de empate.

Daven Quinn
fonte
Olá! Você mencionou que o Proj (Proj4) não pode lidar com a peça de transformação personalizada? Isso significa que tecnicamente não há uma resposta pura do Proj para a pergunta em gis.stackexchange.com/questions/357910 ?
trusktr
0

Eu estava preso no mesmo problema há algumas semanas, descobri um script python que pode ajudar. Solução original daqui

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
fonte