作者:李城来源:微信公众号|3D视觉工坊(系投稿)「3D视觉工坊」技术交流群已经成立,目前大约有12000人,方向主要涉及3D视觉、CV&深度学习、SLAM、三维重建、点云后处理、自动驾驶、CV入门、三维测量、VR/AR、3D人脸识别、医疗影像、缺陷检测、行人重识别、目标跟踪、视觉产品落地、视觉竞赛、车牌识别、硬件选型、学术交流、求职交流、ORB-SLAM系列源码交流、深度估计等。

提到三角化大家都十分熟悉,在CV 领域中,由像点计算物点的过程称为三角化,但在摄影测量领域,其称作为前方交会。值得注意的是单张影像是无法恢复像点的三维坐标,至少需要两张影像才能得到像素点的真实坐标(这里已知两张影像的pose信息)

三角化有很多方法,这里介绍两帧三角化、多帧三角化、迭代三角化、选权迭代多帧三角化(并附上本人代码)。

1、两帧三角化

在opencv 中函数triangulatePoints就可根据两帧的pose 和内参恢复三维点坐标,cv中的三角化是两帧且是没有权的。

其函数参数如下:

void cv::triangulatePoints ( InputArray projMatr1, //P1 1 3*4InputArray projMatr2, //P2 3*4InputArray projPoints1, //pixel coordinatesInputArray projPoints2, // pixel coordinatesOutputArray points4D // 3D coordinates) 2、多帧三角化

三角化严密解推导过程:

由共线条件方程得到三角化严密解法,将分母移到左边,得到

整理可得:

l1X+l3Y+l3Zlx=0L4X+l5Y+l6Zly=0

其中:

从上可以知道,一个像点可以列2个方程,对于n个同名像点就可以列2n个方程(AX=B,超定方程按照最小二乘求解),即是多帧三角化,代码如下:

def pixelToCam(pts,K): ''' :param pts: pixel coordinates :param K: camera params :return: camera coordinates ''' camPts=np.zeros((1,2)) camPts[0,0]=(pts[0,0]-K[0,2])/K[0,0] camPts[0,1]=(pts[0,1]-K[1,2])/K[1,1] return camPtsdef getEquation(camPts,R,t): ''' build equation ,one pixel point get 2 equations :param camPts: camera coordinates :param R: image pose-rotation ,world to camera :param t: image pose -translation,is camera center(t=-R.T*tvec) :return: equation coefficient ''' A=np.zeros((2,3)) b=np.zeros((2,1)) A[0,0]=R[0,0]-camPts[0,0]*R[2,0] A[0,1]=R[0,1]-camPts[0,0]*R[2,1] A[0,2]=R[0,2]-camPts[0,0]*R[2,2] b[0,0]=t[0,0]*A[0,0]+t[0,1]*A[0,1]+t[0,2]*A[0,2] A[1,0]=R[1,0]-camPts[0,1]*R[2,0] A[1,1]=R[1,1]-camPts[0,1]*R[2,1] A[1,2]=R[1,2]-camPts[0,1]*R[2,2] b[1,0]=t[0,0]*A[1,0]+t[0,1]*A[1,1]+t[0,2]*A[1,2] return A,b3 、迭代三角化

其做法就是在方程系数加入因子,不断调整系数的因子,本人代码如下:

def IterativeLinearLSTri(u1,P1,u2,P2): wi,wi1=1,1 #不断需要更新的因子 X=np.zeros((4,1)) for i in range(10): #迭代10次 X_=linear_ls_triangulation(u1,P1,u2,P2) # 线性求解两帧的像素点的三维坐标 X[1,0]=X_[0,1] X[2,0]=X_[0,2] X[3,0]=1 p2x=np.dot(P1[2,:].reshape(1,4),X)[0,0] p2x1=np.dot(P2[2,:].reshape(1,4),X)[0,0] if abs(wi-p2x) <=0.001 and abs(wi1-p2x1)<=0.001 : break wi=p2x wi1=p2x1 A = np.array([(u1[0]*P1[2, 0] - P1[0, 0])/wi, (u1[0]*P1[2, 1] - P1[0, 1])/wi, (u1[0]*P1[2, 2] - P1[0, 2])/wi, (u1[1]*P1[2, 0] - P1[1, 0])/wi, (u1[1]*P1[2, 1] - P1[1, 1])/wi, (u1[1]*P1[2, 2] - P1[1, 2])/wi, (u2[0]*P2[2, 0] - P2[0, 0])/wi1, (u2[0]*P2[2, 1] - P2[0, 1])/wi1, (u2[0]*P2[2, 2] - P2[0, 2])/wi1, (u2[1]*P2[2, 0] - P2[1, 0])/wi1, (u2[1]*P2[2, 1] - P2[1, 1])/wi1, (u2[1]*P2[2, 2] - P2[1, 2])/wi1]).reshape(4, 3) B = np.array([-(u1[0]*P1[2, 3] - P1[0, 3])/wi, -(u1[1]*P1[2, 3] - P1[1, 3])/wi, -(u2[0]*P2[2, 3] - P2[0, 3])/wi1, -(u2[1]*P2[2, 3] - P2[1, 3])/wi1]).reshape(4, 1) ret, X_ = cv2.solve(A, B, flags=cv2.DECOMP_SVD) X[0,0]=X_[0,0] X[1,0]=X_[1,0] X[2,0]=X_[2,0] X[3,0]=1 return X4、选权迭代多帧三角化

首先解释选权迭代(IGG算法),上世纪 80 年代,首创从验后方差估计导出粗差定位的选权迭代法,命名为“李德仁方法”。在实际测量工作中客观条件的限制,很难完全避免粗差的存在或做到完全同等精度量测.在平差过程中,通常引入权作为比较观测值之间相对精度高低的指标,并为精度较高的观测数据赋予较高的权重,这样就可规避有害信息的干扰。例如,我们在image matching 的匹配的时候,会用到ransac(同样是稳健估计算法) 剔除outlier,但是当你的同名点是在多帧上且只有一个的时候(比如多帧红绿灯的位置测量),ransac 就不能再使用,这个时候使用IGG 算法可以有效的规避误点带来影响,论文参考-多像空间前方交会的抗差总体最小二乘估计,本人将论文的算法进行了复现,代码如下:

def IterationInsection(pts,K,R,t): # cam_xyz is inital value # 这里假设像点x,y是等权的 k0=1.5 k1=2.5 # K1=2 weight=np.identity(len(pts)*2) cam_xyz=mutiTriangle(pts,K,R,t) cam_xyz_pre=cam_xyz iteration=0 while 1: d=np.zeros((len(pts),1)) for i in range(len(R)): pro,J = cv2.projectPoints(cam_xyz.reshape(1, 1, 3), R[i], t[i], K, np.array([])) pro=pro.reshape(1,2) deltax=pro[0,0]-pts[i][0,0] deltay=pro[0,1]-pts[i][0,1] d[i,0]=np.sqrt(deltax**2+deltay**2) weight_temp=np.diag(weight)[::2].reshape(-1,1) delta=np.sqrt(np.sum(weight_temp*d**2)/(len(pts)-2)) w=np.zeros((len(pts),1)) for i in range(len(pts)): u=d[i] if abs(u)=k0*delta: w[i]=delta/u elif abs(u)>=k1*delta: w[i]=0 weight_temp=w weight_p=[val for val in weight_temp.reshape(-1,) for i in range(2)] weight_p=np.diag(weight_p) cam_xyz_curr=weight_mutiTriangle(pts,K,R,t,weight_p) dx=cam_xyz_curr[0,0]-cam_xyz_pre[0,0] dy=cam_xyz_curr[1,0]-cam_xyz_pre[1,0] dz=cam_xyz_curr[2,0]-cam_xyz_pre[2,0] # print(dx,dy,dz) if np.sqrt(dx**2+dy**2+dz**2)<0.01: break else: cam_xyz=cam_xyz_curr cam_xyz_pre=cam_xyz_curr weight=weight_p iteration+=1# print("d{0}".format(d)) print("iteration is {0}\n".format(iteration)) print("IGG....{0},{1},{2}".format(cam_xyz[0,0],cam_xyz[1,0],cam_xyz[2,0])) return cam_xyz,weight其中mutiTriangle 函数和weight_mutiTriangle函数如下:

def mutiTriangle(pts,K,R,t): if len(pts)>=4: #这里是假设至少track 4帧 equa_A=[] equa_b=[] for i in range(len(pts)): camPts=pixelToCam(pts[i],K) t1=np.dot(np.linalg.inv(R[i]),-t[i]).reshape(1,3) A1,b1=getEquation(camPts,R[i],t1) equa_A.append(A1) equa_b.append(b1) AA=np.vstack(equa_A) bb=np.vstack(equa_b) P_ls=np.dot(np.linalg.inv(AA.T@AA),AA.T@bb) return P_ls else: print("tracker pixel point less 3,can not insection........") return Nonedef weight_mutiTriangle(pts,K,R,t,weight): if len(pts)>=4: equa_A=[] equa_b=[] for i in range(len(pts)): camPts=pixelToCam(pts[i],K) t1=np.dot(np.linalg.inv(R[i]),-t[i]).reshape(1,3) A1,b1=getEquation(camPts,R[i],t1) equa_A.append(A1) equa_b.append(b1) AA=np.vstack(equa_A) bb=np.vstack(equa_b) P_ls=np.dot(np.linalg.pinv(AA.T@weight@AA),AA.T@weight@bb) return P_ls else: print("tracker pixel point less 4,can not insection........") return None参考文献:

1、多像空间前方交会的抗差总体最小二乘估计[J].李忠美.测绘学报

本文仅做学术分享,如有侵权,请联系删文。

举报/反馈

计算机视觉三角测量公式,摄影测量(计算机视觉)中的三角化方法相关推荐

  1. 摄影测量(计算机视觉)中的三角化方法

    提到三角化大家都十分熟悉,在CV 领域中,由像点计算物点的过程称为三角化,但在摄影测量领域,其称作为前方交会.值得注意的是单张影像是无法恢复像点的三维坐标,至少需要两张影像才能得到像素点的真实坐标(这 ...

  2. 摄影测量计算机视觉领域_死亡之书:摄影测量资产,树木,视觉特效

    摄影测量计算机视觉领域 In this blog series, we will go over every aspect of the creation of our demo "Book ...

  3. Mathtype公式在Word表格中排列不齐的解决方法

    Mathtype公式在Word表格中排列不齐的解决方法 写论文时突然发现一个格式问题,用mathtype公式添加到表格中会出现水平排列无法对齐的现象,如图: 在试过了以下各类调节对齐的方法: 1. 使 ...

  4. 【Arduino串口数据保存到excel中常用三种方法】

    [Arduino串口数据保存到excel中常用三种方法] 1. 前言 2. 利用excel自带Data Streamer读取 2.1 启用 Data Streamer 加载项 2.2 刷写代码并将微控 ...

  5. 摄影测量实习空中三角测量_摄影测量入门:Photoscan

    摄影测量实习空中三角测量 步骤1:准备使用Agisoft Photoscan进行摄影测量 ( Step 1: Getting Ready to Use Agisoft Photoscan for Ph ...

  6. SLAM中双目三角化

    双目三角化 形式1:在等式左边同时乘x1x_1x1​ 和Rx2Rx_2Rx2​ 形式2:直接变形 形式3:等式两边同时叉乘x1 形式4:Direct Linear Transform 参考资料 在SL ...

  7. PCL中GreedyProjection三角化算法简介与示例

    文章目录 前言 一.PCL点云三角化 1.1 Delaunay三角剖分 1.2 贪婪三角化 二.程序示例 总结 前言 Delaunay三角剖分最初应用于2维领域,而与Greedy三角化算法的结合,使之 ...

  8. 【摄影测量原理】第三章:双像立体测图

    本章主要内容: 第一节    人眼的立体视觉和立体观测 第二节    立体像对相对定向和核线几何 第三节    立体像对的前方交会 第四节    单元模型的绝对定向 第五节    双像解析摄影测量 第 ...

  9. 用通达信破解接口指标公式判断股市牛熊的三个方法

    1.赚钱效应:牛市赚钱效应较高,市场热情和参与度较高:熊市赚钱效应低,市场热情和参与度较低. 2.成交量:牛市成交量较大,大部分股票成交量会急剧放大:熊市成交量较小,大部分股票成交量急剧萎缩. 3.股 ...

  10. 【java】springboot项目启动数据加载内存中的三种方法

    文章目录 一.前言 二.加载方式 2.1. 第一种:使用@PostConstruct注解(properties/yaml文件). 2.2. 第二种:使用@Order注解和CommandLineRunn ...

最新文章

  1. 详尽 | PyTorch动态图解析
  2. java代码写jsp读取,Java IO学习基础之读写文本文件-JSP教程,Java技巧及代码
  3. python能够做什么软件-python爬虫软件有哪些做的比较好的?
  4. C语言 利用malloc()和realloc()动态分配内存
  5. 服务器怎么虚拟化内存,服务器虚拟化内存大小
  6. webservice 函数2007不可以用_Excel出了一个新函数,太好用啦!但我不建议你们学……...
  7. Android 更新UI的几种方式
  8. Oracle监听注册和sqlnet,Oracle监听的动态注册与静态注册
  9. 了解如何通过Python使用SQLite数据库
  10. 免费证书https://lamp.sh/ssl.html
  11. L2-004. 这是二叉搜索树吗?-PAT团体程序设计天梯赛GPLT
  12. [转载]生活在 Emacs 中
  13. JS 获取上传文件的内容
  14. 拓端tecdat|R语言线性分类判别LDA和二次分类判别QDA实例
  15. python: 校园网登录脚本
  16. UltraEdit+Masm--打造自己的汇编IDE
  17. 百度Java二面面经
  18. 分位数回归的实现方法
  19. 杰奇cms mysql查询_杰奇cms自动推送链接插件使用方式
  20. SQLserver未发现数据源名称并且未指定默认驱动程序

热门文章

  1. Bootstrap的js插件之側边栏停靠(affix)
  2. VBA 字典方法及属性介绍
  3. Python学习笔记-2017.5.4thon学习笔记-2017.5.19
  4. 数据寻址——偏移寻址
  5. linux中echo是什么意思中文,在Linux操作系统中Echo的用法
  6. npm install Error: EACCES: permission denied 问题解决
  7. 在数据迁移过程中如何迁移holo(memory)表?
  8. 【第9篇】Python爬虫实战-银行卡归属地查询
  9. GFLOPs、GMACs、FMA之间的关系
  10. 如何制作Excel表头