iT邦幫忙

2024 iThome 鐵人賽

DAY 7
0

以下是今天的練習目標:

  1. 畫出一個相機
  2. 將相機移動到設定的位置
  3. 將相機轉向設定的方向
  4. 將多個轉換矩陣組合起來

基於前一篇文的基礎,我們可以畫出一個相機

import sys
import numpy as np
from PIL import Image
from vispy import app, scene, visuals

# Create canvas
canvas = scene.SceneCanvas(title="vispy tutorial", keys="interactive", show=True)
# Make color white
canvas.bgcolor = "white"

# Create view and set the viewing camera
view = canvas.central_widget.add_view()
view.camera = "turntable"
view.camera.fov = 50
view.camera.distance = 10


def create_frustum(aspect_ratio=1.3, camera_to_world=np.eye(4)):
    objects = []    # Record all the objects to created in this function
    center = np.array([0, 0, 0])
    points = np.array([
        [0.5, 0.5, 1],
        [0.5, -0.5, 1],
        [-0.5, -0.5, 1],
        [-0.5, 0.5, 1],
    ])
    points[:, 0] *= aspect_ratio

    for i in range(4):
        line = scene.visuals.Line(pos=np.array([center, points[i]]), color="red", antialias=True, width=2, parent=view.scene)
        objects.append(line)
        line = scene.visuals.Line(pos=np.array([points[i], points[(i + 1) % 4]]), color="red", antialias=True, width=2, parent=view.scene)
        objects.append(line)

    camera_axis = scene.visuals.XYZAxis(parent=view.scene, width=2, antialias=True)
    objects.append(camera_axis)
    
    # Create the semi-transparent plane
    plane = scene.visuals.Polygon(pos=points, color=(1, 0, 0, 0.5), parent=view.scene)
    # Here the z-axis of the plane is ignored, so we need to translate it
    plane.transform = scene.transforms.MatrixTransform()
    plane.transform.translate([0, 0, 1])
    objects.append(plane)



create_frustum()
world_axis = scene.visuals.XYZAxis(parent=view.scene, width=2, antialias=True)


if __name__ == "__main__":
    if sys.flags.interactive != 1:
        app.run()

不同的是,我們用一個objects搜集所有我們創建的物件,這樣我們就可以在之後方便的對他們進行操作,並且加入了camera_to_world=np.eye(4)一個參數,等等會使用到。

frustum1

接著我們在create_frustum的最後面加上camera_to_world的轉換,這樣我們就可以將相機移動到指定的位置。要注意到,在 vispy 的轉換矩陣定義是反過來的,所以我們需要將矩陣轉置一下,再乘上物件原本的轉換。

    new_transform = scene.transforms.MatrixTransform()
    new_transform.matrix = camera_to_world.T    # NOTE: we need to transpose the matrix
    for object in objects:
        object.transform = new_transform * object.transform

舉例來說,我們可以將相機移動到 (3, 2, 1) 的位置

camera_to_world = np.eye(4)
camera_to_world[0, 3] = 3.0
camera_to_world[1, 3] = 2.0
camera_to_world[2, 3] = 1.0
create_frustum(camera_to_world=camera_to_world)

frustum2

也可以將相機轉向,延著 x 軸轉 45 度

camera_to_world = np.eye(4)

# Rotate the camera along x-axis for 100 degrees
camera_to_world[:3, :3] = np.array([
    [1, 0, 0],
    [0, np.cos(np.radians(100)), -np.sin(np.radians(100))],
    [0, np.sin(np.radians(100)), np.cos(np.radians(100))]
])

# Translate the camera to (3, 2, 1)
camera_to_world[0, 3] = 3.0
camera_to_world[1, 3] = 2.0
camera_to_world[2, 3] = 1.0
create_frustum(camera_to_world=camera_to_world)

要記得這裡的定義是,先旋轉再平移,所以我們先將相機轉向,再將相機移動到指定的位置。

frustum3

組合拳

我們可以任意的組合這些旋轉和平移的矩陣,只要把這些矩陣依次從右到左相乘,就可以得到我們想要的結果。舉例來說,我們可以將相機沿著 x, y, z 軸分別旋轉 100, 30, 300 度,然後平移到 (3, 2, 1) 的位置。利用齊次座標的優點,我們可以將這些操作合併成一個矩陣,再套用到相機上,打出一套組合拳。

# Rotate the camera along x-axis for 100 degrees
rotation1 = np.array([
    [1, 0, 0, 0],
    [0, np.cos(np.radians(100)), -np.sin(np.radians(100)), 0],
    [0, np.sin(np.radians(100)), np.cos(np.radians(100)), 0],
    [0, 0, 0, 1]
])

# Rotate the camera along y-axis for 30 degrees
rotation2 = np.array([
    [np.cos(np.radians(30)), 0, np.sin(np.radians(30)), 0],
    [0, 1, 0, 0],
    [-np.sin(np.radians(30)), 0, np.cos(np.radians(30)), 0],
    [0, 0, 0, 1]
])
# Rotate the camera along z-axis for 300 degrees
rotation3 = np.array([
    [np.cos(np.radians(300)), -np.sin(np.radians(300)), 0, 0],
    [np.sin(np.radians(300)), np.cos(np.radians(300)), 0, 0],
    [0, 0, 1, 0],
    [0, 0, 0, 1]
])

# Translate the camera to (3, 2, 1)
translation = np.array([
    [1, 0, 0, 3],
    [0, 1, 0, 2],
    [0, 0, 1, 1],
    [0, 0, 0, 1]
])
# "@" is the matrix multiplication operator in numpy
camera_to_world = translation @ rotation3 @ rotation2 @ rotation1
create_frustum(camera_to_world=camera_to_world)

frustum4


上一篇
Day5: vispy 視覺化 (二) 實作:繪製相機座標
下一篇
Day7: 相機投影練習
系列文
3D 重建實戰:使用 2D 圖片做相機姿態估計與三維空間重建13
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言