简体   繁体   English

3D矩阵透视变换

[英]3D matrix perspective transform

I am using shape from shading to generate a Digital Terrain Model (DTM) of an image taken using a camera mounted on a mobile platform.我正在使用阴影形状来生成使用安装在移动平台上的相机拍摄的图像的数字地形模型 (DTM)。 The algorithm written in Python seems to work reasonably well however the output is at an incline and a bit spherical so I'm suspecting that I need to remove perspective distortion and barrelling from the DTM.用 Python 编写的算法似乎工作得相当好,但是输出是倾斜的并且有点球形,所以我怀疑我需要从 DTM 中去除透视失真和桶形。

The data is available here in case anyone is interested in having a go at this.如果有人有兴趣尝试一下,可以在此处获取数据。

The camera is mounted at an inclination of 41 degrees and has the following camera and distortion matrices:相机以 41 度的倾角安装,并具有以下相机和失真矩阵:

    cam_matrix = numpy.matrix([[246.00559,0.00000,169.87374],[0.00000,247.37317,132.21396],[0.00000,0.00000,1.00000]])
    distortion_matrix = numpy.matrix([0.04674, -0.11775, -0.00464, -0.00346, 0.00000])

How can I apply perspective transform and remove the barreling distortion from this matrix to obtain a flattened DTM?如何应用透视变换并从此矩阵中去除桶形失真以获得平坦的 DTM?

I have attempted this using OpenCV but it doesn't work as OpenCv is expecting an image and the transforms simply move pixels around rather than manipulate their value.我已经使用 OpenCV 尝试过这个,但它不起作用,因为 OpenCv 需要一个图像,并且转换只是移动像素而不是操纵它们的值。 I have also researched Numpy and Scipy but haven't arrived to a conclusion or a solution yet.我也研究了 Numpy 和 Scipy,但还没有得出结论或解决方案。 I am somewhat familiar with the theory behind these transforms but have mostly worked on 2D versions.我对这些变换背后的理论有些熟悉,但主要是在 2D 版本上工作。

Any ideas?有任何想法吗?

You can use a 4 x 4 transformation matrix which is inversible and allows a bi-directional tranformation between the two coordinate systems that you want.您可以使用 4 x 4 变换矩阵,它是可逆的,并允许在您想要的两个坐标系之间进行双向变换。

If you know the three rotations a , b and g , about x , y , z respectively, using the right-hand rule.如果你知道三个旋转abg ,分别关于xyz ,使用右手定则。 The x0 , y0 , z0 are the translations between the origins of the two coordinate systems. x0y0z0是两个坐标系原点之间的平移。

The transformation matrix is defined as:变换矩阵定义为:

T = np.array([[ cos(b)*cos(g), (sin(a)*sin(b)*cos(g) + cos(a)*sin(g)), (sin(a)*sin(g) - cos(a)*sin(b)*cos(g)), x0],
              [-cos(b)*sin(g), (cos(a)*cos(g) - sin(a)*sin(b)*sin(g)), (sin(a)*cos(g) + cos(a)*sin(b)*sin(g)), y0],
              [        sin(b), -sin(a)*cos(b), cos(a)*cos(b), z0]
              [ 0, 0, 0, 1])

To use it efficiently you should put your points in a 2-D array like:为了有效地使用它,你应该把你的点放在一个二维数组中,比如:

orig = np.array([[x0, x1, ..., xn],
                 [y0, y1, ..., yn],
                 [z0, z1, ..., zn],
                 [ 1,  1, ...,  1]])

Then:然后:

new = T.dot(orig)

will give you the transformed points.会给你转换点。

Saullo GP Castro has a great explanation. Saullo GP Castro有一个很好的解释。 This is the code I used with Python 3.8.这是我在 Python 3.8 中使用的代码。 If you play around with the T = make_matrix(90,0,0,1,0,0) line you can see the changes to the XYZ positions in the orig matrix.如果您使用 T = make_matrix(90,0,0,1,0,0) 行,您可以看到原始矩阵中 XYZ 位置的变化。

#!/usr/bin/env python3
import numpy as np
import math
'''If you know the three rotations a, b and g, about x, y, z respectively, using the 
right-hand rule.
The x0, y0, z0 are the translations between the origins of the two coordinate 
systems.'''
#https://stackoverflow.com/questions/22175385/3d-matrix-perspective-transform/22311973#22311973

def make_matrix(roll,pitch,heading,x0,y0,z0):
    a = math.radians(roll)
    b = math.radians(pitch)
    g = math.radians(heading)

    T = np.array([[ math.cos(b)*math.cos(g), (math.sin(a)*math.sin(b)*math.cos(g) + 
    math.cos(a)*math.sin(g)), (math.sin(a)*math.sin(g) - 
    math.cos(a)*math.sin(b)*math.cos(g)), x0],
    [-math.cos(b)*math.sin(g), (math.cos(a)*math.cos(g) - 
    math.sin(a)*math.sin(b)*math.sin(g)), (math.sin(a)*math.cos(g) + 
    math.cos(a)*math.sin(b)*math.sin(g)), y0],
    [        math.sin(b), -math.sin(a)*math.cos(b), math.cos(a)*math.cos(b), z0],
    [ 0, 0, 0, 1]])
    return T

def load_orig():
    orig = np.array([[0, 1, 0],
                [0, 0, 1],
                [1, 0, 0],
                [ 1,  1, 1]])
    return orig

if __name__ == '__main__':
    T = make_matrix(90,0,0,1,0,0)
    orig = load_orig()
    new = T.dot(orig)
    print(new)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM