博主准研究僧一枚,假期在老师指导下接触项目。

本博文可作为坐标转换,特别是布尔莎七参数法的学习资料。其python源码注释充分,也可作为python的学习项目。
程序UI界面如下,由于是自用程序,博主对美化UI不感兴趣,ui部分源码注释充分,颜控可自行修改调整。

PS:克总信徒可以私信博主,富坦!

目前的大地测量实践中,由于GSC2000坐标系的推广,需要做大量将54坐标与80坐标转换为2000坐标的工作。实际工作中,一般通过mapgis实现坐标转换。但是,在某些涉密部门,仍然需要编制自用的程序进行坐标转换。

博主查阅资料,发现这方面资料要么比较老,时效性差,要么泛泛而谈,特别是介绍转换的详细算法的很少。所以,博主写下这篇短文,简要介绍下布尔莎模型及最小二乘思想在参数反解中的应用。同时博主注意到尚无利用python实现布尔莎七参数转换的博主,亦将展示源码,源码注释充分,以供交流学习。
坐标转换中用到的正是布尔莎-沃尔夫(Bursa-Wolf)模型,一般用七参数法进行坐标转换。涉及到的七个参数为:三个位移参数,三个旋转参数,一个尺度参数。不知为何写不了公式,放图:
可转换为:
七参数的矩阵形式即为:
上面三个是位移参数,然后是三个旋转参数,最后k为尺度参数即缩放因子。
我们定义伪观测数据V:

在大多数情况下我们是不知道七个参数的具体值的,所以一般通过最小二乘法拟合反解出七个参数。按照最小二乘原理,实际数据即是伪观测数据与线性公式得到的数据之间误差的平方和最小时的参数。一般需要至少三个公共点的坐标值反解七参数。以三个公共点为例,定义:
使Q最小:
附上python代码如下:
Java留下的习惯,简单的主程序代码:
main.py
from ui import Application
from transform import Coordinateapp=Application()
app.master.title("基于布尔莎模型的坐标转换工具")#窗口标题#编程过程中间检测性质的代码段
# test=Coordinate([1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3])
# print(test.V)
# print(test.K)
# print(test.K.shape)#主消息循环
app.mainloop()
其实写一个函数模块逻辑上更清晰,但出于学习的作用,写了一个坐标系类,带有可以自己转换自己的方法(大雾.......)

numpy真的是个很好用的模块!从某种程度上numpy已经取代了matlab在我干活中的作用。

transform.py
#用python利用最小二乘原理计算矩阵,就得引入numpy模块
from numpy import *class Coordinate():"""坐标Coordinate类"""def __init__(self,X1,Y1,Z1,X2,Y2,Z2,sign,n):"""规定一些坐标类的属性"""if sign==False:V1=mat([[X1[0]-X2[0]],[Y1[0]-Y2[0]],[Z1[0]-Z2[0]]])V2=mat([[X1[1]-X2[1]],[Y1[1]-Y2[1]],[Z1[1]-Z2[1]]])V3=mat([[X1[2]-X2[2]],[Y1[2]-Y2[2]],[Z1[2]-Z2[2]]])#创建伪观测值矩阵Vself.V=vstack((V1,V2,V3))#按列合并#hstack按行合并#创建K'''矩阵K1=mat([[1,0,0,0,-Z1[0],Y1[0],X1[0]],[0,1,0,Z1[0],0,-X1[0],Y1[0]],[0,0,1,-Y1[0],X1[0],0,Z1[0]]])K2=mat([[1,0,0,0,-Z1[1],Y1[1],X1[1]],[0,1,0,Z1[1],0,-X1[1],Y1[1]],[0,0,1,-Y1[1],X1[1],0,Z1[1]]])K3=mat([[1,0,0,0,-Z1[2],Y1[2],X1[2]],[0,1,0,Z1[2],0,-X1[2],Y1[2]],[0,0,1,-Y1[2],X1[2],0,Z1[2]]])self.K=vstack((K1,K2,K3))#可以用shape方法(e.shape)查看矩阵维数,以确定代码正确#根据输入的公共点进行最小二乘反解else:k=1self.V=mat([[X1[0]-X2[0]],[Y1[0]-Y2[0]],[Z1[0]-Z2[0]]])while k<n:V1=mat([[X1[k]-X2[k]],[Y1[k]-Y2[k]],[Z1[k]-Z2[k]]])self.V=vstack((self.V,V1))k+=1k=1self.K=mat([[1,0,0,0,-Z1[0],Y1[0],X1[0]],[0,1,0,Z1[0],0,-X1[0],Y1[0]],[0,0,1,-Y1[0],X1[0],0,Z1[0]]])while k<n:K1 = mat([[1, 0, 0, 0, -Z1[k], Y1[k], X1[k]], [0, 1, 0, Z1[k], 0, -X1[k], Y1[k]],[0, 0, 1, -Y1[k], X1[k], 0, Z1[k]]])self.K=vstack((self.K,K1))k+=1self.X=((self.K.T*self.K).I)*(self.K.T)*self.V#X矩阵即是布尔莎模型根据最小二乘原理得到的转换参数矩阵#X矩阵的排列方式是三个位移参数三个旋转参数和最后一个缩放系数def transform(self,x,y,z):""""类自带的方法"""Xa=mat([x,y,z])Xa=Xa.TK=mat([[1,0,0,0,-z,y,x],[0,1,0,z,0,-x,y],[0,0,1,-y,x,0,z]])#Xb作为类的一个属性,调用transform方法,得到该属性self.Xb=Xa+K*self.X
最后是程序的主干,包含ui部分,主要采用tkinter模块,excel的读写上采用xlrd/xlwt等模块,可做新手学习的实例:
ui.py
from transform import Coordinate
#导入tkinter模块
from tkinter import *
import tkinter.messagebox as messagebox
import tkinter.filedialog
#sys模块对程序进行基本控制
import sys
#excel读写两个模块
import xlrd
import xlwtclass Application(Frame):#创建一个容器,为所有Widget的父容器,继承Frame类def __init__(self,master=None):#master是窗口管理器,用于管理窗口部件,比如按钮标签等等等,master为None即是自己管理自己,为顶级窗口"""创建主窗口也是父容器"""Frame.__init__(self,master)self.pack()#这里图省事,主窗口采用pack布局,其实个人觉得grid布局更实用self.creatWidgets()def creatWidgets(self):"""主程序"""#程序标签语,采用grid布局,覆盖两列self.firstLabel=Label(self,text='基于布尔莎模型的坐标转换程序'+'\n'+'请先输入三个公共点的坐标或选择公共点excel表进行拟合')self.firstLabel.grid(row=0,columnspan=10)#模式转换按钮用checkbutton控件来写,学习下checkbutton的用法self.b=tkinter.BooleanVar()#self.b是该类的扩展的重要属性,用以选择是还按之前的程序目标通过手动输入三个公共点坐标来拟合,还是通过读取公共点的excel表,读取n个公共点#同时扩展属性self.n作为一个可变变量,即公共点个数self.n=tkinter.IntVar()self.modelButton=Checkbutton(self,variable=self.b,text='excel输入公共点')self.modelButton.grid(row=7,column=8)#输入框行注释self.rowoneLabel=Label(self,text='转换前的公共测量点坐标')self.rowoneLabel.grid(row=1,column=1,columnspan=3)self.rowtwoLabel=Label(self,text='转换后的公共测量点坐标')self.rowtwoLabel.grid(row=1,column=6,columnspan=3)#输入框列注释self.coloneLabel=Label(self,text='X:    ')self.coloneLabel.grid(row=2,column=0)self.coltwoLabel=Label(self,text='Y:    ')self.coltwoLabel.grid(row=3,column=0)self.colthreeLabel=Label(self,text='Z:    ')self.colthreeLabel.grid(row=4,column=0)#创建旧坐标输入框self.e11=Entry(self,width=15)#Xaself.e11.grid(row=2,column=1)self.e21=Entry(self,width=15)#Yaself.e21.grid(row=3,column=1)self.e31=Entry(self,width=15)#Zaself.e31.grid(row=4,column=1)self.e12=Entry(self,width=15)#Xaself.e12.grid(row=2,column=2)self.e22=Entry(self,width=15)#Yaself.e22.grid(row=3,column=2)self.e32=Entry(self,width=15)#Zaself.e32.grid(row=4,column=2)self.e13 = Entry(self,width=15)  # Xaself.e13.grid(row=2, column=3)self.e23 = Entry(self,width=15)  # Yaself.e23.grid(row=3, column=3)self.e33 = Entry(self,width=15)  # Zaself.e33.grid(row=4, column=3)#创建新坐标输入框self.n11=Entry(self,width=15)#Xaself.n11.grid(row=2,column=6)self.n21=Entry(self,width=15)#Yaself.n21.grid(row=3,column=6)self.n31=Entry(self,width=15)#Zaself.n31.grid(row=4,column=6)self.n12=Entry(self,width=15)#Xaself.n12.grid(row=2,column=7)self.n22=Entry(self,width=15)#Yaself.n22.grid(row=3,column=7)self.n32=Entry(self,width=15)#Zaself.n32.grid(row=4,column=7)self.n13 = Entry(self,width=15)  # Xaself.n13.grid(row=2, column=8)self.n23 = Entry(self,width=15)  # Yaself.n23.grid(row=3, column=8)self.n33 = Entry(self,width=15)  # Zaself.n33.grid(row=4, column=8)#创建一块空白部分作为分割self.middleLabel=Label(self,text='  ',width=15)self.middleLabel.grid(row=2,column=4,columnspan=2,rowspan=3)#给显示窗口添加标签self.delayLabel=Label(self,text='布尔莎模型七参数矩阵拟合结果[Tx,Ty,Tz,wx,wy,wz,k]')self.delayLabel.grid(row=5,columnspan=10)#创建显示窗口,显示七参数的拟合结果self.Xresult=StringVar()#利用StrtingVat储存值self.delay1=Entry(self,width=120,state='readonly',text=self.Xresult)self.delay1.grid(row=6,columnspan=10)#创建拟合按钮self.XButton=Button(self,text='拟合',command=self.first_step,width=15)self.XButton.grid(row=7,column=5)#创建三个路径显示的StringVarself.file_name_read=StringVar()self.file_name_write=StringVar()self.public_point=StringVar()#创建四个按钮self.openButton=Button(self,text='打开',width=15,command=self.read_location)self.openButton.grid(row=8,column=0)self.writeButton=Button(self,text='路径',width=15,command=self.write_location)self.writeButton.grid(row=9,column=0)self.openButton1=Button(self,text='打开公共点excel表',width=15,command=self.read_public_point)self.openButton1.grid(row=10,column=0)self.creatButton=Button(self,text='输出',command=self.write_excel,width=15)self.creatButton.grid(row=11,column=5)#路径窗口self.delay2=Entry(self,width=100,state='readonly',text=self.file_name_read)self.delay2.grid(row=8,column=1,columnspan=8)self.delay3=Entry(self,width=100,state='readonly',text=self.file_name_write)self.delay3.grid(row=9,column=1,columnspan=8)self.delay4=Entry(self,width=100,state='readonly',text=self.public_point)self.delay4.grid(row=10,column=1,columnspan=8)#作者介绍self.writerLabel=Label(self,text='制作人——田睿,密斯卡托尼克大学助教,阿卡姆镇巡更人,印斯茅斯荣誉市民,拉莱耶城的监视者'+'\n'+'欢迎克苏鲁神话爱好者私信骚扰')self.writerLabel.grid(row=12,columnspan=10,rowspan=2)def first_step(self):"""该函数主要进行第一步的七参数拟合工作"""#为Coordinate类创建输入矩阵量#由于经常会发生输入异常,这里写了一个异常处理代码if self.b.get()==False:# 由于经常会发生输入异常,这里写了一个异常处理代码try:X1=[float(self.e11.get()),float(self.e12.get()),float(self.e13.get())]Y1=[float(self.e21.get()),float(self.e22.get()),float(self.e23.get())]Z1=[float(self.e31.get()),float(self.e32.get()),float(self.e33.get())]X2=[float(self.n11.get()),float(self.n12.get()),float(self.n13.get())]Y2=[float(self.n21.get()),float(self.n22.get()),float(self.n23.get())]Z2=[float(self.n31.get()),float(self.n32.get()),float(self.n33.get())]#得到转换参数结果矩阵,用Xresult接收(已经定义为StringVar)#cd 作为Application类的一个属性,接收Coordinate类的实例,这样写是方便后边的方法调用#这样写不会存在风险,因为正常使用程序,必须先调用first_step方法self.cd=Coordinate(X1,Y1,Z1,X2,Y2,Z2,self.b.get(),self.n.get())X1=str(self.cd.X)#得到矩阵的字符串形式,但需要进行加工#对字符串进行加工X1=X1[2:-3]X1=X1.replace(']',',')X1=X1.replace('[', '')X2='['+X1+']'self.Xresult.set(X2)except ValueError:messagebox.showinfo('错误','如果要使用输入的三个公共点进行拟合的话,请将三个公共测量点的坐标输全,再拟合反解参数!')else:messagebox.showinfo('提示','拟合完毕,可以进行下一步工作')else:#!!!!!!!!!!!!!!!!!!#这里强调一个错误,之前这样写的:read_public_excel(),出错NameError: name 'read_public_excel' is not defined#在非结构方法中(java的叫法)引用必须用self.  记得java是this???好久不用Java忘了self.read_public_excel()def read_public_point(self):file_name=tkinter.filedialog.askopenfilename()self.public_point.set(file_name)def read_location(self):file_name=tkinter.filedialog.askopenfilename()self.file_name_read.set(file_name)def write_location(self):file_name=tkinter.filedialog.askopenfilename()self.file_name_write.set(file_name[:-1])def read_public_excel(self):"""读取公共点excel表"""file_name=self.public_point.get()data=xlrd.open_workbook(file_name)table=data.sheets()[0]self.n.set(table.nrows)#n为行数,即公共点个数n1=self.n.get()if n1<3:messagebox.showinfo('错误', '拟合需要至少三个以上公共点的数据')k=0#定义输入的列表X1=[]Y1=[]Z1=[]X2=[]Y2=[]Z2=[]while k<n1:X1.append(float(table.cell_value(k,0)))Y1.append(float(table.cell_value(k, 1)))Z1.append(float(table.cell_value(k, 2)))X2.append(float(table.cell_value(k,3)))Y2.append(float(table.cell_value(k, 4)))Z2.append(float(table.cell_value(k, 5)))k+=1cd=Coordinate(X1,Y1,Z1,X2,Y2,Z2,True,n1)X1 = str(cd.X)  # 得到矩阵的字符串形式,但需要进行加工# 对字符串进行加工X1 = X1[2:-3]X1 = X1.replace(']', ',')X1 = X1.replace('[', '')X2 = '[' + X1 + ']'self.Xresult.set(X2)def read_excel(self):"""读取excel表函数"""file_name=self.file_name_read.get() #想获取stringvar中的内容为字符串,用get方法,用set存储#读取excel# data=xlrd.open_workbook('E:/workspace/BJ54transform_project/Data/test.xlsx')data=xlrd.open_workbook(file_name)table=data.sheets()[0]#获取其中一个工作表i=table.nrows#i为行数k=0#计数变量#采用一个字典储存值datas={'x':0,'y':0,'z':0}saves=[]#存储字典单元的列表while k<i:datas['x']=table.cell(k,0).valuedatas['y']=table.cell(k,1).valuedatas['z']=table.cell(k,2).value# #重大误区!!!!!# 原来的代码是这样的saves.append(datas)# 最后是列表所有元素都一样,因为引用一样# 所以最后用copy方法添加一个复制,每次循环复制的都不一眼# 重要# 重要# 重要# 技巧记住!!!!!# !!!!# !!!!saves.append(datas.copy())k+=1return savesdef write_excel(self):"""写excel表,写为xls格式"""new_data=xlwt.Workbook()sheet1=new_data.add_sheet('结果',cell_overwrite_ok=True)saves=self.read_excel()sheet1.write(0,0,'x')sheet1.write(0, 1, 'y')sheet1.write(0, 2, 'z')i=1for cell in saves:xd=cell['x']yd=cell['y']zd=cell['z']self.cd.transform(xd,yd,zd)Xr=self.cd.Xbprint(Xr)sheet1.write(i,0,Xr[0,0])sheet1.write(i,1,Xr[1,0])sheet1.write(i,2,Xr[2,0])i+=1file_name=self.file_name_write.get()#存储在指定路径print(file_name)# new_data.save('E:/workspace/BJ54transform_project/Data/test.xls')new_data.save(file_name)#存储在指定路径
注释比较详细,各位直接看注释就好。
各位小伙伴,永恒的宅邸拉莱耶中,克苏鲁候汝入梦!

python应用实例:坐标转换——基于布尔莎模型,可实现BJ54坐标系/GSC2000坐标系/WGS84等各种地心直角坐标系的转换相关推荐

  1. 基于布尔莎模型的7参数计算及坐标转换

    前言 坐标转换的意义在前一篇<基于二维四参数模型的坐标转换>一文中已经提到,这里就不赘言.这篇文章我将主要介绍基于布尔莎模型的7参数计算流程及转换方法.为了验证数据转换的正确性,先将该工具 ...

  2. C++实现七参数转换法(布尔莎模型)

    七参数转换法(布尔莎模型) 七参数法(包括布尔莎模型,一步法模型,海尔曼特等)是解决此问题的比较严密和通用的方法.一般含有7个转换参数:X平移,Y平移,Z平移,X旋转,Y旋转,Z旋转,尺度变化m.通过 ...

  3. python数据分析实例:客户流失预警模型

    python数据分析实例:客户流失预警模型 客户流失是电信行业最重要的服务方面之一.客户流失的广义说法是因为客户自己或运营商违反服务协议而终止客户服务的行为. 流失预测流程一共分为四个步骤,分别为(1 ...

  4. python cnn 实例_基于CNN的纹理合成实践【附python实现】

    Q0: Preliminary knowledge of Texture Synthesis Baseline请见此处,下文所有的代码修改均建立此代码基础之上. 1. 纹理合成简述 ​纹理合成(Tex ...

  5. lda主题模型python实现篇_基于LDA主题模型的短文本分类

    VSM(向量空间模型)是信息检索领域最为经典的分析模型之一,采用VSM对短文本进行建模,即将每一篇短文本表示为向量的形式,用TF-TDF表示向量的值.给出一些符号定义:短文本集SD= {sd1,sd2 ...

  6. 基于树的模型的机器学习

    This is a memo to share what I have learnt in Machine Learning with Tree-Based Models (using Python) ...

  7. 坐标转换--基准面转换(布尔莎七参数)

    坐标转换–基准面转换(布尔莎七参数) 在坐标转换中,除了正投影和反投影的转换,还有不同基准面之间的转换.基准面的转换有很多种转换模型,常见的有三参数和七参数转换.三参数的转换主要是通过对x,y,z三个 ...

  8. python基于轻量级CNN模型开发构建手写藏文数字识别系统

    最近做的很多工作都是跟手写性质的数据集有关的,比如:手写汉字.手写甲骨文.手写数字.手写字母等等,今天主要做的实践是对藏文中的手写数字进行识别分析,在我之前的博文中有很多相关的实践分析,感兴趣的话可以 ...

  9. python数据分析可视化实例_Python数据分析及可视化实例之基于Kmean分析RFM进行用户关怀...

    系列文章总目录:Python数据分析及可视化实例目录 数据集下载 Python数据分析及可视化实例之全国各城市房价分析(含数据采集) Python数据分析及可视化实例之帝都房价预测 Python数据分 ...

最新文章

  1. UART0串口编程(六):串口(UART0)之UC/OS(二)UC/OS下的串口接收任务编程
  2. Java传xml时字符串乱码_php调用java传递xml字符串乱码怎么办
  3. android复选按钮,Android的复选框的详细开发案例分析
  4. 文件查找_tar_ext34_swap
  5. 还债速度果然快,罗永浩限高令已再度解除
  6. PHP 生成csv的遇到的分隔符问题
  7. paip.提升性能---string split
  8. 【图像配准】基于matlab OpenSUFT图像配准【含Matlab源码 1232期】
  9. php动态网站程序设计课后答案,《PHP动态网站开发实例教程》课程标准
  10. overleaf 公式_Latex的公式输入
  11. Multi-Armed Bandits
  12. 关于vue-pdf插件ios端打包白屏(hbuilderx打包)
  13. Paddle进阶实战系列(二):智慧交通预测系统
  14. opencv C++图像/视频旋转 90度 180度 270度
  15. 永久删除计算机文件怎么操作步骤,两种可以直接彻底删除文件的操作方法-电脑自学网...
  16. Redis系列内容完整版
  17. CS188 Project 4: Inference in Bayes Nets(4-6)
  18. Android键盘的显示和隐藏
  19. 基于点云数据提取道路标线的思路
  20. 橙色金属 联想K900橙色开启预售

热门文章

  1. jsp的定义,创建和使用
  2. 在Windows XP中制作屏保
  3. 短信CMPP通信协议
  4. Prim和Kruskal算法应用----城市水管连接
  5. 指针式仪表自动读数与识别(五):刻度线定位与拟合
  6. 【动画消消乐】HTML+CSS 自定义加载动画 068
  7. 支付宝API接入,网页支付接口。
  8. 同惠TH2810DLCR测试仪电感的测量方法
  9. eNSP配置ospf实例
  10. JavaCV学习(一)