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));
下面我把不同投影的原图采样结果也贴上来吧,白色像素为采样点。
小行星采样:
广角镜头采样:
局部平面投影采样: