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));

下面我把不同投影的原图采样结果也贴上来吧,白色像素为采样点。

小行星采样:

广角镜头采样:

局部平面投影采样:

posted @ 2021-02-06 21:14  Dsp Tian  阅读(1266)  评论(0编辑  收藏  举报