之前提到过透视仿射矩阵需要4个点对便可求出A。但是在项目中为了定位精准采用大于4个点对的来获得透视矩阵,点对大于4方程数大于未知数,所有只能通过最小二乘来解该超定矩阵。设矩阵方程为R*A = Y。最小二乘解为:
公式推导没研究过。想知道推导过程的请移步。
结合之前透视仿射的矩阵公式,写出了C#实现的代码。矩阵运算使用Math.Net包。代码如下:
public static int PerspectiveAfffine(List<PointF> srcList, List<PointF> destList, out Matrix<float> matrix)
{
List<float> BLit = new List<float>();
foreach (var item in srcList)
{
BLit.Add(item.X);
BLit.Add(item.Y);
}
float[,] Barray = new float[BLit.Count, 1];
for (int i = 0; i < BLit.Count; i++)
{
Barray[i, 0] = BLit[i];
}
Matrix<float> B = CreateMatrix.DenseOfArray<float>(Barray); //Ax = B.....B矩阵
float[,] Xarray = new float[3, 3]; //3行3列透视仿射矩阵 X矩阵
matrix = CreateMatrix.DenseOfArray<float>(Xarray);
if (srcList.Count <= 4 || destList.Count <= 4 || destList.Count != srcList.Count)
{
return 0x0001; //错误码
} //检查
List<float[]> ALit = new List<float[]>();
for (int i = 0; i < destList.Count; i++)
{
float[] Column1x = new float[] { destList[i].X, destList[i].Y, 1f, 0f, 0f, 0f, -(destList[i].X * srcList[i].X), -(destList[i].Y * srcList[i].X) };
float[] Column2x = new float[] { 0f, 0f, 0f, destList[i].X, destList[i].Y, 1f, -(destList[i].X * srcList[i].Y), -(destList[i].Y * srcList[i].Y) };
ALit.Add(Column1x);
ALit.Add(Column2x);
}
float[,] Aarray = new float[ALit.Count, 8];
for (int i = 0; i < ALit.Count; i++)
{
for (int j = 0; j < 8; j++)
{
Aarray[i, j] = ALit[i][j];
}
}
Matrix<float> A = CreateMatrix.DenseOfArray<float>(Aarray);
var r = (A.Transpose().Multiply(A)).Inverse();
var x = (r * A.Transpose() * B).ToArray();
Xarray = new float[3, 3] { { x[0,0],x[1,0],x[2,0] },
{ x[3,0],x[4,0],x[5,0]},
{ x[6,0],x[7,0],1}
};
matrix = CreateMatrix.DenseOfArray<float>(Xarray);
return 0x0000;
}