3d вращение на изображении - PullRequest
8 голосов
/ 08 февраля 2012

Я пытаюсь получить некоторый код, который будет выполнять преобразование перспективы (в данном случае 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, прежде чем я начну получать результаты, которые кажутся вполне разумными. Есть идеи, что может быть не так?

Ответы [ 2 ]

24 голосов
/ 09 февраля 2012

Сначала построим матрицу вращения вида

    [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

Мне нужно немного подумать о том, как связать наклонную матрицу с трехмерным преобразованием. Я ожидаю, что самый простой способ - установить матрицу 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 cameraman around origin and center+skew

0 голосов
/ 08 февраля 2012

Я не понимаю, как вы строите свою матрицу вращения. Это кажется довольно сложным для меня. Обычно его строят путем построения нулевой матрицы, размещения 1 на ненужных осях и общих sin, cos, -cos, sin в двух используемых измерениях. Затем умножаем все это вместе.

Откуда вы взяли эту np.eye(3) + np.sin(angle) * skew(axis) + (1 - np.cos(angle)) * skew(axis).dot(skew(axis)) конструкцию?

Попробуйте построить матрицу проекции из основных строительных блоков. Построить матрицу вращения довольно просто, и «точка-матрица вращения» должна работать.

Возможно, вам придется обратить внимание на центр вращения. Ваше изображение, вероятно, размещено в виртуальной позиции 1 на оси z, поэтому, поворачиваясь на x или y, оно немного перемещается. Поэтому вам нужно использовать перевод, чтобы z стало 0, затем поверните, а затем переведите обратно. (Матрицы перевода в аффинных координатах тоже довольно просты. См. Википедию: https://en.wikipedia.org/wiki/Transformation_matrix)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...