图像上的 3D 旋转

发布于 2025-01-03 06:40:17 字数 967 浏览 0 评论 0原文

我正在尝试获取一些代码来对图像执行透视变换(在本例中为 3d 旋转)。

import os.path
import numpy as np
import cv

def rotation(angle, axis):
    return np.eye(3) + np.sin(angle) * skew(axis) \
               + (1 - np.cos(angle)) * skew(axis).dot(skew(axis))

def skew(vec):
    return np.array([[0, -vec[2], vec[1]],
                     [vec[2], 0, -vec[0]],
                     [-vec[1], vec[0], 0]])

def rotate_image(imgname_in, angle, axis, imgname_out=None):
    if imgname_out is None:
        base, ext = os.path.splitext(imgname_in)
        imgname_out = base + '-out' + ext
    img_in = cv.LoadImage(imgname_in)
    img_size = cv.GetSize(img_in)
    img_out = cv.CreateImage(img_size, img_in.depth, img_in.nChannels)
    transform = rotation(angle, axis)
    cv.WarpPerspective(img_in, img_out, cv.fromarray(transform))
    cv.SaveImage(imgname_out, img_out)

当我绕 z 轴旋转时,一切都按预期工作,但绕 x 或 y 轴旋转似乎完全不正常。在开始获得看起来完全合理的结果之前,我需要旋转小至 pi/200 的角度。知道可能出什么问题吗?

I'm trying to get some code that will perform a perspective transformation (in this case a 3d rotation) on an image.

import os.path
import numpy as np
import cv

def rotation(angle, axis):
    return np.eye(3) + np.sin(angle) * skew(axis) \
               + (1 - np.cos(angle)) * skew(axis).dot(skew(axis))

def skew(vec):
    return np.array([[0, -vec[2], vec[1]],
                     [vec[2], 0, -vec[0]],
                     [-vec[1], vec[0], 0]])

def rotate_image(imgname_in, angle, axis, imgname_out=None):
    if imgname_out is None:
        base, ext = os.path.splitext(imgname_in)
        imgname_out = base + '-out' + ext
    img_in = cv.LoadImage(imgname_in)
    img_size = cv.GetSize(img_in)
    img_out = cv.CreateImage(img_size, img_in.depth, img_in.nChannels)
    transform = rotation(angle, axis)
    cv.WarpPerspective(img_in, img_out, cv.fromarray(transform))
    cv.SaveImage(imgname_out, img_out)

When I rotate about the z-axis, everything works as expected, but rotating around the x or y axis seems completely off. I need to rotate by angles as small as pi/200 before I start getting results that seem at all reasonable. Any idea what could be wrong?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

惟欲睡 2025-01-10 06:40:17

首先,构建旋转矩阵,其形式

    [cos(theta)  -sin(theta)  0]
R = [sin(theta)   cos(theta)  0]
    [0            0           1]

为应用此坐标变换可以围绕原点进行旋转。

相反,如果您想绕图像中心旋转,则必须首先移动图像中心
到原点,然后应用旋转,然后将所有内容移回原点。您可以使用
平移矩阵:

    [1  0  -image_width/2]
T = [0  1  -image_height/2]
    [0  0   1]

平移、旋转和逆平移的变换矩阵变为:

H = inv(T) * R * T

我必须考虑一下如何将倾斜矩阵与 3D 变换联系起来。我预计最简单的方法是设置 4D 变换矩阵,然后将其投影回 2D 齐次坐标。但目前,倾斜矩阵的一般形式:

    [x_scale 0       0]
S = [0       y_scale 0]
    [x_skew  y_skew  1]

x_skew 和 y_skew 值通常很小(1e-3 或更小)。

这是代码:

from skimage import data, transform
import numpy as np
import matplotlib.pyplot as plt

img = data.camera()

theta = np.deg2rad(10)
tx = 0
ty = 0

S, C = np.sin(theta), np.cos(theta)

# Rotation matrix, angle theta, translation tx, ty
H = np.array([[C, -S, tx],
              [S,  C, ty],
              [0,  0, 1]])

# Translation matrix to shift the image center to the origin
r, c = img.shape
T = np.array([[1, 0, -c / 2.],
              [0, 1, -r / 2.],
              [0, 0, 1]])

# Skew, for perspective
S = np.array([[1, 0, 0],
              [0, 1.3, 0],
              [0, 1e-3, 1]])

img_rot = transform.homography(img, H)
img_rot_center_skew = transform.homography(img, S.dot(np.linalg.inv(T).dot(H).dot(T)))

f, (ax0, ax1, ax2) = plt.subplots(1, 3)
ax0.imshow(img, cmap=plt.cm.gray, interpolation='nearest')
ax1.imshow(img_rot, cmap=plt.cm.gray, interpolation='nearest')
ax2.imshow(img_rot_center_skew, cmap=plt.cm.gray, interpolation='nearest')
plt.show()

输出:

Rotations of Photographer around origin and center+skew

First, build the rotation matrix, of the form

    [cos(theta)  -sin(theta)  0]
R = [sin(theta)   cos(theta)  0]
    [0            0           1]

Applying this coordinate transform gives you a rotation around the origin.

If, instead, you want to rotate around the image center, you have to first shift the image center
to the origin, then apply the rotation, and then shift everything back. You can do so using a
translation matrix:

    [1  0  -image_width/2]
T = [0  1  -image_height/2]
    [0  0   1]

The transformation matrix for translation, rotation, and inverse translation then becomes:

H = inv(T) * R * T

I'll have to think a bit about how to relate the skew matrix to the 3D transformation. I expect the easiest route is to set up a 4D transformation matrix, and then to project that back to 2D homogeneous coordinates. But for now, the general form of the skew matrix:

    [x_scale 0       0]
S = [0       y_scale 0]
    [x_skew  y_skew  1]

The x_skew and y_skew values are typically tiny (1e-3 or less).

Here's the code:

from skimage import data, transform
import numpy as np
import matplotlib.pyplot as plt

img = data.camera()

theta = np.deg2rad(10)
tx = 0
ty = 0

S, C = np.sin(theta), np.cos(theta)

# Rotation matrix, angle theta, translation tx, ty
H = np.array([[C, -S, tx],
              [S,  C, ty],
              [0,  0, 1]])

# Translation matrix to shift the image center to the origin
r, c = img.shape
T = np.array([[1, 0, -c / 2.],
              [0, 1, -r / 2.],
              [0, 0, 1]])

# Skew, for perspective
S = np.array([[1, 0, 0],
              [0, 1.3, 0],
              [0, 1e-3, 1]])

img_rot = transform.homography(img, H)
img_rot_center_skew = transform.homography(img, S.dot(np.linalg.inv(T).dot(H).dot(T)))

f, (ax0, ax1, ax2) = plt.subplots(1, 3)
ax0.imshow(img, cmap=plt.cm.gray, interpolation='nearest')
ax1.imshow(img_rot, cmap=plt.cm.gray, interpolation='nearest')
ax2.imshow(img_rot_center_skew, cmap=plt.cm.gray, interpolation='nearest')
plt.show()

And the output:

Rotations of cameraman around origin and center+skew

浅忆流年 2025-01-10 06:40:17

我不明白你构建旋转矩阵的方式。对我来说这似乎相当复杂。通常,它会通过构造一个零矩阵,将 1 放在不需要的轴上,以及常见的 sincos- 来构建cossin 转换为两个使用的维度。然后将所有这些相乘。

你从哪里得到的 np.eye(3) + np.sin(angle) * skew(axis) + (1 - np.cos(angle)) * skew(axis).dot(skew(axis)) 构造自?

尝试从基本构建块构建投影矩阵。构建旋转矩阵相当容易,“旋转矩阵点倾斜矩阵”应该可以工作。

不过,您可能需要注意旋转中心。您的图像可能放置在 z 轴上的虚拟位置 1 处,因此通过在 x 或 y 上旋转,它会移动一点。
因此,您需要使用平移,使 z 变为 0,然后旋转,然后平移回来。 (仿射坐标中的平移矩阵也非常简单。请参阅维基百科:https://en.wikipedia.org/维基/Transformation_matrix

I do not get the way you build your rotation matrix. It seems rather complicated to me. Usually, it would be built by constructing a zero matrix, putting 1 on unneeded axes, and the common sin, cos, -cos, sin into the two used dimensions. Then multiplying all these together.

Where did you get that np.eye(3) + np.sin(angle) * skew(axis) + (1 - np.cos(angle)) * skew(axis).dot(skew(axis)) construct from?

Try building the projection matrix from basic building blocks. Constructing a rotation matrix is fairly easy, and "rotationmatrix dot skewmatrix" should work.

You might need to pay attention to the rotation center though. Your image probably is placed at a virtual position of 1 on the z axis, so by rotating on x or y, it moves around a bit.
So you'd need to use a translation so z becomes 0, then rotate, then translate back. (Translation matrixes in affine coordinates are pretty simple, too. See wikipedia: https://en.wikipedia.org/wiki/Transformation_matrix )

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文