使用双目相机进行三维重建 第一部分:相机校准

本文为 AI 研习社编译的技术博客,原标题 : 3D Reconstruction with Stereo Images -Part 1: Camera Calibration 作者 | Keenan James 翻译 | 通夜、Hasekiel_learn 校对 | 酱番梨 审核 | 约翰逊·李加薪 整理 | 立鱼王 原文链接: https://medium.com/@dc.aihub/3d-reconstruction-with-stereo-images-part-1-camera-calibration-d86f750a1ade 注:本文的相关链接请访问文末【阅读原文】

引言:后续的一系列文章会尝试解释用于从2D图片提取3D信息的一些重要工具和技术。3D重建对于很多应用来说是一个非常有用的工具,他可以构建人脸、场景、或其他物体的3D模型。这种模型是通过计算2D图像像素中的深度信息得到的。

(图 3D重建)

因为现在针孔数码相机已经相对比较便宜也容易买到,我们可以看到,相比其他的一些更加昂贵的技术(比方说Lidar),这种(数码相机的)手段为3D扫描提供了更实用的一种方法。而且,随着智能手机、监控技术、物联网的兴起,标准的2D相机早已在我们日常生活中得到普及。因此,这种2D手段使得3D重建在现有设备上的部署和应用成为可能,大大减少了资金上的门槛。

在本文中我们会研究如何使用双目图像(stereo images)实施3D重建。

双目图像需要两个相机分别拍摄图片,利用两张图片计算3D空间中的一个点。本质上是先把两张图片对应同一空间点的像素匹配,接着利用对极几何(epipolar geometry)计算该点在3D空间的坐标。处理了所有相关像素之后,最终得到的是被拍摄物体的3D点图(point map)。

(图)

然而,在实践中,3D重建远没有这么简单,需要更多步骤才能得到准确的3D点图。这个系列的文章会有四篇,每篇都涵盖一些实施有效3D重建需要弄懂的重要技术。该篇参考了Open CV文档中的教程,可以通过下面的链接中查看:

https://docs.opencv.org/3.0-beta/doc/py_tutorials/py_calib3d/py_table_of_contents_calib3d/py_table_of_contents_calib3d.html

这四篇文章包括:

  • 相机校准
  • 姿态估计
  • 对极几何
  • 立体图像的深度图

在本系列的最后,我希望你能够理解如何使用此工具集处理三维重建或三维扫描问题。有关详细内容请查看上面的Open CV文档。

相机校准

第一篇文章的目的是帮助你了解在使用普通针孔相机拍摄的照片中常见的相机变形。我们还将学习相机的内部参数和外部参数之间的定义和区别,以及为什么在我们的代码中需要它们。一旦找到了这些参数,我们就可以使用Open CV对图像进行变形校正。这是全面三维重建的第一步。

普通针孔相机通过两个主要因素使图像失真。径向畸变;这本质上使得直线在图像中呈现出轻微的曲线。线离图像中心越远,径向畸变的影响越严重。下面我们可以看到一个棋盘的例子,它的曲线特征由图像上方的红色直线突出显示。

为了纠正这个问题,并相应地校准相机,我们使用下面的方程。

针孔相机产生畸变的另一个因素是切向畸变。当使用的相机镜头与图像平面不完全对齐时,就会发生这种形式的失真。假设一个相机面对一个特定的方向,为了避免在图像中出现切向畸变,覆盖针孔光传感器的镜头必须完全垂直于相机所面对的方向。然而事实并非如此,因为大多数镜头都有轻微的倾斜,这导致物体在图像的一边比另一边更靠近相机。虽然人们用肉眼乍一看是几乎不可能看到这种失真的,但是为了进行三维重建,我们将需要使用一个方程来纠正图像。

这些方程的目的是确定我们的代码需要的五个参数,称为失真系数。这些信息将用于执行我们的Open CV包中专门用来3D重建的函数。

除了畸变系数,我们还需要识别相机的内部和外部参数。

内部参数是指相机的特定信息,如焦距和光的中心。

焦距是摄影镜头的基本描述,通常用(mm)表示。焦距与给定透镜的大小无关,而是指光线在光学距离上的一点,在这一点上,光线会聚在一起,使底层的数字传感器生成清晰而详细的图像。对于我们的例子,它用下面的符号表示。

