国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

關(guān)于相機(jī)內(nèi)參與外參的淺讀

這篇具有很好參考價(jià)值的文章主要介紹了關(guān)于相機(jī)內(nèi)參與外參的淺讀。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

原文地址:https://tunmx.github.io/posts/CH-Camera-internal-and-external-parameters/

學(xué)習(xí)人臉3D重建的第一天,在首次接觸3D相關(guān)的內(nèi)容,必須要搞清楚相機(jī)的成像原理,如何將真實(shí)三維空間中的三維點(diǎn)與顯示器、屏幕和圖像等二維成像的平面映射,以及了解該過(guò)程的推導(dǎo)方式和相關(guān)坐標(biāo)系的換算,如像素坐標(biāo),圖像坐標(biāo),相機(jī)坐標(biāo)以及世界坐標(biāo)這四種關(guān)系的變換。

主要內(nèi)容從以下博主的文章整理,并結(jié)合自己的實(shí)驗(yàn)代碼進(jìn)行測(cè)試,推薦直接看原帖,無(wú)中間商賺差價(jià):

https://www.cnblogs.com/wangguchangqing/p/8126333.html#autoid-0-5-0

一文帶你搞懂相機(jī)內(nèi)參外參(Intrinsics & Extrinsics) - Yanjie Ze的文章 - 知乎?

針孔模型

從圖中所示,我們可以清楚的看到兩種坐標(biāo)系:

  • 相機(jī)坐標(biāo)系(3D):以光心中心點(diǎn)相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔為原點(diǎn),建立相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔三維坐標(biāo)系;

  • 圖像坐標(biāo)系(2D):以被投射的平面中相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔為原點(diǎn),建立相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔二維坐標(biāo)系。

相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔

從圖所示,取真實(shí)世界中的任意一點(diǎn)相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔通過(guò)相機(jī)的光心相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔點(diǎn)映射到成像平面上的點(diǎn)相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔,其中我們令點(diǎn)相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔,則對(duì)應(yīng)到點(diǎn)相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔,這邊比較特殊,將成像的平面與光點(diǎn)的距離記為f,即為像距,所以可以用以下圖表示坐標(biāo)系和映射點(diǎn)之間的關(guān)系:

相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔

通過(guò)上圖相似三角形關(guān)系可以得出以下關(guān)系式:

相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔

其中出現(xiàn)負(fù)號(hào)的原因是因?yàn)樽鴺?biāo)軸在映射過(guò)程中的成像為倒立所導(dǎo)致,為了表達(dá)方便,看到一個(gè)博主是這樣解釋和處理的:

為了表示起來(lái)更方便,我們把成像平面從相機(jī)的后面對(duì)稱到前面去,這樣,負(fù)號(hào)就沒(méi)有了。

一文帶你搞懂相機(jī)內(nèi)參外參(Intrinsics & Extrinsics) - Yanjie Ze的文章 - 知乎?

經(jīng)過(guò)轉(zhuǎn)換后的關(guān)系:

相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔

通現(xiàn)在我們把上面的關(guān)系式以解出相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔點(diǎn)為目的進(jìn)行變形,可得:

相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔

相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔

上面便是整理好的小孔模型基本公式,通過(guò)這些公式我們可以進(jìn)一步的去推算利用該模型下求解相機(jī)的內(nèi)參和外參。

簡(jiǎn)單的描述一下相機(jī)內(nèi)參:相機(jī)內(nèi)參描述了相機(jī)本身自帶的一些屬性,如焦距、像素間距等;通常是用一個(gè)內(nèi)參矩陣K來(lái)表示,這個(gè)矩陣K用于描述從三維場(chǎng)景到二維場(chǎng)景的映射形狀和大小。

上一步我們求解出了小孔模型的基本公式,需要進(jìn)一步將所述的坐標(biāo)點(diǎn)映射到像素坐標(biāo)系中,像素坐標(biāo)定義通常如下:

  • 像素坐標(biāo)系(2D):通常以圖像的左上角為坐標(biāo)的原點(diǎn),u軸從左到右與x軸平行,v軸從上到下與y軸平行;

我們?cè)O(shè)像素坐標(biāo)軸同時(shí)在u軸和v軸縮放了S的倍數(shù),倍數(shù)定義為相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔,即u軸縮放了α倍,v軸縮放了β倍;同時(shí),原點(diǎn)坐標(biāo)也平移了C個(gè)像素點(diǎn),即相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔,在與上一步求解的點(diǎn)相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔的坐標(biāo)關(guān)系如下:

相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔

相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔

將上一步以相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔關(guān)系得出的小孔模型公式代入可得:

相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔

相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔

我們令相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔,可得:

相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔

相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔

我們將方程組寫(xiě)成齊次坐標(biāo)的形式:

相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔

我們可以把z挪到左邊得到:

相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔

并且,令相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔,相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔

可得簡(jiǎn)化的表達(dá)式:相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔

通過(guò)上面的推導(dǎo),我們已經(jīng)計(jì)算出了相機(jī)內(nèi)參(Camera Intrinsics)內(nèi)參矩陣K,通常在實(shí)際項(xiàng)目中該內(nèi)參的得出方式通常需要標(biāo)定,標(biāo)定的方式后面等到具體實(shí)踐再進(jìn)行整理。

相機(jī)外參

簡(jiǎn)單的描述一下相機(jī)的外參:相機(jī)的外參主要描述的是相機(jī)在三維場(chǎng)景下的位置以及鏡頭朝向,通常以一個(gè)旋轉(zhuǎn)矩陣R平移向量t進(jìn)行表示,描述了相機(jī)的位置、方向和觀察角度,決定了相機(jī)從哪個(gè)角度觀察場(chǎng)景。

在上面的推導(dǎo)過(guò)程中,我們已經(jīng)求出了坐標(biāo)系之間的關(guān)系以及內(nèi)參矩陣,其中內(nèi)參矩陣是通過(guò)相機(jī)坐標(biāo)系與像素坐標(biāo)之間的關(guān)系得出,所以我們這步需要通過(guò)世界坐標(biāo)系與相機(jī)坐標(biāo)系之間的關(guān)系來(lái)推導(dǎo)相機(jī)外參,并記錄過(guò)程。

根據(jù)上面描述的內(nèi)容,我們繼續(xù)以上述為例,設(shè)相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔是在相機(jī)坐標(biāo)系的點(diǎn),相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔是在世界坐標(biāo)系下的點(diǎn),我們可以使用一個(gè)旋轉(zhuǎn)矩陣相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔和一個(gè)平移向量相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔,把相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔變換到相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔,即:

相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔

其中,相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔是一個(gè)3x3的旋轉(zhuǎn)矩陣,相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔是一個(gè)3x1的平移向量,我們將其使用其次坐標(biāo)表達(dá):

相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔

可以改變式子,把加號(hào)也干掉:

相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔

所以將旋轉(zhuǎn)矩陣相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔和平移向量相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔帶入到上述公式可得:

相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔

所以我們可以使用該矩陣來(lái)表示相機(jī)的外參:

相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔

內(nèi)參與外參組合使用

由于上述內(nèi)容可得知:

相機(jī)外參公式:相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔

相機(jī)內(nèi)參公式:相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔

則將外參公式帶入內(nèi)參可得如下結(jié)果:

相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔

代碼示例

完成上述公式的推導(dǎo)后,使用Python環(huán)境下進(jìn)行實(shí)際操作一下,僅使用numpy的ndarray作為數(shù)據(jù)結(jié)構(gòu)和opencv的繪圖工具以及solvePnP來(lái)驗(yàn)證相機(jī)外參解法。

首先我們需要先定義一個(gè)被觀測(cè)的目標(biāo),并將其定義在世界坐標(biāo)中;這里我們就選擇使用一個(gè)立方體作為觀測(cè)目標(biāo):


import cv2
import numpy as np

# 定義方形畫(huà)布像素坐標(biāo)長(zhǎng)度
canvas_square_size = 320
# 定義立方體的邊長(zhǎng)
length = 1

# 定義立方體的8個(gè)頂點(diǎn)坐標(biāo) 使用世界坐標(biāo)作為表達(dá)
vertices_w = np.array([
    [-length / 2, -length / 2, -length / 2],
    [-length / 2, -length / 2, length / 2],
    [-length / 2, length / 2, -length / 2],
    [-length / 2, length / 2, length / 2],
    [length / 2, -length / 2, -length / 2],
    [length / 2, -length / 2, length / 2],
    [length / 2, length / 2, -length / 2],
    [length / 2, length / 2, length / 2]])
print("像素坐標(biāo)系頂點(diǎn)集合: ", vertices_uv.shape)
# 打印結(jié)果:
# 世界坐標(biāo)系頂點(diǎn)集合:  (8, 3)

定義好世界坐標(biāo)下的立方體后,我們來(lái)手動(dòng)定義一組相機(jī)外參,上述提到過(guò),相機(jī)外參是由一個(gè)旋轉(zhuǎn)矩陣R和一個(gè)平移向量t組成,這里我們利用旋轉(zhuǎn)矩陣的特性,定義一個(gè)攜帶讓其沿著roll軸旋轉(zhuǎn)一定角度的RulerAngle屬性的旋轉(zhuǎn)矩陣R_roll,并手動(dòng)設(shè)置一個(gè)t向量;使用世界坐標(biāo)系對(duì)其進(jìn)行變換得出相機(jī)坐標(biāo)系頂點(diǎn)集,即使用公式:相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔,求解步驟代碼如下:


# 定義一個(gè)角度
a = 45
# 轉(zhuǎn)換為弧度制
a = np.deg2rad(a)

# 手動(dòng)定一個(gè)相機(jī)外參R旋轉(zhuǎn)矩陣,并設(shè)置讓其繞roll軸旋轉(zhuǎn)a度
R_roll = np.array([
    [1, 0, 0],
    [0, np.cos(a), -np.sin(a)],
    [0, np.sin(a), np.cos(a)]
])
# 手動(dòng)定一個(gè)相機(jī)外參的偏移向量t 即在x, y, z的位置看面朝單位
t1 = 0
t2 = 0
t3 = 5  # 數(shù)值越大則距離觀測(cè)目標(biāo)距離則越長(zhǎng)
T = np.array([t1, t2, t3])

# 求基于相機(jī)坐標(biāo)系的頂點(diǎn)集
vertices_c = np.matmul(R_roll, vertices_w.T).T + T

再求出新的點(diǎn)集后,我們手動(dòng)定義一組相機(jī)內(nèi)參的K矩陣,并將中心點(diǎn)設(shè)置在像素坐標(biāo)系中畫(huà)布的中心點(diǎn),以便我們可視化時(shí)可能更清晰的觀測(cè)到目標(biāo);定義內(nèi)參K矩陣后,我們定義一個(gè)透視投影函數(shù),用于將三維的坐標(biāo)系投影到像素坐標(biāo)系中,即公式:相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔,函數(shù)定義如下:


def perspective_projection(vertices, K):
    """use perspective projection"""
    vertices_2d = np.matmul(K, vertices.T).T
    vertices_2d[:, 0] /= vertices_2d[:, 2]
    vertices_2d[:, 1] /= vertices_2d[:, 2]
    vertices_2d = vertices_2d[:, :2].astype(np.int32)

    return vertices_2d

定義好函數(shù)perspective_projection后,我們?cè)谥鞒绦蛑欣^續(xù)定義我們的內(nèi)參矩陣K,并使用函數(shù)進(jìn)行坐標(biāo)轉(zhuǎn)換:


# 手動(dòng)定一組相機(jī)內(nèi)參K
fx = 800
fy = 800
cx = canvas_square_size // 2
cy = canvas_square_size // 2
K = np.array([
    [fx, 0, cx],
    [0, fy, cy],
    [0, 0, 1]
])

# 使用透視投影解出像素坐標(biāo)的頂點(diǎn)集
vertices_uv = perspective_projection(vertices_c, K)
print("像素坐標(biāo)系頂點(diǎn)集合: ", vertices_uv.shape)
# 打印結(jié)果:
# 世界坐標(biāo)系頂點(diǎn)集合:  (8, 3)

完成像素坐標(biāo)系的轉(zhuǎn)換后,我們準(zhǔn)備一個(gè)繪制函數(shù),用來(lái)顯示我們的處理結(jié)果,將投影后的像素坐標(biāo)系顯示出來(lái):


def display_vertices_uv(vertices_2d, win_name='vertices', wait_key=0, canvas_size=(320, 320)):
    """Show the vertices on uv-coordinates"""
    img = np.zeros((canvas_size[0], canvas_size[1], 3), dtype=np.uint8)
    edges = np.array([
        [0, 1], [0, 2], [0, 4],
        [1, 3], [1, 5],
        [2, 3], [2, 6],
        [4, 5], [4, 6],
        [7, 5], [7, 6], [7, 3]])

    for edge in edges:
        pt1 = tuple(vertices_2d[edge[0]])
        pt2 = tuple(vertices_2d[edge[1]])
        cv2.line(img, pt1, pt2, (0, 255, 255), 2)

    cv2.imshow(win_name, img)
    cv2.waitKey(wait_key)

定義好函數(shù)后,我們回到主程序運(yùn)行代碼顯示結(jié)果:


# 顯示求解后的uv頂點(diǎn)集
display_vertices_uv(vertices_uv, canvas_size=(canvas_square_size, canvas_square_size))

結(jié)果如下:

相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔

可以看到我們已經(jīng)成功的使用自己定義的模擬相機(jī)內(nèi)外參去對(duì)該立方體進(jìn)行世界坐標(biāo)轉(zhuǎn)換到像素坐標(biāo),并成功可視化觀測(cè)到這個(gè)立方體。

這里我們將相機(jī)通過(guò)外參矩陣R的形式設(shè)置的是把相機(jī)擺放在一個(gè)以roll轉(zhuǎn)角45度的觀測(cè)角度,為了以更加豐富的角度觀測(cè)到這個(gè)立方體,我們可以在roll轉(zhuǎn)角45度的情況下,再加入另外一種歐拉角屬性pitch,使其可以添加一種新的角度去觀測(cè)該對(duì)象,代碼如下:


