zoukankan      html  css  js  c++  java
  • 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));

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

    小行星采样:

    广角镜头采样:

    局部平面投影采样:

  • 相关阅读:
    SDUT 1299 最长上升子序列
    HDU 1754 I Hate It
    SDUT 2080 最长公共子序列问题
    HDU 1102 Constructing Roads HDU1863 畅通工程
    HDU 1166 敌兵布阵
    HDU 1874 畅通工程续
    准备翻译Windows 8 动手实验系列教程
    Windows 8 动手实验系列教程 简介
    一起学Windows phone7开发(十九. Windows phone7发布)
    一起学Windows phone7(十六. windows phone 7 developer tool RTM 发布)
  • 原文地址:https://www.cnblogs.com/tiandsp/p/14382974.html
Copyright © 2011-2022 走看看