一 背景

最小二乘估计(Least Square Estimation)是方程参数估测的常用方法之一,在机器人视觉中应用广泛,在估计相机参数矩阵(Cameral calibration matrix)、单应矩阵(Homography)、基本矩阵(Fundamental matrix)、本质矩阵(Essential matrix)中都有使用,这种估计方法称为DLT(Direct Linear Transformation)算法。
在进行最小二乘估计时,常采用SVD(Singular Value Decomposition)方法。

二 数学计算

1 最小二乘估计

在估算单应矩阵时,会用到DLT算法,其核心就是SVD方法,基本流程见下图。其中方程形式为Ah=0,A是2n*9矩阵,n为采样点数量,h是1*9矩阵。

书[Hartley, 2003]中介绍到,A经过SVD可以得到A=UDVT,其中D是对角矩阵,对角元素按照从大到小排列。那么结论是,V的最后一列等于h,也就是说V的最后一列的9个元素,就是h内9个元素的估算结果。
在做最小二乘估计时,其实不需要完整进行SVD分解,只需要得到AT*A的最小特征值对应的特征向量即可,因为这个向量就是上面所说的V的最后一列。

2 SVD(奇异值分解)

矩阵奇异值分解的数学表示是A=UDVT,其中,D是对角矩阵,其值是AT*A的特征值的平方根,叫做奇异值,具体可参考[Zeng, 2015]。

3 特征值和特征向量

特征值和特征向量的基本算法有四种——定义法、幂法、雅各比(Jacobi)法和QR法。定义法就是从矩阵特征值和特征向量的定义出发,可参考[Lay, 2007],定义法适用于无误差的情况,而在计算机视觉的实际应用中,采集的数据有人工误差的引入,因此不适用。幂法的缺点是可能遗漏特征值,而这里需要知道最小特征值,因此也不适用。雅各比(Jacobi)法和QR法都能够求取所有特征值,也能够得到所有特征向量,因而适合与我们的应用背景。
我们目前适用的是雅各比(Jacobi)法,具体参考[Zhou, 2014]。需要注明的是,该博客所分享的代码中,第28行,对dbMax取的第一个值时,我认为应该取矩阵元素的绝对值,而不是其元素值本身。另外,Jacobi法的使用前提是原始矩阵为实对称阵。

Python程序

主函数:

import SVD#------------------------------------------------
# main
if __name__ == "__main__":print("Hello world")arr = [1., 2., 3.,7., 8., 9.]# doing SVD (single value decompositioin)eigens_sorted2 = SVD.Doing_svd(arr, 2, 3)print(eigens_sorted2)

SVD类:

from math import *PI = 3.1415926#------------------------------------------------
# Matrix math : dot prodict and transpose
#------------------------------------------------
def getTranspose(arr, nRow, nCol):arrTrans = []nRowT = nColnColT = nRowi = 0j = 0while i<nRowT:j = 0while j<nColT:arrTrans.append(arr[j*nCol+i])j += 1i += 1return arrTrans#------------------------------------------------
def getDotProduct_ATransA(arr, nRow, nCol):result = []arrTrans = getTranspose(arr, nRow, nCol)#print("trans")#epiACounter = 0#for ele in arrTrans:#   print("{},".format(ele)),#   epiACounter += 1#   if(epiACounter == 9):#       print("")#       epiACounter = 0i = 0j = 0nColT = nRownRowT = nColwhile i<nRowT:j = 0while j<nCol:#print("i {},   j {}".format(i,j))ele = 0k = 0while k<nColT:ele = ele + (arrTrans[i*nColT+k]*arr[k*nCol+j])#print("i {},   j {}, k {}".format(i,j,k))#print("{} * {}".format(arrTrans[i*nColT+k], arr[k*nCol+j]))#print("i {},   j {}, k {}".format(i,j,k))#print(ele)k += 1result.append(ele)j += 1i += 1#print(result)return result
#------------------------------------------------
# Single value decompostion
#------------------------------------------------
def getUnitMatrix(dimension):unitMatrix = []i = 0j = 0while i<dimension:j = 0while j<dimension:if(i==j):ele = 1.else:ele = 0.unitMatrix.append(ele)j += 1i += 1return unitMatrix
#------------------------------------------------
def arcTan(p1, p2):if p2!=0.:return atan(p1/p2)else:value = p1if value>0:return PI/2.else:return PI/-2.
#------------------------------------------------
def getEigenValue_Jacobi(arr, eps, maxCount):# step 1 : make eigen vector matrix readysizeDim = int(sqrt(len(arr)))sizeRow = int(sizeDim)sizeCol = int(sizeDim)eigenVector = getUnitMatrix(sizeDim)#print(eigenVector)# step 2 : iterate# step 2.1 : find the largest element nCount = 0while True:maxEle = abs(arr[1])#maxEle = abs(arr[1])nRow = 0nCol = 1i = 0j = 0while i<sizeDim:j=0while j<sizeDim:value = abs(arr[i*sizeRow+j])#print(value)if i!=j:if value>maxEle:maxEle = valuenRow = inCol = jj += 1i += 1#print("max element ({},{}) {}".format(nRow,nCol,maxEle))# step 2.2 : checkif maxEle<eps:breakif nCount>maxCount:breaknCount += 1# step 3 : calculateApp = arr[nRow*sizeDim+nRow]Apq = arr[nRow*sizeDim+nCol]Aqq = arr[nCol*sizeDim+nCol]#print("App = {}".format(App))theta = 0.5*arcTan(-2.*Apq,Aqq-App)sinTheta = sin(theta)cosTheta = cos(theta)sin2Theta = sin(2.*theta)cos2Theta = cos(2.*theta)arr[nRow*sizeDim+nRow] = App*cosTheta*cosTheta + Aqq*sinTheta*sinTheta + 2.*Apq*cosTheta*sinThetaarr[nCol*sizeDim+nCol] = App*sinTheta*sinTheta + Aqq*cosTheta*cosTheta - 2.*Apq*cosTheta*sinThetaarr[nRow*sizeDim+nCol] = 0.5*(Aqq-App)*sin2Theta + Apq*cos2Thetaarr[nCol*sizeDim+nRow] = arr[nRow*sizeDim+nCol]i = 0while i<sizeDim:if (i!=nRow)and(i!=nCol):u = i*sizeDim + nRow # pw = i*sizeDim + nCol # qdbMax = arr[u]arr[u] = arr[w]*sinTheta + dbMax*cosThetaarr[w] = arr[w]*cosTheta - dbMax*sinThetai += 1j = 0while j<sizeDim:if (j!=nRow)and(j!=nCol):u = nRow*sizeDim + j # pw = nCol*sizeDim + j # qdbMax = arr[u]arr[u] = arr[w]*sinTheta + dbMax*cosThetaarr[w] = arr[w]*cosTheta - dbMax*sinThetaj += 1# step 4 : get eigen vectori = 0while i<sizeDim:u = i*sizeDim + nRoww = i*sizeDim + nColdbMax = eigenVector[u]eigenVector[u] = eigenVector[w]*sinTheta + dbMax*cosThetaeigenVector[w] = eigenVector[w]*cosTheta - dbMax*sinThetai += 1#print("eigen vactors")#print(eigenVector)#print("eigen values")#print(arr)# make elements in eigen values matrix, i.e. arr, that are less than the eps to be 0for i in range(sizeDim):for j in range(sizeDim):if i!=j:if arr[i*sizeDim+j]<eps:arr[i*sizeDim+j] = 0eigens_svd = [arr] + [eigenVector] return eigens_svd
#------------------------------------------------
def getEigenValueAndVector_sorting(eigenValueAndVector):# get eigen values and eigen vectors from function "getEigenValue_Jacobi"eigenValue  = eigenValueAndVector[0]eigenVector = eigenValueAndVector[1]#print(eigenVectorAndValue)#print(eigenValue)#print(eigenVector)nDim = int(sqrt(len(eigenValue)))#print(nDim)if nDim!=3:print("the dimenstion of eigen value matrix is not 3!")returneigenValue_sorted  = [0,0,0] eigenVector_sorted = getUnitMatrix(3)# step 1 : find the largest eigen valuelargestEle  = eigenValue[0*nDim+0]position_largestEigenValue = 0for i in range(nDim):ele = eigenValue[i*nDim+i]#print("ele : {} ({},{})".format(ele, i, i))if ele>largestEle:largestEle = eleposition_largestEigenValue = i#print("the largest eigen value is : {} ({},{})".format(largestEle, position_largestEigenValue,position_largestEigenValue))eigenValue_sorted[0] = largestEleeigenVector_sorted[0] = eigenVector[0*nDim+position_largestEigenValue]eigenVector_sorted[3] = eigenVector[1*nDim+position_largestEigenValue]eigenVector_sorted[6] = eigenVector[2*nDim+position_largestEigenValue]#print("largest")#print(eigenVector_sorted)# step 2 : find the mediumlarge and the smallest eigen valueseigenValues_rest = [] # 2 row, 2 column. [eigen value, eigen value position] for each rowfor i in range(nDim):if i!=position_largestEigenValue:eigenValues_rest.append(eigenValue[i*nDim+i])eigenValues_rest.append(i)#print("the rest eigen values are {}".format(eigenValues_rest))position_mediumEigenValue = 0 position_smallestEigenValue = 1if eigenValues_rest[0]<eigenValues_rest[2]:position_mediumEigenValue = 1 position_smallestEigenValue = 0#print(position_mediumEigenValue)#print(position_smallestEigenValue)position_mediumEigenValue_inEigenValue = eigenValues_rest[position_mediumEigenValue*2+1]eigenValue_sorted[1] = eigenValues_rest[position_mediumEigenValue*2+0]eigenVector_sorted[1] = eigenVector[0*nDim+position_mediumEigenValue_inEigenValue]eigenVector_sorted[4] = eigenVector[1*nDim+position_mediumEigenValue_inEigenValue]eigenVector_sorted[7] = eigenVector[2*nDim+position_mediumEigenValue_inEigenValue]position_smallestEigenValue_inEigenValue = eigenValues_rest[position_smallestEigenValue*2+1]eigenValue_sorted[2] = eigenValues_rest[position_smallestEigenValue*2+0]eigenVector_sorted[2] = eigenVector[0*nDim+position_smallestEigenValue_inEigenValue]eigenVector_sorted[5] = eigenVector[1*nDim+position_smallestEigenValue_inEigenValue]eigenVector_sorted[8] = eigenVector[2*nDim+position_smallestEigenValue_inEigenValue]#print("eigen value stored : ")#print(eigenValue_sorted)#print("eigen vector stored : ")#print(eigenVector_sorted)eigens_sorted = [eigenValue_sorted] + [eigenVector_sorted]return eigens_sorted#------------------------------------------------
def Doing_svd(arr, nRow, nCol):arrT = getTranspose(arr, nRow, nCol)arrTTimesarr = getDotProduct_ATransA(arr, nRow, nCol)lowerlimit = 1.e-15eigens = getEigenValue_Jacobi(arrTTimesarr, lowerlimit, 300)    eigens_sorted = getEigenValueAndVector_sorting(eigens)return eigens_sorted#------------------------------------------------
def Test_showing():print("Hello, this comes from function \" Test_showing \"")return 

参考文献

[Hartley, 2003] Hartley R, Zisserman A. Multiple View Geometry in Computer Vision[M]. Cambridge University Press, 2003.
[Lay, 2007] David C. Lay, 沈复兴, 傅莺莺,等. 线性代数及其应用[M]. 人民邮电出版社, 2007.
[Zeng, 2015] 如何轻松干掉svd(矩阵奇异值分解),用代码说话, http://www.cnblogs.com/whu-zeng/p/4705970.html
[Zhou, 2014] 矩阵的特征值和特征向量的雅克比算法C/C++实现, http://blog.csdn.net/zhouxuguang236/article/details/40212143

最小二乘估计和奇异值分解(SVD)相关推荐

  1. 奇异值分解SVD和偏最小二乘奇异值分解PLSSVD

    奇异值分解SVD和偏最小二乘奇异值分解PLSSVD 目录 奇异值分解SVD和偏最小二乘奇异值分解PLSSVD 奇异值分解SVD

  2. 矩阵分解之: 特征值分解(EVD)、奇异值分解(SVD)、SVD++

    目录: 1.矩阵分解 1.1 矩阵分解的产生原因 1.2 矩阵分解作用 1.3 矩阵分解的方法 1.4 推荐学习的经典矩阵分解算法 2. 特征值分解(EVD) 3. 奇异值分解(SVD) 4. SVD ...

  3. 矩阵分解 (特征值/奇异值分解+SVD+解齐次/非齐次线性方程组)

    ,#1. 用途# 1.1 应用领域 最优化问题:最小二乘问题 (求取最小二乘解的方法一般使用SVD) 统计分析:信号与图像处理 求解线性方程组: Ax=0或Ax=b Ax = 0 或 Ax =b 奇异 ...

  4. tf 如何进行svd_一步步教你轻松学奇异值分解SVD降维算法

    摘要:奇异值分解(singular value decomposition)是线性代数中一种重要的矩阵分解,在生物信息学.信号处理.金融学.统计学等领域有重要应用,SVD都是提取信息的强度工具.在机器 ...

  5. 最小二乘估计 Least Squares estimation

    本文主要讲标准最小二乘方法及其常见的变形:加权最小二乘和总体最小二乘算法,关注不同方法之间的逻辑. 一.最小二乘估计(Least Squares estimation,LS) 最小二乘估计方法是一种不 ...

  6. 奇异值的物理意义是什么?强大的矩阵奇异值分解(SVD)及其应用

    作者:郑宁 链接:https://www.zhihu.com/question/22237507/answer/53804902 来源:知乎 著作权归作者所有.商业转载请联系作者获得授权,非商业转载请 ...

  7. 奇异值分解(SVD)原理详解及推导 (转)

    很不错的文章,适合入门. 转载出处http://blog.csdn.net/zhongkejingwang/article/details/43053513 在网上看到有很多文章介绍SVD的,讲的也都 ...

  8. 奇异值分解(SVD) --- 几何意义

     奇异值分解(SVD) --- 几何意义 2013-12-16 22:33:42 分类: 大数据 PS:一直以来对SVD分解似懂非懂,此文为译文,原文以细致的分析+大量的可视化图形演示了SVD的几何意 ...

  9. UA STAT687 线性模型II 最小二乘理论2 约束最小二乘估计

    UA STAT687 线性模型II 最小二乘理论2 约束最小二乘估计 约束最小二乘估计的求解 数值计算的思路 系数估计量的解析式 约束最小二乘估计的统计性质 约束最小二乘估计的求解 在线性模型y=Xβ ...

最新文章

  1. 三亚免税店积分抵现_又变了??三亚免税店的政策又变了~
  2. CLR Via C# 3rd 阅读摘要 -- Chapter 28 – Primitive Thread Synchronization Constructs
  3. 集合转换Stream流式操作
  4. ORACLE 普通表转换成分区表(在线重定义)
  5. iOS中安全结束 子线程 的方法
  6. Netflix正在搞的混沌工程到底是什么?终于有人讲明白了
  7. (转)基于.Net的单点登录(SSO)解决方案(1)
  8. 新会计准则(New Edition of Accounting Standard)
  9. 在 Windows 中为高级用户配置 IPv6 的指南
  10. 单片机是什么?51单片机和stm32有什么区别?
  11. Apache Pulsar 生态项目 AoP 新增两位中国移动 Maintainer!
  12. 开机hidl报错修改
  13. 速达财务软件未能连接服务器,速达3000财务软件使用常见问题
  14. 微信 8.0 的状态原来这么炸裂,无情地爱了爱了,做程序员的你还不赶紧设置一把?
  15. 自媒体如何推广?推广的渠道有哪些?
  16. 人工智能学习路线(转载)
  17. 【CF 比赛记录】Roye_ack的艰难上分日常(35)
  18. 使用 github 或者 gitee(码云)当作 maven 仓库的方法
  19. MATLAB 函数求导的若干问题
  20. 明基投影仪中心服务器联机失败,投影机使用中常见故障解决方法

热门文章

  1. 常用数学符号读法和常用含义
  2. 「AI+教育」和「AI教育」:一个为教育,一个做教育
  3. PyQt5安装及Pycharm配置详细教程(win10)
  4. python中凯撒密码加密_凯撒密码加密Python
  5. Linux驱动入门学习(三):I2C架构全面理解
  6. passport通行证设计一例
  7. Linux进程同步机制-Futex
  8. 【数据结构】求二叉树深度的算法
  9. aspen为什么不能用_我是如何学习Aspen Plus软件的---入门必看
  10. Oracle数据库开启归档日志和补充日志