【问题标题】:Python create image with new camera positionPython使用新的相机位置创建图像
【发布时间】:2018-01-30 08:57:35
【问题描述】:

我现在正在努力完成一项特定的计算机视觉任务。例如,假设我们有一个道路的相机框架。现在我想用水平平移的假想相机生成一个新帧。此外,还增加了一个微小的摄像机角度。为了说明这一点,我上传了一张演示图片:

如何在 python 中从原始框架创建新框架? 对于我的其他计算机视觉任务,我已经在使用 OpenCV。

【问题讨论】:

  • 假设您在展示时拍摄了两张照片,但没有将x 平移到距平面一米的位置。你可以想象,即使你会得到一些视角的变化,你也会从右边得到更多的图像,从左边得到更少的图像,所以会涉及到一些翻译。现在想象你做同样的事情,离墙只有一公里。从同一个角度翻译更多。所以你需要更多信息;特别是深度。 Here's a very detailed slide 涵盖了这个问题的许多方面。

标签: python opencv camera


【解决方案1】:

我也为此苦苦挣扎了一段时间,直到我看到 this helpful post 分享了一些示例代码。我从理论上理解,如果你有单应矩阵,你可以使用 OpenCV 的 warpPerspective 函数获得新框架。由于您具有精确的平移和旋转值,因此您可以根据相机的内在参数自行推导出矩阵。然而,直到我自己尝试了代码,我才完全了解它是如何完成的。

我们知道,对于空间中的 3D 点到 2D 图像投影,单应矩阵由下式给出

H = K[R|T]

要将点从一个 2D 图像转换为另一个,您只需先将点反投影到 3D,然后将它们重新投影到新的图像平面。

x' = K * [R2|T2] * [R1|T1](inv) * K(inv) * x

[R2|T2] * [R1|T1](inv) 相当于一个单一的变换矩阵,它给出了从一个摄像机姿态到另一个摄像机姿态的相对变换。通过在需要的地方附加 [0, 0, 0, 1],所有矩阵的形状为 4x4。

这里是一些示例代码,它们改编自同一篇文章的代码。

import cv2
import numpy as np

f = 500
rotXval = 90
rotYval = 90
rotZval = 90
distXval = 500
distYval = 500
distZval = 500

def onFchange(val):
    global f
    f = val
def onRotXChange(val):
    global rotXval
    rotXval = val
def onRotYChange(val):
    global rotYval
    rotYval = val
def onRotZChange(val):
    global rotZval
    rotZval = val
def onDistXChange(val):
    global distXval
    distXval = val
def onDistYChange(val):
    global distYval
    distYval = val
def onDistZChange(val):
    global distZval
    distZval = val

if __name__ == '__main__':

    #Read input image, and create output image
    src = cv2.imread('test.jpg')
    src = cv2.resize(src,(640,480))
    dst = np.zeros_like(src)
    h, w = src.shape[:2]

    #Create user interface with trackbars that will allow to modify the parameters of the transformation
    wndname1 = "Source:"
    wndname2 = "WarpPerspective: "
    cv2.namedWindow(wndname1, 1)
    cv2.namedWindow(wndname2, 1)
    cv2.createTrackbar("f", wndname2, f, 1000, onFchange)
    cv2.createTrackbar("Rotation X", wndname2, rotXval, 180, onRotXChange)
    cv2.createTrackbar("Rotation Y", wndname2, rotYval, 180, onRotYChange)
    cv2.createTrackbar("Rotation Z", wndname2, rotZval, 180, onRotZChange)
    cv2.createTrackbar("Distance X", wndname2, distXval, 1000, onDistXChange)
    cv2.createTrackbar("Distance Y", wndname2, distYval, 1000, onDistYChange)
    cv2.createTrackbar("Distance Z", wndname2, distZval, 1000, onDistZChange)

    #Show original image
    cv2.imshow(wndname1, src)

    k = -1
    while k != 27:

        if f <= 0: f = 1
        rotX = (rotXval - 90)*np.pi/180
        rotY = (rotYval - 90)*np.pi/180
        rotZ = (rotZval - 90)*np.pi/180
        distX = distXval - 500
        distY = distYval - 500
        distZ = distZval - 500

        # Camera intrinsic matrix
        K = np.array([[f, 0, w/2, 0],
                    [0, f, h/2, 0],
                    [0, 0,   1, 0]])

        # K inverse
        Kinv = np.zeros((4,3))
        Kinv[:3,:3] = np.linalg.inv(K[:3,:3])*f
        Kinv[-1,:] = [0, 0, 1]

        # Rotation matrices around the X,Y,Z axis
        RX = np.array([[1,           0,            0, 0],
                    [0,np.cos(rotX),-np.sin(rotX), 0],
                    [0,np.sin(rotX),np.cos(rotX) , 0],
                    [0,           0,            0, 1]])

        RY = np.array([[ np.cos(rotY), 0, np.sin(rotY), 0],
                    [            0, 1,            0, 0],
                    [ -np.sin(rotY), 0, np.cos(rotY), 0],
                    [            0, 0,            0, 1]])

        RZ = np.array([[ np.cos(rotZ), -np.sin(rotZ), 0, 0],
                    [ np.sin(rotZ), np.cos(rotZ), 0, 0],
                    [            0,            0, 1, 0],
                    [            0,            0, 0, 1]])

        # Composed rotation matrix with (RX,RY,RZ)
        R = np.linalg.multi_dot([ RX , RY , RZ ])

        # Translation matrix
        T = np.array([[1,0,0,distX],
                    [0,1,0,distY],
                    [0,0,1,distZ],
                    [0,0,0,1]])

        # Overall homography matrix
        H = np.linalg.multi_dot([K, R, T, Kinv])

        # Apply matrix transformation
        cv2.warpPerspective(src, H, (w, h), dst, cv2.INTER_NEAREST, cv2.BORDER_CONSTANT, 0)

        # Show the image
        cv2.imshow(wndname2, dst)
        k = cv2.waitKey(1)

【讨论】:

    【解决方案2】:

    如果您尝试平移,请更改图像的平面,这可以通过单应矩阵来完成。检查透视变换。 Here .

    您需要使用矩阵的值 H(0,2) 和 H(2,0) 沿 X 平移,然后将图像更改为一个角度,就像在您的图像中一样。

    首先找到具有相同图像的Homography矩阵,然后改变矩阵的上述位置值并对其进行翘曲。你会得到你想要的。

    编辑:单应性只是一个 3x3 矩阵。每个矩阵元素对应于对图像的特定操作。

    Like 0x0 位置的元素水平拉伸图像。 1x0 位置的元素使图像倾斜。就像保持左边缘静止并拉下右边缘一样。同样,其他元素执行各自的操作。

    现在在单应矩阵中,2x0 和 0x2 处的元素被分配给您想要的任务。即,平移​​平面并沿 X 方向移动。通过更改(播放)这些值,您可以获得图像的不同视角。因此这也称为透视变换。

    【讨论】:

    • 您好,这听起来很简单,但是您所说的“使用值 H(0,2) 和 H(2,0)”是什么意思?对不起,我对这个话题很陌生
    • 好的,我在答案的最后部分进行了编辑和添加。查看。如果您需要代码方面的帮助,请随时提出。
    猜你喜欢
    • 1970-01-01
    • 2020-12-29
    • 1970-01-01
    • 2018-10-20
    • 1970-01-01
    • 2012-10-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多