# 再定義一組旋轉(zhuǎn)矩陣,以pitch軸進(jìn)行b度旋轉(zhuǎn)
b = 25
b = np.deg2rad(b)
R_pitch = np.array([
    [0, np.cos(b), -np.sin(b)],
    [1, 0, 0],
    [0, np.sin(b), np.cos(b)]
])
# 重新調(diào)整一下外參的旋轉(zhuǎn)矩陣R
R = np.matmul(R_roll, R_pitch)
# 重新求基于相機(jī)坐標(biāo)系的頂點(diǎn)集 加入yaw旋轉(zhuǎn)角
vertices_c_pitch = np.matmul(R, vertices_w.T).T + T
# 繼續(xù)使用內(nèi)參K透視投影解出像素坐標(biāo)的頂點(diǎn)集
vertices_uv_pitch = perspective_projection(vertices_c_pitch, K)
# 顯示求解后的uv頂點(diǎn)集
display_vertices_uv(vertices_uv_pitch)

通過(guò)代碼可得知我們?cè)谥匦露x了一個(gè)外參矩陣R,是將之前定義的外參矩陣R_roll與當(dāng)前新定義的R_pitch進(jìn)行一個(gè)線性變換處理所得出的結(jié)果,其目的是讓機(jī)位角在roll軸旋轉(zhuǎn)45度的情況下再對(duì)其pitch軸旋轉(zhuǎn)25度,得出該外參矩陣并進(jìn)行坐標(biāo)轉(zhuǎn)換,結(jié)果如下:

相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔

可以看到我們能觀測(cè)到的立方體視角更加豐富了

示例2:使用解PnP求出外參矩陣

通過(guò)上述的案例,我們手動(dòng)定義了相機(jī)的內(nèi)外參矩陣,這里補(bǔ)充一點(diǎn),在知道觀測(cè)目標(biāo)的世界坐標(biāo)與相機(jī)內(nèi)參的情況下,我們是可以使用一些數(shù)學(xué)手段去解出相機(jī)的外參矩陣的,這里采用的方法是使用opencv提供的solvePnP解法,去解出外參矩陣,接續(xù)上一個(gè)案例下進(jìn)行代碼的補(bǔ)充即可,代碼如下:


# 使用solvePnP嘗試解出相機(jī)外參
rvec = np.zeros((3, 1))
tvec = np.zeros((3, 1))

retval, rvec, tvec = cv2.solvePnP(vertices_w.astype(np.float32), vertices_uv_pitch.astype(np.float32),
                                  K.astype(np.float32),
                                  None, rvec, tvec, False, cv2.SOLVEPNP_ITERATIVE)
R_solved, _ = cv2.Rodrigues(rvec)
print("解PnP得出的R Matrix: ", -R_solved)    # 解出的坐標(biāo)系是反著需要自行調(diào)整
print("自己定的R Matrix: ", R)

# 打印結(jié)果:
# 解PnP得出的R Matrix:  [[ 1.27441147e-04  9.06220345e-01 -4.22805713e-01]
#  [ 7.06805406e-01 -2.99177784e-01 -6.41029463e-01]
#  [ 7.07408017e-01  2.98759670e-01  6.40559566e-01]]
# 自己定的R Matrix:  [[ 0.          0.90630779 -0.42261826]
#  [ 0.70710678 -0.29883624 -0.64085638]
#  [ 0.70710678  0.29883624  0.64085638]]

可以看到,使用solvePnP解出的外參矩陣R與我們自行定義的矩陣R基本相等,該結(jié)果的精度與觀測(cè)目標(biāo)的頂點(diǎn)數(shù)量有關(guān),頂點(diǎn)越多精度會(huì)越高。

示例3:旋轉(zhuǎn)的立方體

通過(guò)上面的案例,我們可以寫(xiě)一個(gè)小玩意,通過(guò)不斷的改變相機(jī)外參來(lái)實(shí)時(shí)更新并顯示出被觀測(cè)對(duì)象的畫(huà)面,可讓立方體仿佛動(dòng)起來(lái)一樣,代碼如下:


# 定義方形畫(huà)布像素坐標(biāo)長(zhǎng)度
canvas_square_size = 320
# 定義立方體的邊長(zhǎng)
length = 1

# 定義立方體的8個(gè)頂點(diǎn)坐標(biāo)
vertices_w = np.array([
    [-length / 2, -length / 2, -length / 2],
    [-length / 2, -length / 2, length / 2],
    [-length / 2, length / 2, -length / 2],
    [-length / 2, length / 2, length / 2],
    [length / 2, -length / 2, -length / 2],
    [length / 2, -length / 2, length / 2],
    [length / 2, length / 2, -length / 2],
    [length / 2, length / 2, length / 2]])

# 手動(dòng)定一組相機(jī)內(nèi)參K
fx = 800
fy = 800
cx = canvas_square_size // 2
cy = canvas_square_size // 2
K = np.array([
    [fx, 0, cx],
    [0, fy, cy],
    [0, 0, 1]
])

# 初始化角度
a = 0
while True:
    # 手動(dòng)定一個(gè)相機(jī)外參R旋轉(zhuǎn)矩陣,并設(shè)置讓三個(gè)軸旋轉(zhuǎn)a度
    R = construct_extrinsic_matrix_R(a, a, a)

    # 手動(dòng)定一個(gè)相機(jī)外參的偏移向量t 即在x, y, z的位置看面朝單位
    t1 = 0
    t2 = 0
    t3 = 5  # 數(shù)值越大則距離觀測(cè)目標(biāo)距離則越長(zhǎng)
    T = np.array([t1, t2, t3])
    # 求基于相機(jī)坐標(biāo)系的頂點(diǎn)集
    vertices_c = np.matmul(R, vertices_w.T).T + T
    # 使用透視投影解出像素坐標(biāo)的頂點(diǎn)集
    vertices_uv = perspective_projection(vertices_c, K)
    # 顯示求解后的uv頂點(diǎn)集
    display_vertices_uv(vertices_uv, wait_key=30, canvas_size=(canvas_square_size, canvas_square_size))
    a += 1

結(jié)果如下:

相機(jī)內(nèi)參,3D視覺(jué)學(xué)習(xí),算法,圖形,圖像算法,相機(jī)內(nèi)參,相機(jī)外參,Powered by 金山文檔

完整代碼:

所有示例的完整代碼如下:


import cv2
import numpy as np


def display_vertices_uv(vertices_2d, win_name='vertices', wait_key=0, canvas_size=(320, 320)):
    """Show the vertices on uv-coordinates"""
    img = np.zeros((canvas_size[0], canvas_size[1], 3), dtype=np.uint8)
    edges = np.array([
        [0, 1], [0, 2], [0, 4],
        [1, 3], [1, 5],
        [2, 3], [2, 6],
        [4, 5], [4, 6],
        [7, 5], [7, 6], [7, 3]])

    for edge in edges:
        pt1 = tuple(vertices_2d[edge[0]])
        pt2 = tuple(vertices_2d[edge[1]])
        cv2.line(img, pt1, pt2, (0, 255, 255), 2)

    cv2.imshow(win_name, img)
    cv2.waitKey(wait_key)


def perspective_projection(vertices, K):
    """use perspective projection"""
    vertices_2d = np.matmul(K, vertices.T).T
    vertices_2d[:, 0] /= vertices_2d[:, 2]
    vertices_2d[:, 1] /= vertices_2d[:, 2]
    vertices_2d = vertices_2d[:, :2].astype(np.int32)

    return vertices_2d


def construct_extrinsic_matrix_R(yaw_angle, roll_angle, pitch_angle):
    """Construct the camera external parameter rotation matrix R"""
    yaw = np.deg2rad(yaw_angle)
    roll = np.deg2rad(roll_angle)
    pitch = np.deg2rad(pitch_angle)
    R_yaw = np.array([
        [np.cos(yaw), -np.sin(yaw), 0],
        [np.sin(yaw), np.cos(yaw), 0],
        [0, 0, 1]
    ])
    R_roll = np.array([
        [1, 0, 0],
        [0, np.cos(roll), -np.sin(roll)],
        [0, np.sin(roll), np.cos(roll)]
    ])
    R_pitch = np.array([
        [0, np.cos(pitch), -np.sin(pitch)],
        [1, 0, 0],
        [0, np.sin(pitch), np.cos(pitch)]
    ])
    R = np.matmul(R_pitch, np.matmul(R_yaw, R_roll))

    return R


def sample_a():
    # 定義方形畫(huà)布像素坐標(biāo)長(zhǎng)度
    canvas_square_size = 320
    # 定義立方體的邊長(zhǎng)
    length = 1

    # 定義立方體的8個(gè)頂點(diǎn)坐標(biāo) 使用世界坐標(biāo)作為表達(dá)
    vertices_w = np.array([
        [-length / 2, -length / 2, -length / 2],
        [-length / 2, -length / 2, length / 2],
        [-length / 2, length / 2, -length / 2],
        [-length / 2, length / 2, length / 2],
        [length / 2, -length / 2, -length / 2],
        [length / 2, -length / 2, length / 2],
        [length / 2, length / 2, -length / 2],
        [length / 2, length / 2, length / 2]])
    print("世界坐標(biāo)系頂點(diǎn)集合: ", vertices_w.shape)

    # 定義一個(gè)角度
    a = 45
    # 轉(zhuǎn)換為弧度制
    a = np.deg2rad(a)

    # 手動(dòng)定一個(gè)相機(jī)外參R旋轉(zhuǎn)矩陣,并設(shè)置讓其繞roll軸旋轉(zhuǎn)a度
    R_roll = np.array([
        [1, 0, 0],
        [0, np.cos(a), -np.sin(a)],
        [0, np.sin(a), np.cos(a)]
    ])
    # 手動(dòng)定一個(gè)相機(jī)外參的偏移向量t 即在x, y, z的位置看面朝單位
    t1 = 0
    t2 = 0
    t3 = 5  # 數(shù)值越大則距離觀測(cè)目標(biāo)距離則越長(zhǎng)
    T = np.array([t1, t2, t3])

    # 求基于相機(jī)坐標(biāo)系的頂點(diǎn)集
    vertices_c = np.matmul(R_roll, vertices_w.T).T + T

    # 手動(dòng)定一組相機(jī)內(nèi)參K
    fx = 800
    fy = 800
    cx = canvas_square_size // 2
    cy = canvas_square_size // 2
    K = np.array([
        [fx, 0, cx],
        [0, fy, cy],
        [0, 0, 1]
    ])

    # 使用透視投影解出像素坐標(biāo)的頂點(diǎn)集
    vertices_uv = perspective_projection(vertices_c, K)
    print("像素坐標(biāo)系頂點(diǎn)集合: ", vertices_uv.shape)

    # 顯示求解后的uv頂點(diǎn)集
    display_vertices_uv(vertices_uv, canvas_size=(canvas_square_size, canvas_square_size))

    # 再定義一組旋轉(zhuǎn)矩陣,以pitch軸進(jìn)行b度旋轉(zhuǎn)
    b = 25
    b = np.deg2rad(b)
    R_pitch = np.array([
        [0, np.cos(b), -np.sin(b)],
        [1, 0, 0],
        [0, np.sin(b), np.cos(b)]
    ])
    # 重新調(diào)整一下外參的旋轉(zhuǎn)矩陣R
    R = np.matmul(R_roll, R_pitch)
    # 重新求基于相機(jī)坐標(biāo)系的頂點(diǎn)集 加入yaw旋轉(zhuǎn)角
    vertices_c_pitch = np.matmul(R, vertices_w.T).T + T
    # 繼續(xù)使用內(nèi)參K透視投影解出像素坐標(biāo)的頂點(diǎn)集
    vertices_uv_pitch = perspective_projection(vertices_c_pitch, K)
    # 顯示求解后的uv頂點(diǎn)集
    display_vertices_uv(vertices_uv_pitch)

    # 使用solvePnP嘗試解出相機(jī)外參
    rvec = np.zeros((3, 1))
    tvec = np.zeros((3, 1))

    retval, rvec, tvec = cv2.solvePnP(vertices_w.astype(np.float32), vertices_uv_pitch.astype(np.float32),
                                      K.astype(np.float32),
                                      None, rvec, tvec, False, cv2.SOLVEPNP_ITERATIVE)
    R_solved, _ = cv2.Rodrigues(rvec)
    print("解PnP得出的R Matrix: ", -R_solved)   # 解出的坐標(biāo)系是反著需要自行調(diào)整
    print("自己定的R Matrix: ", R)


def sample_b():
    # 定義方形畫(huà)布像素坐標(biāo)長(zhǎng)度
    canvas_square_size = 320
    # 定義立方體的邊長(zhǎng)
    length = 1

    # 定義立方體的8個(gè)頂點(diǎn)坐標(biāo)
    vertices_w = np.array([
        [-length / 2, -length / 2, -length / 2],
        [-length / 2, -length / 2, length / 2],
        [-length / 2, length / 2, -length / 2],
        [-length / 2, length / 2, length / 2],
        [length / 2, -length / 2, -length / 2],
        [length / 2, -length / 2, length / 2],
        [length / 2, length / 2, -length / 2],
        [length / 2, length / 2, length / 2]])

    # 手動(dòng)定一組相機(jī)內(nèi)參K
    fx = 800
    fy = 800
    cx = canvas_square_size // 2
    cy = canvas_square_size // 2
    K = np.array([
        [fx, 0, cx],
        [0, fy, cy],
        [0, 0, 1]
    ])

    # 初始化角度
    a = 0
    while True:
        # 手動(dòng)定一個(gè)相機(jī)外參R旋轉(zhuǎn)矩陣,并設(shè)置讓三個(gè)軸旋轉(zhuǎn)a度
        R = construct_extrinsic_matrix_R(a, a, a)

        # 手動(dòng)定一個(gè)相機(jī)外參的偏移向量t 即在x, y, z的位置看面朝單位
        t1 = 0
        t2 = 0
        t3 = 5  # 數(shù)值越大則距離觀測(cè)目標(biāo)距離則越長(zhǎng)
        T = np.array([t1, t2, t3])
        # 求基于相機(jī)坐標(biāo)系的頂點(diǎn)集
        vertices_c = np.matmul(R, vertices_w.T).T + T
        # 使用透視投影解出像素坐標(biāo)的頂點(diǎn)集
        vertices_uv = perspective_projection(vertices_c, K)
        # 顯示求解后的uv頂點(diǎn)集
        display_vertices_uv(vertices_uv, wait_key=30, canvas_size=(canvas_square_size, canvas_square_size))
        a += 1


if __name__ == '__main__':
    sample_a()  # 示例1
    sample_b()  # 示例2

Note:

由于忘性較大,倉(cāng)促實(shí)驗(yàn)和匆忙記錄只為記錄自己的理解和實(shí)驗(yàn)經(jīng)過(guò)留后期繼續(xù)學(xué)習(xí)和觀看,可能會(huì)有不少理解錯(cuò)誤,如果給您帶來(lái)困擾煩請(qǐng)指正和海涵。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-610356.html

到了這里,關(guān)于關(guān)于相機(jī)內(nèi)參與外參的淺讀的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 計(jì)算機(jī)視覺(jué)(相機(jī)標(biāo)定;內(nèi)參;外參;畸變系數(shù))

    計(jì)算機(jī)視覺(jué)(相機(jī)標(biāo)定;內(nèi)參;外參;畸變系數(shù))

    目錄 一、預(yù)備知識(shí) 1、坐標(biāo)系變換過(guò)程(相機(jī)成像過(guò)程) (1)相機(jī)坐標(biāo)系轉(zhuǎn)換為圖像坐標(biāo)系(透視投影變換遵循的是針孔成像原理) (2)齊次坐標(biāo)的引入原因:(為什么引入齊次坐標(biāo)???) 2、內(nèi)參與外參矩陣的構(gòu)成 3、畸變參數(shù) 二、相機(jī)標(biāo)定 1、張正友標(biāo)定法(光學(xué)標(biāo)

    2024年02月07日
    瀏覽(23)
  • (九)相機(jī)內(nèi)參、外參、反透視變換python  opencv

    (九)相機(jī)內(nèi)參、外參、反透視變換python opencv

    任務(wù)需求:將相機(jī)上的一個(gè)點(diǎn)投影到真實(shí)世界平面上去。 原則上單目相機(jī)是不可以的,因?yàn)橹挥涗浟硕S信息,真實(shí)世界是三維的,雙目相機(jī)可以通過(guò)視差,或者單目+IMU組合,但是 由于特征點(diǎn)在地面上的先驗(yàn)知識(shí) ,因此可以進(jìn)行反透視變換。方法有很多種那個(gè),這里采用計(jì)

    2024年02月06日
    瀏覽(35)
  • 一文理清相機(jī)內(nèi)參和外參矩陣的來(lái)龍去脈 -- review向

    一文理清相機(jī)內(nèi)參和外參矩陣的來(lái)龍去脈 -- review向

    Auther:SeaHIRobot date: 2023-05-03 最近在做一門(mén)課程的項(xiàng)目,在pybullet中復(fù)現(xiàn)GGCNN的機(jī)械臂視覺(jué)抓取的深度學(xué)習(xí)網(wǎng)絡(luò)。在搭建仿真環(huán)境時(shí),又回到了繞不開(kāi)的相機(jī)內(nèi)參和外參。借此機(jī)會(huì)對(duì)相機(jī)內(nèi)參外參這一套進(jìn)行一個(gè)review,對(duì)這個(gè)問(wèn)題進(jìn)行一個(gè)邏輯梳理。 因此本文不建議純小白閱讀

    2024年02月04日
    瀏覽(21)
  • 使用ROS功能包c(diǎn)amera_calibration進(jìn)行單目相機(jī)和雙目相機(jī)的內(nèi)參和外參標(biāo)定

    使用ROS功能包c(diǎn)amera_calibration進(jìn)行單目相機(jī)和雙目相機(jī)的內(nèi)參和外參標(biāo)定

    本文總結(jié)使用ROS標(biāo)定單目和雙目相機(jī)的過(guò)程,同時(shí)提供生成棋盤(pán)格文件的方法。 參考鏈接: [1]使用ros標(biāo)定相機(jī)的內(nèi)參和外參 [2]ROS下采用camera_calibration進(jìn)行雙目相機(jī)標(biāo)定 棋盤(pán)格可以自己買(mǎi)一個(gè),或者打印一個(gè)粘在板子上,棋盤(pán)格電子版生成可以參考博客《使用kalibr標(biāo)定工具進(jìn)

    2024年02月11日
    瀏覽(27)
  • 數(shù)字圖像處理 --- 相機(jī)的內(nèi)參與外參(CV學(xué)習(xí)筆記)

    數(shù)字圖像處理 --- 相機(jī)的內(nèi)參與外參(CV學(xué)習(xí)筆記)

    Pinhole Camera Model(針孔相機(jī)模型) ????????針孔相機(jī)是一種沒(méi)有鏡頭、只有一個(gè)小光圈的簡(jiǎn)單相機(jī)。 光線穿過(guò)光圈并在相機(jī)的另一側(cè)呈現(xiàn)倒立的圖像。為了建模方便,我們可以把 物理成像平面 (image plane)上的圖像移到 實(shí)際場(chǎng)景 (3D object)和 焦點(diǎn) (focal point)之間,把他想象成

    2024年02月12日
    瀏覽(26)
  • c++學(xué)習(xí)【13】3D-2D高斯牛頓BA迭代求解相機(jī)外參

    pc表示當(dāng)前坐標(biāo), 通過(guò)將 points_3d[i] 與 pose 相乘,得到的結(jié)果 pc 是該點(diǎn)在相機(jī)坐標(biāo)系下的表示。 proj 是一個(gè)二維向量,表示在相機(jī)坐標(biāo)系下,通過(guò)相機(jī)投影將三維點(diǎn)投影到二維平面上得到的坐標(biāo)。 inv_z在綁定調(diào)整迭代求解相機(jī)位姿中,用于后續(xù)的優(yōu)化目標(biāo)函數(shù)計(jì)算或者高斯牛

    2024年02月11日
    瀏覽(21)
  • 標(biāo)定(內(nèi)參、外參)

    在計(jì)算機(jī)視覺(jué)中,特別是在相機(jī)標(biāo)定和立體視覺(jué)領(lǐng)域,內(nèi)參(intrinsic parameters)和外參(extrinsic parameters)是非常重要的概念。它們與相機(jī)的幾何屬性和姿態(tài)有關(guān)。 內(nèi)參(Intrinsic Parameters) : 內(nèi)參是描述相機(jī)內(nèi)部屬性的參數(shù),包括焦距、主點(diǎn)(光學(xué)中心)坐標(biāo)、畸變系數(shù)等。

    2024年02月14日
    瀏覽(25)
  • 激光雷達(dá)與相機(jī)外參標(biāo)定(附open3d python代碼)

    激光雷達(dá)與相機(jī)外參標(biāo)定(附open3d python代碼)

    現(xiàn)在的激光雷達(dá)與相機(jī)的標(biāo)定程序基本都是Ubuntu框架下面的,并且都是C++代碼,需要安裝的依賴也比較復(fù)雜,于是自己寫(xiě)了一個(gè)python版本的標(biāo)定程序,依賴非常簡(jiǎn)單,Windows系統(tǒng)也可以運(yùn)行。并且代碼簡(jiǎn)單一個(gè)文件搞定,符合python簡(jiǎn)單易行的風(fēng)格。 先上最后標(biāo)定后的效果圖?

    2024年02月11日
    瀏覽(17)
  • 形參與實(shí)參的主要區(qū)別

    形參與實(shí)參的主要區(qū)別

    形參(parameter) :形參(形式參數(shù))是在函數(shù)定義中出現(xiàn)的參數(shù),是一個(gè)虛擬參數(shù),調(diào)用之前并沒(méi)有給他分配內(nèi)存,可以看作是一個(gè)占位符,在函數(shù)定義時(shí)沒(méi)有實(shí)際的數(shù)值,只有在函數(shù)調(diào)用時(shí)才會(huì)接收到傳遞進(jìn)來(lái)的數(shù)據(jù);只是因?yàn)楹瘮?shù)需要從別處傳遞數(shù)據(jù),為了表示此數(shù)據(jù),

    2024年02月05日
    瀏覽(18)
  • 【相機(jī)標(biāo)定】相機(jī)內(nèi)參

    【相機(jī)標(biāo)定】相機(jī)內(nèi)參

    相機(jī)在計(jì)算機(jī)視覺(jué)方面的一些應(yīng)用一般需要相機(jī)標(biāo)定。我們總是聽(tīng)到標(biāo)定這個(gè)詞,那么具體標(biāo)定的是什么呢?相機(jī)的拍攝是一個(gè)三維到二維(透視投影)的過(guò)程,這個(gè)過(guò)程可以用數(shù)學(xué)模型去表述,標(biāo)定便是計(jì)算這個(gè)數(shù)學(xué)模型中的參數(shù),我們最終希望通過(guò)這些參數(shù)能夠從二維的

    2023年04月10日
    瀏覽(29)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包