透镜的光学中心是指光线通过其曲面时不发生偏转的一个点。由于透镜具有凸凹形状,透镜的任何其他点都会使光线向光学中心偏转或偏离光学中心。在我们的例子中,它用下面的符号表示。

在我们的代码中,内部参数包含在一个3×3矩阵中,如下所示。

外部参数是指描述相机在三维空间中相对位置的信息;比如旋转和平移向量。

对于我们针对立体图像的应用程序,在进一步尝试进行三维重建之前,需要首先使用上述参数纠正失真。要发现这些参数,我们需要提供一个定义良好的对象的示例图像,该对象的一般维度已经知道。利用物体在二维平面上的坐标与三维空间中真实物体的已知维数相匹配,可以计算出Open CV模块中所需要的畸变系数。幸运的是,我们将能够使用上面显示的棋盘作为我们的校准对象,并且Open CV中提供了该图片。

Code

虽然提供至少10张图片来有效校准我们的相机是一种很好的做法,但是为了简单起见,我们只举一个例子。

我们可以使用已知对象的图像来提取能够校准我们的相机的信息。我们需要的是一组二维图像平面内的物体的二维坐标,以及它在现实世界空间中的三维坐标。二维坐标称为图像点,三维坐标称为目标点。

图像点很容易确定,因为它只是简单地测量图像上的一个点与用X、Y坐标表示的其余点之间的关系。而目标点更难计算。我们需要知道的是物体在真实空间中的X,Y,Z坐标。为了简单起见,我们假设物体固定在xy平面上,因此Z的值总是0。这样一来,我们就可以只用X和Y作为三维空间中一个点的位置。用这种方法,我们可以有效地描述被描绘对象的大小和位置。

在我们的例子中,我们想用X和Y值来描述棋盘上单个正方形的大小。我们应该注意到,因为我们使用的是提供给我们的图片,而不是我们自己拍摄的,所以我们不知道图片中棋盘的确切大小。如果是我们自己拍的,我们就能够将特定的值(尺度或其他)传递到我们的坐标系。因为我们没有这个信息,所以我们仍然可以继续使用棋盘上单个正方形的大小作为度量标准。例如,正方形左下角的点可以表示为0,0,而右上角是1,1。假设棋盘上的所有方块大小相同,那么我们就可以根据图像中相同点的二维坐标引用这些信息来推断其在三维现实空间中的位置。

设置

接下来,我们可以继续编写代码,这些代码将在我们的棋盘中找到模式。我们可以从使用函数cv2.findChessBoardCorners()开始。这个函数需要特定的网格信息,比如8 x 8或4 x 4。在我们的例子中,我们会找到一个7×6的网格。这个函数返回的是棋盘每个角落的图像点坐标和一个布尔值,该值表示是否找到了完整的棋盘。

一旦发现棋盘的角,建议使用cv2.cornerSubPix()函数进一步提高其准确性,然后使用cv2.drawChessboardCorners()绘制覆盖在图像上的棋盘图案。

下面所示的代码涵盖了我们到目前为止所完成的工作。

import numpy as np
import cv2
import glob

# termination criteria
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)

# prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
objp = np.zeros((6*7,3), np.float32)
objp[:,:2] = np.mgrid[0:7,0:6].T.reshape(-1,2)

# Arrays to store object points and image points from all the images.
objpoints = [] # 3d point in real world space
imgpoints = [] # 2d points in image plane.

images = glob.glob('*.jpg')

for fname in images:
    img = cv2.imread(fname)
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

    # Find the chess board corners
    ret, corners = cv2.findChessboardCorners(gray, (7,6),None)

    # If found, add object points, image points (after refining them)
    if ret == True:
        objpoints.append(objp)

        cv2.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria)
        imgpoints.append(corners)

        # Draw and display the corners
        cv2.drawChessboardCorners(img, (7,6), corners2,ret)
        cv2.imshow('img',img)
        cv2.waitKey(500)

cv2.destroyAllWindows()

上面的代码将生成如下图,图中的棋盘上突出显示了一个7 x 6的网格。

我们终于可以继续校准我们的相机和纠正我们的图像。为此,我们将使用函数cv2.calibrateCamera()。它返回相机矩阵和畸变系数,包括旋转和平移向量为我们的外在值。

ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1],None,None)

畸变校正

在这一部分,我们现在能够使用Open CV的其他函数来对一个图像进行畸变校正。然而,第一步是使用cv2.getOptimalNewCameraMatrix()来完善含有我们内部参数值的相机矩阵。代码如下所示。

img = cv2.imread('left12.jpg')h,  w = img.shape[:2]newcameramtx, roi=cv2.getOptimalNewCameraMatrix(mtx,dist,(w,h),1,(w,h))

接下来我们可以继续校正畸变。下一个代码块显示了Open CV中用于执行此任务的方法的最简单实现。我们将使用前一个函数返回的ROI来裁剪得到的图像。

# undistortdst = cv2.undistort(img, mtx, dist, None, newcameramtx)
# crop the imagex,y,w,h = roidst = dst[y:y+h, x:x+w]cv2.imwrite('calibresult.png',dst)

结果如下图所示,它描绘了一个未失真的棋盘。

这篇文章的目的是提高我对计算机视觉应用程序的理解,希望它也能帮助其他人。

作者:Keenan James,导师:Amit Maraj教授

本文分享自微信公众号 - AI研习社(okweiwu)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-05-06

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏量子位

不用P30 Pro,普通手机也能变身望远镜:陈启峰团队新作,登上CVPR 2019

不过现在,就算不是P30 Pro,没有徕卡四摄,没有4,000万像素,只靠深度学习,iPhone也可以把50米之外的细节,拍得清楚明白。

12640
来自专栏量子位

华人女性AI科学家申省梅加盟安防新势力澎思,任职首席科学家,领导新加坡研究院

今日(3月19日),澎思科技宣布前松下新加坡研究院副院长申省梅为首席科学家,同时宣布成立澎思新加坡研究院,从事人工智能技术和深度学习领域的研究,申省梅担任院长,...

7810
来自专栏量子位

从高通加盟小鹏汽车负责自动驾驶后,吴新宙:L3方案下月亮相

3月13日,他们又有技术高管加盟。吴新宙,前高通自动驾驶业务负责人,正式官宣加盟小鹏汽车,出任自动驾驶副总裁,全面负责小鹏汽车自动驾驶美国及国内的整体技术路线规...

12210
来自专栏量子位

硬核佩奇和圣诞鳌拜,没有抠图AI能同时闯过这两关

随着AI技术的发展,抠图业也步入了新的竞争格局中,老牌巨头、新兴APP、开源项目、论文实现齐上阵,要把头发丝都抠出来。

13530
来自专栏量子位

一周AI十大要闻回顾 | 多项小技术有大突破,巨头忙打造产业基础平台

量子位筛选整理出过去一周Top 10,从技术新突破、政策新风向和产业新动态3大方面,为你提供最新趋势参考。

8540
来自专栏量子位

只要算法够厉害,白墙能当镜子用:我初中物理都白学了 | Nature新论文

一篇新论文登上了Nature,论文中显示,仅仅用一台普通的数码相机,仅仅凭借墙上模糊不清的光影,就能还原最初的画面。

10220
来自专栏量子位

吴恩达获英特尔投资!这次,英特尔拿出7.85亿砸向AI创业公司

英特尔投资在其全球峰会上宣布,拿出1.17亿美元(约合人民币7.85亿)投资14家创业公司。

10540
来自专栏量子位

Deepfake又被玩坏了:马斯克一键变成钢铁侠,Gif表情包换脸App试一下

11310
来自专栏量子位

Adobe放出P图新研究:就算丢了半个头,也能逼真复原

不好不好,这可是限量版24k纯金足球纪念勋章挂坠的唯一存世照片,要是没了,就只能飞8个航班越过54座山丘穿越25000公里拿出我逆光也清晰的R213重新拍一张了...

7520
来自专栏量子位

3D打印革命性升级!只要光照几十秒,完美雕像浮出水面丨Science

而利用光聚合反应,能够合成任意的几何形状,开头出现的神奇一幕,就是通过这个原理最终完成了3D打印。

8220

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励