matlab練習程序(全景圖變換)


拿到一張全景圖,我們可以做一些變換將其投影到平面上。

比如可以投影到局部立方體平面、可以投影到類似行星效果的平面,還可以投影到類似超廣角像頭一樣的平面。

所有的投影方式基本是一致的,唯一的區別就是視點位置和視場角的大小。

比如我們有下面一張全景圖。

全景圖寬高比為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));

下面我把不同投影的原圖采樣結果也貼上來吧,白色像素為采樣點。

小行星采樣:

廣角鏡頭采樣:

局部平面投影采樣:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM