1.四参数来历
1、平面坐标 - 平面坐标
在坐标转换的过程中,我们我们在小范围内,可以使用四参数就能达到坐标转换的目的,且精度也能达到预定的需求。,四参数计算公式如下
X1与Y1代表原平面坐标下的坐标, X2与Y2代表目标平面坐标下的坐标,二者转换需要四个参数,分别为x、y两个坐标的偏移,以及旋转角度和尺度因子等
2、四参数求解
四参数求解至少需要两个点对,分别知道其在目标投影坐标和原投影坐标下的坐标点对,我觉得**dibowei2069**写的求解过程就很详细,下面我将贴出其博客的链接,同时为了保持本文丰富性,将其内容进行拿来主义了:
PS:这里的P矩阵写法有问题,自己在计算的过程中发现了致命的问题,P矩阵应该是一个单位矩阵,其维度应为2count✖2count (count为数据点对的个数),因此在公式中,我们可以忽略相应的单位矩阵,得到的结果也不影响最终的答案。
PS: 想知道更加具体的信息,可以去他博客去了解下,链接为:https://blog.csdn.net/dibowei2069/article/details/106039613 再次表示感谢、感谢、感谢!!!!!
2、四参数求解
1、java写矩阵运算计算
一开始想着自己写矩阵运算,提高自己的码力,也写出来了,但是精度有点问题,我也不知道为啥,在计算的过程中,我都使用了BigDecimal去保留更多的精度,奈何就是精度不够,差距十多米,但是我坚信,自己写的没问题,下面我贴出自己的实现方式,希望大家多多提出意见,看看到底错在那里:同时在此我给出两组数组对,方便大家使用,在下面的代码中,需要的自取,最后,我还会给出一对方便大家验证:下面给出截图,同时为了方便复制,我也将其放在代码块里面
/*
**点 X1 Y1 X2 Y2
P1 4312820.897 513670.931 4312816.917 513553.7194
P2 4314058.425 514231.984 4314054.44 514114.7771
P3 4306670.108 511168.332 4306666.154 511051.098**
*/
//利用两组坐标,求解四参数
public static double [] solveFourParameters(){
Point3D original = new Point3D(4312820.897,513670.931,402.992);
Point3D origina2 = new Point3D(4314058.425,514231.984,432.447);
Point3D target1 = new Point3D(4312816.917,513553.719,416.183);
Point3D target2 = new Point3D(4314054.440,514114.777,445.596);
double [][] L = {{target1.getX()-original.getX()},
{target1.getY()-original.getY()},
{target2.getX()- origina2.getX()},
{target2.getY()-origina2.getY()}
};
PrintMatrix(L);
double [][] P = formUnitMatrix(4);
PrintMatrix(P);
double [][] B = {{1,0,original.getX(),-original.getY()},
{0,1,original.getY(),original.getX()},
{1,0,origina2.getX(),-origina2.getY()},
{0,1,origina2.getY(),origina2.getX()}};
PrintMatrix(B);
double [][] firstPart = matrixInv(matrixMultiply(matrixMultiply(matrixTransposition(B),P),B));
double [][] first = matrixMultiply(matrixTransposition(B),P);
PrintMatrix(first);
double [][] second = matrixMultiply(first,B);
PrintMatrix(second);
double [][] third = matrixInv(second);
PrintMatrix(third);
double [][] fourth = matrixMultiply(third,matrixTransposition(B));
PrintMatrix(fourth);
double [][] fifth = matrixMultiply(fourth,P);
PrintMatrix(fifth);
double [][] finalMatrix = matrixMultiply(fifth,L);
PrintMatrix(finalMatrix);
// double [][] finalMatrix = matrixMultiply(matrixMultiply(matrixMultiply(firstPart,matrixTransposition(B)),P),L);
double m = Math.sqrt(Math.pow(finalMatrix[2][0]+1,2)+ Math.pow(finalMatrix[3][0],2));
double angle = Math.atan(finalMatrix[3][0]/(finalMatrix[2][0]-1));
double [] fourParameter = {finalMatrix[0][0],finalMatrix[1][0],angle,m};
Log.e("anywhere", fourParameter[0]+ "\n"+ fourParameter[1]+"\n"+ fourParameter[2]+"\n"+fourParameter[3]);
//得到的四参数进行结算
double[] four_para = fourParameter;
Point3D point3D = new Point3D(4306670.108,511168.332,309.157);
BigDecimal oldx = BigDecimal.valueOf(point3D.getX());
BigDecimal oldy = BigDecimal.valueOf(point3D.getY());
BigDecimal cos = new BigDecimal(String.valueOf(Math.cos(four_para[2]))); //计算cos
BigDecimal sin = new BigDecimal(String.valueOf(Math.sin(four_para[2]))); //计算sin
BigDecimal part1= cos.multiply(oldx);
BigDecimal part2= oldy.multiply(sin);
BigDecimal part3= part1.subtract(part2);
BigDecimal part4= BigDecimal.valueOf(four_para[3]).multiply(part3);
BigDecimal x= BigDecimal.valueOf(four_para[0]).add(part4);
BigDecimal newX =x.setScale(6,BigDecimal.ROUND_HALF_DOWN);
BigDecimal y = BigDecimal.valueOf(four_para[1]).add(BigDecimal.valueOf(four_para[3]).multiply(oldx.multiply(sin).add(oldy.multiply(cos))));
BigDecimal newY = y.setScale(6,BigDecimal.ROUND_HALF_DOWN);
Log.e("anywhere","newx:"+ newX+"\n"+"newY:"+ newY);
return fourParameter;
}
private static void PrintMatrix(double [][] matrix) {
for(int i = 0 ; i< matrix.length;i++){
StringBuilder builder = new StringBuilder();
for(int j = 0; j<matrix[0].length;j++){
builder.append(matrix[i][j]).append(" + ");
}
Log.e("matrix",builder.toString()+"\n");
}
}
public static double[][] formUnitMatrix(int dimen) {
double [][]temp = new double[dimen][dimen];
for(int i = 0;i< dimen ;i++){
for(int j= 0;j< dimen;j++){
if(i==j)
temp[i][j]=1;
else
temp[i][j]=0;
}
}
return temp;
}
/*
利用java实现矩阵的乘法和转置以及求逆矩阵
*/
//转置,必须行列都一样
public static double [][] matrixTransposition( double [][] changedMatrix){
int colums = changedMatrix.length;
double targetMatrix [][] = new double[colums][colums];
for(int i = 0; i< colums ;i++){
for(int j = 0; j< colums; j++){
targetMatrix[i][j] = changedMatrix[j][i];
}
}
return targetMatrix;
}
//矩阵的乘法,前一个列数与后一个行数相同
public static double[][] matrixMultiply(double[][] previousMatrix , double [][] laterMatrix){
if(previousMatrix[0].length!= laterMatrix.length){
return null;
}
int lines = previousMatrix.length; //新的行数
int colums = laterMatrix[0].length; //列数
int commonLines = laterMatrix.length; //前一个的列数与后一个的行数
double[][] targetMatrix = new double[lines][colums];
for(int i = 0; i < lines ; i++){
for(int j = 0; j< colums ;j++){
BigDecimal sum = BigDecimal.valueOf(0.0);
for(int k = 0 ;k < commonLines ;k++){
sum = sum.add(BigDecimal.valueOf(previousMatrix[i][k]).multiply(BigDecimal.valueOf(laterMatrix[k][j])));
}
targetMatrix[i][j] = sum.doubleValue();
}
}
return targetMatrix;
}
//求矩阵的行列式,我们可以求解四次的
public static double matrixValues(double [][] solvMatrix){
if(solvMatrix.length!= solvMatrix[0].length)
return 0.;
if (solvMatrix.length==1)
return solvMatrix[0][0];
else if (solvMatrix.length==2)
return matrix2Det(solvMatrix);
else if (solvMatrix.length==3)
return matrix3Det(solvMatrix);
else { //可以求解四次的
double sum = 0.0;
for (int i = 0; i < 4; i++) {
sum += Math.pow(-1, i + 2) * solvMatrix[0][i] * matrix3Det(companionMatrix(solvMatrix, 0, i));
}
return sum;
}
}
// 根据位置,求得伴随矩阵
public static double [][] companionMatrix(double [][] matrix ,int line ,int column){
int lines = matrix.length;
int columns = matrix[0].length;
double [][] targetMarix = new double[lines-1][columns-1];
int dx=0;
for(int i=0;i < lines ;++i){
if(i!=line){
int dy=0;
for (int j=0;j < columns ;++j){
if (j!=column){
targetMarix[dx][dy++] = matrix[i][j];
}
}
++dx;
}
}
return targetMarix;
}
//求解三阶的行列式值
public static double matrix3Det(double[][] solvMatrix) {
if(solvMatrix.length!=solvMatrix[0].length){
return 0.;
}
double [][] A0 = companionMatrix(solvMatrix,0,0);
double [][] A1 = companionMatrix(solvMatrix,0,1);
double [][] A2 = companionMatrix(solvMatrix,0,2);
BigDecimal Part1 = BigDecimal.valueOf(solvMatrix[0][0]).multiply(BigDecimal.valueOf(matrix2Det(A0)));
BigDecimal Part2 = BigDecimal.valueOf(solvMatrix[0][1]).multiply(BigDecimal.valueOf(matrix2Det(A1)));
BigDecimal Part3 = BigDecimal.valueOf(solvMatrix[0][2]).multiply(BigDecimal.valueOf(matrix2Det(A2)));
BigDecimal part1_2 = Part1.subtract(Part2);
BigDecimal final_result = part1_2.add(Part3);
return final_result.doubleValue();
}
//求解2阶的行列式值
public static double matrix2Det(double[][] solvMatrix) {
BigDecimal first = BigDecimal.valueOf(solvMatrix[0][0]).multiply(BigDecimal.valueOf(solvMatrix[1][1]));
BigDecimal second = BigDecimal.valueOf(solvMatrix[0][1]).multiply(BigDecimal.valueOf(solvMatrix[1][0]));
return first.subtract(second).doubleValue();
}
//求逆矩阵
public static double[][] matrixInv(double[][] solveMatrix){
//行数与列数必须相等
if (solveMatrix.length!=solveMatrix[0].length)
return null;
int lines = solveMatrix.length;
int columns = solveMatrix[0].length;
double A = matrixValues(solveMatrix);
double[][] targetMatrix =new double[lines][columns];
for(int i=0;i < lines;++i){
for (int j=0;j< columns ;++j){
double[][] temp= companionMatrix(solveMatrix,i,j);
targetMatrix[j][i]=BigDecimal.valueOf(matrixValues(temp)).divide(BigDecimal.valueOf(A),40,BigDecimal.ROUND_DOWN).doubleValue() * Math.pow(-1,i+j);
}
}
return targetMatrix;
}
2、jar包闪亮上场
既然自己写的精度存在问题,那么我就想到了jar的方法,去看看大佬们如何写的,然后就网上搜索,看到了一篇关于***commons-math3***的介绍,在此对***HFUT_qianyang***表示感谢、感谢、感谢!!大家也可以去他的博客去看看jar包math3关于矩阵的基本使用,链接位:https://blog.csdn.net/qy20115549/article/details/54604264,同时,我也将自己下载好的math3 jar包上传,希望能帮助到大家。链接在此:https://mp.csdn.net/console/upDetailed
实现流程与上文自己写的类似,就是将矩阵运算替换位jar包中提供的方法,最后结果的截图位:
newX、newY分别为根据计算出的四参数求得的新的转换坐标,本身应该为 X2= 4306666.154 Y2 = 511051.098,误差分别只有3mm与4mm,对于厘米级要求的工程,远远超出其标准。
import java.math.BigDecimal;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.math3.linear.Array2DRowRealMatrix;
import org.apache.commons.math3.linear.LUDecomposition;
import org.apache.commons.math3.linear.RealMatrix;
public class Hero {
public static void main(String[] asgs){
//checkRegerx();
calculateFourParameters();
}
private static void calculateFourParameters() {
Point3D original = new Point3D(4312820.897,513670.931,402.992);
Point3D origina2 = new Point3D(4314058.425,514231.984,432.447);
Point3D target1 = new Point3D(4312816.917,513553.719,416.183);
Point3D target2 = new Point3D(4314054.440,514114.777,445.596);
double [][] L1 = {{target1.getX()-original.getX()},
{target1.getY()-original.getY()},
{target2.getX()- origina2.getX()},
{target2.getY()-origina2.getY()}
};
double [][] P1 = formUnitMatrix(4);
double [][] B1 = {{1,0,original.getX(),-original.getY()},
{0,1,original.getY(),original.getX()},
{1,0,origina2.getX(),-origina2.getY()},
{0,1,origina2.getY(),origina2.getX()}};
//转为我们需要的数组
RealMatrix L = new Array2DRowRealMatrix(L1);
RealMatrix P = new Array2DRowRealMatrix(P1);
RealMatrix B = new Array2DRowRealMatrix(B1);
RealMatrix first = P.multiply(B.transpose()); //Bt*P
PrintMatrix(first,"BT*P");
RealMatrix second = first.multiply(B);
PrintMatrix(second,"BT*P*B");
RealMatrix third = inverseMatrix(second);
PrintMatrix(third,"(BT*B*P)-");
RealMatrix fourth = third.multiply(B.transpose());
PrintMatrix(fourth,"(BT*B*P)-*BT");
RealMatrix fifth = fourth.multiply(P);
PrintMatrix(fifth,"(BT*B*P)-BT*P");
RealMatrix sixth = fifth.multiply(L);
PrintMatrix(sixth,"(BT*B*P)-BT*P*L");
double [][] finalMatrix = sixth.getData();
double m = Math.sqrt(Math.pow(finalMatrix[2][0]+1,2)+ Math.pow(finalMatrix[3][0],2));
double angle = Math.atan(finalMatrix[3][0]/(finalMatrix[2][0]-1));
double [] fourParameter = {finalMatrix[0][0],finalMatrix[1][0],Math.abs(angle),m};
System.out.print("final: "+ fourParameter[0]+ "\n"+ fourParameter[1]+"\n"+ fourParameter[2]+"\n"+fourParameter[3]);
double[] four_para = fourParameter;
Point3D point3D = new Point3D(4306670.108,511168.332,309.157);
BigDecimal oldx = BigDecimal.valueOf(point3D.getX());
BigDecimal oldy = BigDecimal.valueOf(point3D.getY());
BigDecimal cos = new BigDecimal(String.valueOf(Math.cos(four_para[2]))); //计算cos
BigDecimal sin = new BigDecimal(String.valueOf(Math.sin(four_para[2]))); //计算sin
BigDecimal part1= cos.multiply(oldx);
BigDecimal part2= oldy.multiply(sin);
BigDecimal part3= part1.subtract(part2);
BigDecimal part4= BigDecimal.valueOf(four_para[3]).multiply(part3);
BigDecimal x= BigDecimal.valueOf(four_para[0]).add(part4);
BigDecimal newX =x.setScale(6,BigDecimal.ROUND_HALF_DOWN);
BigDecimal y = BigDecimal.valueOf(four_para[1]).add(BigDecimal.valueOf(four_para[3]).multiply(oldx.multiply(sin).add(oldy.multiply(cos))));
BigDecimal newY = y.setScale(6,BigDecimal.ROUND_HALF_DOWN);
System.out.print("newX:"+ newX+"\n"+"newY:"+ newY);
}
/*
求逆函数
*/
//求逆函数
public static RealMatrix inverseMatrix(RealMatrix A) {
RealMatrix result = new LUDecomposition(A).getSolver().getInverse();
return result;
}
/*
打印信息
*/
private static void PrintMatrix(RealMatrix first,String part) {
double [][] matrix = first.getData();
for(int i = 0 ; i< matrix.length;i++){
StringBuilder builder = new StringBuilder();
for(int j = 0; j<matrix[0].length;j++){
builder.append(matrix[i][j]).append(" + ");
}
System.out.print(part + builder.toString()+"\n");
}
}
/*
单位矩阵
*/
private static double[][] formUnitMatrix(int dimen) {
double [][]temp = new double[dimen][dimen];
for(int i = 0;i< dimen ;i++){
for(int j= 0;j< dimen;j++){
if(i==j)
temp[i][j]=1;
else
temp[i][j]=0;
}
}
return temp;
}
private static void checkRegerx() {
String test = "dz_2dc78";
String regex = "(\\d+)"; //匹配数字
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(test);
while (matcher.find()){
int temp = Integer.valueOf(matcher.group(1))+1;
System.out.println( temp);
test = test.replace(matcher.group(),String.valueOf(temp));
System.out.println( test);
}
}
}