大数据,机器学习,人工智能

使用双目相机进行三维重建 第二部分:姿态估计

2019-05-08  本文已影响3人  AI研习社
image

本文为 AI 研习社编译的技术博客,原标题 :

3D Reconstruction with Stereo Images - Part 2: Pose Estimation

作者 |* Keenan James*

翻译 | 酱番梨、Hasekiel_learn

校对 | 酱番梨 审核 | 酱番梨 整理 | 立鱼王

原文链接:

https://medium.com/@dc.aihub/3d-reconstruction-with-stereo-images-part-2-pose-estimation-1bcfbba61b26

image

引言:在上一篇文章中我们讲了相机的特征以及这些信息与我们做3D重建有什么关系。通过相机校正,我们确认了一些我们程序要用的相机属性数据,即相机矩阵(camera matrix)和扭曲系数(distortion coefficients)。利用这些信息,我们可以从拍摄的模式图像(patterned image)中计算出现实空间中物体的位置。在我们的例子中,我们会用象棋棋盘图像,并通过3D立方的绘制方向来可视化平面物体的相对位置。

image

开始

这个练习的目的是给我们的图像画上x,y,z轴,放在棋盘的底部角落。按惯例,3D空间中X坐标轴用蓝色、Y用绿色、Z用红色。这个例子里,我们让Z轴垂直于物体(即Z轴是从棋盘2D平面指向相机的)。

我们首先取出之前练习保存的相机矩阵和扭曲系数。

import cv2
import numpy as np
import glob

# Load previously saved data
with np.load('B.npz') as X:
    mtx, dist, _, _ = [X[i] for i in ('mtx','dist','rvecs','tvecs')]

接下来要写一个函数来绘制3D坐标轴。这个函数的输入是:棋盘图像、棋盘四个角(坐标)、三个分别代表三坐标轴方向终点的点(坐标)。

棋盘的角落可以用之前的cv2.findChessboardCorner()函数,返回的是一个含有4个角位置的数组。这里我们只需要注意底部左手角落,它是数组的第一个元素,如下图corner[0]。得到该坐标后,我们就可以利用之前定义的3个终点展开我们的坐标轴了。

def draw(img, corners, imgpts):
    corner = tuple(corners[0].ravel())
    img = cv2.line(img, corner, tuple(imgpts[0].ravel()), (255,0,0), 5)
    img = cv2.line(img, corner, tuple(imgpts[1].ravel()), (0,255,0), 5)
    img = cv2.line(img, corner, tuple(imgpts[2].ravel()), (0,0,255), 5)
    return img

下一步我们要在3D空间中定义一些点帮助我们绘制坐标轴。回忆一下在上一个练习中,我们令棋盘一个方块的边长等于一个单位。在这个例子中,我们在三个方向上画了长3个单位的坐标轴。Z轴需要标负值,因为这样可以保证轴线面朝相机。

criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
objp = np.zeros((6*7,3), np.float32)
objp[:,:2] = np.mgrid[0:7,0:6].T.reshape(-1,2)

axis = np.float32([[3,0,0], [0,3,0], [0,0,-3]]).reshape(-1,3)

现在我们可以用上我们的绘制函数了。第一步先读取图片,寻找7x6的格子(译者注:指棋盘)。找到之后,我们可以利用cv2.solvePnPRansac()计算其旋转角和平移距离(rotation and translation)。现在把3D空间的轴点(axis points)投影到2D图像平面去。识别出坐标轴后,就用绘制函数可视化其方向。

for fname in glob.glob('left*.jpg'):
    img = cv2.imread(fname)
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    ret, corners = cv2.findChessboardCorners(gray, (7,6),None)

    if ret == True:
        corners2 = cv2.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria)

        # Find the rotation and translation vectors.
        rvecs, tvecs, inliers = cv2.solvePnPRansac(objp, corners2, mtx, dist)

        # project 3D points to image plane
        imgpts, jac = cv2.projectPoints(axis, rvecs, tvecs, mtx, dist)

        img = draw(img,corners2,imgpts)
        cv2.imshow('img',img)
        k = cv2.waitKey(0) & 0xff
        if k == 's':
            cv2.imwrite(fname[:6]+'.png', img)

cv2.destroyAllWindows()

如下图,我们看到四张不同棋盘图像被我们程序处理后的结果。

image

渲染一个立方体

为了描画一个立方体,我们可以按照下文所述修改绘图函数。首先绘制一个3 x 3的正方形,朝向左下角并与我们的棋盘平行。然后我们将添加从该正方形延伸的线,以在面向相机的方向上完成立方体。

def draw(img, corners, imgpts):
    imgpts = np.int32(imgpts).reshape(-1,2)

    # draw ground floor in green
    img = cv2.drawContours(img, [imgpts[:4]],-1,(0,255,0),-3)

    # draw pillars in blue color
    for i,j in zip(range(4),range(4,8)):
        img = cv2.line(img, tuple(imgpts[i]), tuple(imgpts[j]),(255),3)

    # draw top layer in red color
    img = cv2.drawContours(img, [imgpts[4:]],-1,(0,0,255),3)

    return img

我们必须修改轴点,并以此来囊括立方体的每个角。

axis = np.float32([[0,0,0], [0,3,0], [3,3,0], [3,0,0],
                   [0,0,-3],[0,3,-3],[3,3,-3],[3,0,-3] ])

下面的两幅图片已将结果显示出来:

image

结论

在上述练习之后,我们可以考虑增强现实(AR)的应用。在这里,我们成功地将3D对象包含在真实世界图像中,该图像与所描绘的对象相互作用,允许真实世界和虚拟世界之间的动态链接。

image

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

想要继续查看该篇文章相关链接和参考文献?

点击使用双目相机进行三维重建 第二部分:姿态估计即可访问:

【译者招募】伯克利《深度无监督学习》

很高兴我们又拿到了2019 春季伯克利 深度无监督学习这门课程的授权,现在开始招募译者了噢!
如果你对此感兴趣的话,可以点击链接加入课程小组:
https://ai.yanxishe.com/page/groupDetail/70

同时你想报名参与课程翻译的话,请私聊字幕君,字幕君会将你拉入译者群,准备开始翻译噢!

上一篇下一篇

猜你喜欢

热点阅读