拿到一張全景圖,我們可以做一些變換將其投影到平面上。
比如可以投影到局部立方體平面、可以投影到類似行星效果的平面,還可以投影到類似超廣角像頭一樣的平面。
所有的投影方式基本是一致的,唯一的區別就是視點位置和視場角的大小。
比如我們有下面一張全景圖。
全景圖寬高比為2:1,可以認為是球坐標系下的theta角和fi角,或者直接認為是經緯度也行。范圍寬是0-2PI,高是0-PI。
我們可以通過變換生成類似下面的圖像。
小行星:
廣角鏡頭:
局部平面(生成6張貼到立方體上就有街景效果):
下面介紹投影方法。
1. 首先我們可以認為將全景圖投影到球坐標系上。
2. 可以設定一個視點和一個投影平面。
3. 局部平面投影視點設為(0,0,0),廣角鏡頭視點可以設為(0,0,-1000000),總之z就是一個很遠的值就行,小行星視點可以設為(0,0,-1)。投影平面統一設為z=1且x,y大小均為1的正方形平面。
4. 遍歷投影平面坐標,連接平面坐標與視點坐標,生成視向量。
5. 計算視向量與球的交點,並且得到距離平面近的交點坐標(x,y,z)。
6. 根據球旋轉參數(roll,pitch,yaw),對(x,y,z)進行旋轉得到(x',y',z')。
7. 根據球坐標公式計算(x',y',z')對應的theta角和fi角。
8. 根據theta角和fi角去原始圖像中找到對應像素即可。
matlab代碼如下:
clear all; close all; clc; img = imread('pano.jpg'); [panoH,panoW,~] = size(img); imgre = zeros(300,300,3); [h,w,~] = size(imgre); imgb = img; x = 0*pi/180; %定義三維球roll,pitch和yaw,改變能夠得到不同方向的投影圖 y = 0*pi/180; z = 180*pi/180; Rx = [cos(x) -sin(x) 0; sin(x) cos(x) 0; 0 0 1]; Ry= [cos(y) 0 sin(y); 0 1 0; -sin(y) 0 cos(y)]; Rz = [1 0 0; 0 cos(z) -sin(z); 0 sin(z) cos(z)]; R = Rz*Ry*Rx; %觀察原點 %局部平面設為(0,0,0) %小行星設為(0,0,-1) %廣角設為(0,0,-1000000) cent = [0 0 0]; %投影平面縮放系數,cent為[0 0 0]時,同時該值為1時,fov為90度 %局部平面和廣角設為1. %小行星可以設為3,增大視場角 coeff = 1; for i=1:h for j=1:w x = coeff*(i - w/2)/(w/2); %投影平面在三維空間坐標,z=1的平面 y = coeff*(j - h/2)/(h/2); z = 1; L = [x - cent(1) y - cent(2) z - cent(3)]; %連接投影平面與觀察點的向量 a = L(1)/norm(L); b = L(2)/norm(L); c = L(3)/norm(L); %計算光線向量與pano球交點,根據交點得到球坐標系theta和fi角 tmp = (2*a*x + 2*b*y + 2*c*z)^2 - 4*(-1 + x^2 + y^2 + z^2); if tmp>=0 k1 =(-2*a*x - 2*b*y - 2*c*z - sqrt(tmp))/2; k2 =(-2*a*x - 2*b*y - 2*c*z + sqrt(tmp))/2; x1 = k1*a+x; y1 = k1*b+y; z1 = k1*c+z; x2 = k2*a+x; y2 = k2*b+y; z2 = k2*c+z; if abs(k1)>abs(k2) x = x2;y = y2;z = z2; else x = x1;y = y1;z = z1; end newxyz = R*[x y z]'; x = newxyz(1); y = newxyz(2); z = newxyz(3); theta = acos(z); fi = atan2(y,x); if isnan(fi) fi = 0; end if (fi <= 0) fi = fi + 2*pi; end %知道theta和fi角后從原始pano圖中查找對應像素 X = floor(fi * panoW / (2*pi)); Y = floor(theta * panoH / pi); if (X < 1) X = 1; end if (Y < 1) Y = 1; end if (X > panoW) X = panoW; end if (Y > panoH) Y = panoH; end imgre(i,j,:) = img(floor(Y),floor(X),:); imgb(floor(Y),floor(X),:) = 255; %在原pano圖中顯示采樣用到的像素 end end end figure(1) imshow(uint8(imgre)); figure(2) imshow(uint8(imgb));
下面我把不同投影的原圖采樣結果也貼上來吧,白色像素為采樣點。
小行星采樣:
廣角鏡頭采樣:
局部平面投影采樣: