คณิตศาสตร์มุมมองของฉันถูกต้องหรือไม่


24

ฉันมีการบ้านที่ฉันต้องคำนวณและพล็อตจุดบางจุดโดยใช้การแปลงแบบ pespective แต่ฉันไม่แน่ใจว่าผลลัพธ์ของฉันถูกต้องเนื่องจากพล็อต 3 มิติที่ใช้พิกัดกล้องดูแตกต่างจาก 2d โดยใช้พิกัดภาพ . คุณช่วยฉันเข้าใจสิ่งที่ผิดหรือเปล่า?

นี่คือสิ่งที่ได้รับ: กล้องอยู่ที่จุด , ระบุในพิกัดโลก (เป็นเมตร) ระบบพิกัดของกล้องหมุนรอบแกน Y ของการอ้างอิงโลกโดยดังนั้นเมทริกซ์การหมุนคือWTC=[-1,1,5]Tw R c = [ c o s ( θ ) 0 s i n ( θ ) 0 1 0 - s i n ( θ ) 0 c o s ( θ ) ]θ=160โอWR=[โอs(θ)0sผมn(θ)010-sผมn(θ)0โอs(θ)]

พารามิเตอร์กล้องคือ: , , ,=16ม.ม.sx=sY=0.01ม.ม./พีxโอx=320พีxโอY=240พีx

จุดตัวอย่าง (ในพิกัดโลก):

WP1=[1,1,0.5]T

WP2=[1,1.5,0.5]T

WP3=[1.5,1.5,0.5]T

WP4=[1.5,1,0.5]T

ฉันต้องคำนวณและพล็อตจุดในพิกัดกล้องและพิกัดภาพดังนั้นฉันจึงเขียนโค้ดต่อไปนี้ใน Octave:

%camera intrinsic parameters
f = 16
Sx = 0.01
Sy = 0.01
Ox = 320
Oy = 240

%given points, in world coordinate
wP1 = transpose([1, 1, 0.5])
wP2 = transpose([1, 1.5, 0.5])
wP3 = transpose([1.5, 1.5, 0.5])
wP4 = transpose([1.5, 1, 0.5])

% camera translation matrix
wTc = transpose([-1, 1, 5])

% rotation angle converted to rad
theta = 160 / 180 * pi

%camera rotation matrix
wRc = transpose([cos(theta), 0, sin(theta); 0, 1, 0; -sin(theta), 0, cos(theta)])

%transform the points to homogeneous coordinates
wP1h = [wP1; 1]
wP2h = [wP2; 1]
wP3h = [wP3; 1]
wP4h = [wP4; 1]

%separate each line of the rotation matrix
R1 = transpose(wRc(1 , :))
R2 = transpose(wRc(2 , :))
R3 = transpose(wRc(3 , :))

%generate the extrinsic parameters matrix
Mext = [wRc, [-transpose(R1) * wTc; -transpose(R2) * wTc; -transpose(R3) * wTc]]

%intrinsic parameters matrix
Mint = [-f/Sx, 0, Ox; 0, -f/Sy, Oy; 0, 0, 1]

% calculate coordinates in camera coordinates
cP1 = wRc * (wP1 - wTc)
cP2 = wRc * (wP2 - wTc)
cP3 = wRc * (wP3 - wTc)
cP4 = wRc * (wP4 - wTc)

% put coordinates in a list for plotting

x = [cP1(1), cP2(1), cP3(1), cP4(1), cP1(1)]
y = [cP1(2), cP2(2), cP3(2), cP4(2), cP1(2)]
z = [cP1(3), cP2(3), cP3(3), cP4(3), cP1(3)]

%plot the points in 3D using camera coordinates
plot3(x, y, z, "o-r")

pause()

% calculate the points in image coordinates
iP1 = Mint * (Mext * wP1h)
iP2 = Mint * (Mext * wP2h)
iP3 = Mint * (Mext * wP3h)
iP4 = Mint * (Mext * wP4h)

%generate a list of points for plotting
x = [iP1(1) / iP1(3), iP2(1) / iP2(3), iP3(1) / iP3(3), iP4(1) / iP4(3), iP1(1) / iP1(3)]
y = [iP1(2) / iP1(3), iP2(2) / iP2(3), iP3(2) / iP3(3), iP4(2) / iP4(3), iP1(2) / iP1(3)]

plot(x, y, "o-r")

pause()

และนี่คือแผนการที่ฉันได้รับจากสคริปต์: ฉันคาดหวังว่าพวกเขาจะคล้ายกัน แต่พวกเขาไม่ได้ดู

พล็อต 3D

พล็อตในพิกัดกล้อง

พล็อต 2D

พล็อตในพิกัดรูปภาพ


8
+1 สำหรับแสดงว่าคำถามการบ้านอาจเป็นคำถามคุณภาพสูง :)
Martin Ender

2
ตามที่ระบุในเมตาคำถามนี้สมควรได้รับคำตอบที่ดี ฉันไม่มีตัวเอง แต่ฉันมีความสุขที่ได้ให้ชื่อเสียงกับใครบางคน
trichoplax

@trichoplax ปัญหาคือมันทำใน matlab
joojaa

@ joojaa อาจุดดี หากไม่มีผู้เชี่ยวชาญด้าน matlab เข้ามาในช่วงระยะเวลาของเงินรางวัลฉันจะพิจารณาการเรียนรู้Octaveเพื่อดูว่ามันใกล้พอที่จะหาทางออกหรือไม่
trichoplax

1
ไม่ชัดเจนสำหรับฉันว่าภาพแรกควรจะหมายถึงอะไร ส่วนที่สองมาจากมุมมองของกล้องและหลังจากการประมาณค่าซองจดหมายฉันคิดว่ามันถูกต้อง
Julien Guertault

คำตอบ:


8

การระบุแกนของคุณทั้งในรูปและเพิ่มตำแหน่งกล้องในรูปแรกของคุณจะช่วยให้คุณเข้าใจว่าเกิดอะไรขึ้น

นอกจากนี้คุณยังอาจมีตัวแปรเดียวสำหรับจุดทั้งหมดของคุณสร้างเมทริกซ์ 2D กับแถวเป็นจุดแต่ละจุดและคอลัมน์ที่เป็นส่วนประกอบ ,และZด้วยวิธีนี้คุณสามารถจัดการการฉายโดยใช้การคูณเมทริกซ์อย่างง่ายแทนที่จะจัดการแต่ละแถวแยกกันxYZ

ในคำแถลงปัญหาน่าสนใจที่จะทราบทิศทางการหมุนของคุณและที่สำคัญกว่านั้นคือทิศทางกล้องดั้งเดิมและเวกเตอร์ขึ้นไป ผมคิดว่าคุณกล้องจะหมุน 160 องศาทวนเข็มนาฬิกาทิศทางกล้องเดิมและเวกเตอร์ขึ้นเป็น0] หากข้อสันนิษฐานเหล่านี้ผิดคำตอบที่เหลือจะผิด[0,0,1][0,1,0]

ไม่มีสัญลักษณ์ของการแปลง mm เป็น m ในรหัสของคุณ ทั้งโฟกัสของคุณควรจะและหรือพิกัดจุดของคุณควรจะคูณด้วย0.000010.016Sx=SY=0.00010.00001

ให้เหตุผลว่าจุดใดควรเป็นจุดสิ้นสุดในภาพของคุณ ตัวอย่างเช่นศูนย์กล้องของคุณที่ไม่มีการหมุนจะชี้ไปที่บรรทัดเนื่องจากจุดทั้งหมดอยู่บนระนาบเราจึงสามารถทำการวิเคราะห์ต่อไปนี้: ถ้าเรามุ่งเน้นที่ -axis เราจะเห็น , ดังนั้นศูนย์กล้องจะจบลงเล็กน้อยที่ด้านซ้ายของจุด (เนื่องจากกล้องอยู่ที่ ) ดังนั้นจุดศูนย์กลางจะสิ้นสุดที่ซึ่งหมายความว่าจุดจะปรากฏขึ้นที่ส่วนด้านขวาของภาพ . นอกจากนี้กล้องยังมีพิกัดเช่นเดียวกับสองจุดและตั้งแต่[-1,1,x]Z=0.5xเสื้อan(160°)(5-0.5)=1.64 ...x=-10.64YY พิกัดจะไม่เปลี่ยนไปตามการหมุน แต่ก็ควรจะจบลงที่พิกัดเดียวกันหลังจากการแปลงซึ่งหมายถึงแถวกลางของภาพ

วิธีที่ดีในการตรวจสอบคำตอบของคุณคือการใช้แบบจำลอง 3 มิติที่มีอยู่เช่นเครื่องปั่น: ฉาก 3 มิติใน Blender ระมัดระวังกับการปั่น' [0, 0, -1]ระบบพิกัดเช่นเวกเตอร์กล้องเริ่มต้นคือ นี่คือการแสดงผล: แสดงผลใน Blender โฟกัสถูกตั้งค่าเป็นค่าอื่นเพื่อให้ทรงกลมมองเห็นได้มากขึ้น ดังนั้นเราจะเห็นว่าจุดสองจุดด้านล่างอยู่ในแถวกลางของภาพและจุดนั้นอยู่ทางด้านขวาของภาพเล็กน้อย

ฉันทำการบ้านของคุณใน Python:

import numpy as np

from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import axes3d, Axes3D


# Parameters
f_mm = 0.016
f_px = f_mm / 0.00001
t_cam = np.array([[-1., 1., 5.]]).T
t_cam_homogeneous = np.vstack((t_cam, np.array([[0]])))
theta = 160. * np.pi / 180.
ox = 320
oy = 240
# Rotation and points are in homogeneous coordinates
rot_cam = np.array([[np.cos(theta), 0, np.sin(theta)],
                    [0, 1, 0],
                    [-np.sin(theta), 0, np.cos(theta)]])
points = np.array([[1, 1, 0.5, 1],
                   [1, 1.5, 0.5, 1],
                   [1.5, 1.5, 0.5, 1],
                   [1.5, 1, 0.5, 1]]).T

# Compute projection matrix using intrinsics and extrinsics
intrinsics = np.array([[f_px, 0, ox],
                       [0, f_px, oy],
                       [0, 0, 1]])
extrinsics = np.hstack((rot_cam, rot_cam.dot(-t_cam)))

rot_cam2 = np.identity(4); rot_cam2[:3,:3] = rot_cam
camera_coordinates = rot_cam2.dot(points - t_cam_homogeneous)
camera_coordinates = camera_coordinates[:3,:] / camera_coordinates[3,:]

# Perform the projection
projected_points = intrinsics.dot(camera_coordinates)
projected_points = projected_points[:2,:] / projected_points[2,:]
projected_points[0,:] = -projected_points[0,:] # Inverted x-axis because camera is pointing toward [0, 0, 1]

fig = plt.figure()
ax = Axes3D(fig)
ax.scatter(points[0,:], points[1,:], points[2,:], label="Points")
ax.scatter(t_cam[0], t_cam[1], t_cam[2], c="red", label="Camera")
ax.set_xlabel("X axis"); ax.set_ylabel("Y axis"); ax.set_zlabel("Z axis")
plt.title("World coordinates")
plt.legend()
plt.savefig('world_coordinates.png', dpi=300, bbox_inches="tight")

fig = plt.figure()
ax = Axes3D(fig)
ax.scatter(camera_coordinates[0,:], camera_coordinates[1,:], camera_coordinates[2,:], label="Points")
ax.scatter(0, 0, 0, c="red", label="Camera")
ax.set_xlabel("X axis"); ax.set_ylabel("Y axis"); ax.set_zlabel("Z axis")
plt.title("Camera coordinates")
plt.legend()
plt.savefig('camera_coordinates.png', dpi=300, bbox_inches="tight")

plt.figure()
plt.scatter(projected_points[0,:], projected_points[1,:])
plt.xlabel("X axis"); plt.ylabel("Y axis")
plt.title("Image coordinates")
plt.savefig('image_coordinates.png', dpi=300, bbox_inches="tight")

plt.show()

นี่ให้ผลตัวเลขเหล่านั้น: ตามลำดับ: พิกัดโลก, พิกัดกล้อง, พิกัดกล้องหมุนเพื่อให้พอดีกับการวางแนวกล้องเล็กน้อย (โปรดสังเกตว่าที่นี่เวกเตอร์กล้องไปยังจุดชมวิวรูปมันไม่ได้ "ป้อน" ภาพ) และพิกัดรูปภาพพิกัดโลก พิกัดของกล้อง พิกัดของกล้องหมุน พิกัดรูปภาพ

ดังนั้นเราจะเห็นว่าพิกัดแนวตั้งสำหรับจุดด้านล่างนั้นอยู่ในแถวกลาง (240) อย่างถูกต้องและจุดนั้นอยู่ทางด้านขวาของภาพ (ค่าแนวนอน> 320)

ฉันเชื่อว่ามีข้อบกพร่องอย่างหนึ่งที่คุณพบว่าคุณพบค่า X ติดลบดังนั้นคุณจึงลบล้าง focals ( -f/Sxy) ในเมทริกซ์อินทรินเพื่อชดเชย ปัญหาที่นี่คือเราได้สมมติว่ากล้องเริ่มชี้ไปที่ (มิฉะนั้นการหมุน 160 °จะไม่ชี้ไปที่จุดนั้น) หากคุณมองไปทางนั้นค่า -axis จะเพิ่มขึ้นเมื่อเดินไปทางซ้ายควรใช้อินเวอร์สของแกนนี้[0,0,1]x

ผลลัพธ์ของเราทั้งคู่ดูเหมือนกันกับฉันเพียงแค่คุณคาดว่าจะมีเวกเตอร์อัพสำหรับกล้อง (อันที่จริงทั้งสองแกนถูกมิเรอร์เพราะคุณลบล้างทั้ง focals) และทำการคำนวณเป็นมิลลิเมตรแทนเมตร[0,-1,0]

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.