目錄
- part1 全景圖切割
- 1.1 邊緣剔除
- 1.2 圖像裁剪
- 1.3 完整代碼
- 1.4 其他幾組切割結(jié)果
- part2 盒圖展示
- 2.1 曲面繪制
- 2.2 視角調(diào)整
- 2.3 完整代碼
part1 全景圖切割
原圖:
![](/d/20211017/898ae664cb1a6ace0003b69da09a6519.gif)
切割效果:
![](/d/20211017/e1e3dee0f77a714d7ec204c3728ba0f2.gif)
![](/d/20211017/7c40a0bbebebaa3dbc03e7df309be135.gif)
以下是切割部分步驟:
舉這張圖為例,圖片格式hdr,jpg啥的都行:
![](/d/20211017/2dfd3a67787f756c548889603c861b8a.gif)
1.1 邊緣剔除
有些全景圖會(huì)自帶白灰色邊緣,若是直接進(jìn)行切割便會(huì)出現(xiàn)如下效果:
![](/d/20211017/183f74751638faca008e0780f84c218c.gif)
這時(shí)候我們首先要對(duì)原圖進(jìn)行白邊剔除,代碼如下:
oriPic=imread('test.hdr');
[rows,cols,~]=size(oriPic);
for i=cols:-1:1
tempListR=oriPic(floor(rows/4):ceil(3*rows/4),i,1);
tempListG=oriPic(floor(rows/4):ceil(3*rows/4),i,1);
tempListB=oriPic(floor(rows/4):ceil(3*rows/4),i,1);
if all(round(tempListR-mean(tempListR))==0)all(tempListR==tempListG)all(tempListR==tempListB)
oriPic(:,i,:)=[];
else
break;
end
end
oriPic=oriPic(:,end:-1:1,:);
for i=size(oriPic,2):-1:1
tempListR=oriPic(floor(rows/4):ceil(3*rows/4),i,1);
tempListG=oriPic(floor(rows/4):ceil(3*rows/4),i,1);
tempListB=oriPic(floor(rows/4):ceil(3*rows/4),i,1);
if all(round(tempListR-mean(tempListR))==0)all(tempListR==tempListG)all(tempListR==tempListB)
oriPic(:,i,:)=[];
else
break;
end
end
oriPic=oriPic(:,end:-1:1,:);
for i=rows:-1:1
tempListR=oriPic(i,floor(cols/4):ceil(3*cols/4),1);
tempListG=oriPic(i,floor(cols/4):ceil(3*cols/4),1);
tempListB=oriPic(i,floor(cols/4):ceil(3*cols/4),1);
if all(round(tempListR-mean(tempListR))==0)all(tempListR==tempListG)all(tempListR==tempListB)
oriPic(i,:,:)=[];
else
break;
end
end
oriPic=oriPic(end:-1:1,:,:);
for i=size(oriPic,1):-1:1
tempListR=oriPic(i,floor(cols/4):ceil(3*cols/4),1);
tempListG=oriPic(i,floor(cols/4):ceil(3*cols/4),1);
tempListB=oriPic(i,floor(cols/4):ceil(3*cols/4),1);
if all(round(tempListR-mean(tempListR))==0)all(tempListR==tempListG)all(tempListR==tempListB)
oriPic(i,:,:)=[];
else
break;
end
end
oriPic=oriPic(end:-1:1,:,:);
1.2 圖像裁剪
我們要讓完成的就是如下的變換和裁剪:
![](/d/20211017/f9944656073ae0bd4d09ac8d7a3999e4.gif)
![](/d/20211017/8ab1fc5784695d217293c932a7cdbcd3.gif)
這部分其實(shí)已經(jīng)有較為成熟的原理和代碼:
代碼參考:https://stackoverflow.com/questions/29678510/convert-21-equirectangular-panorama-to-cube-map
原理參考:
http://paulbourke.net/panorama/cubemaps/#1
http://paulbourke.net/panorama/cubemaps/
原理參考文章中更加清晰的變化圖:
![](/d/20211017/f295d7aeb55bdd0a5ca8d61274c786a0.gif)
另:
在參考代碼的基礎(chǔ)上,對(duì)映射像素進(jìn)行了插值處理,可以使圖像更加平滑,原理如下:
![](/d/20211017/2c9a7f27e3c0fb4453f15bf4bdc38e64.gif)
![](/d/20211017/6657d44cfd77214029f3e637fc3e6554.gif)
主要函數(shù)代碼:
function resultPic=createCubeMapFace(oriPic,id,height,width)
[M,N,~]=size(oriPic);
resultPic=zeros([height,width,3]);
an=sin(pi/4);
ak=cos(pi/4);
faceTransform=[0,0;
pi/2,0;
pi,0;
-pi/2,0;
0,-pi/2;
0,pi];
ftu=faceTransform(id,1);
ftv=faceTransform(id,2);
for y=0:height-1
for x=0:width-1
nx=y/height-0.5;
ny=x/width-0.5;
nx=nx*2*an;
ny=ny*2*an;
if (ftv == 0)
u=atan2(nx, ak);
v=atan2(ny*cos(u),ak);
u=u+ftu;
elseif(ftv>0)
d=sqrt(nx*nx+ny*ny);
v=pi/2-atan2(d,ak);
u=atan2(ny,nx);
else
d=sqrt(nx*nx+ny*ny);
v=-pi/2+atan2(d,ak);
u=atan2(-ny,nx);
end
u=u/(pi);
v=v/(pi/2);
while(v-1)
v=v+2;
u=u+1;
end
while(v>1)
v=v-2;
u=u+1;
end
while(u-1)
u=u+2;
end
while(u>1)
u=u-2;
end
u=u/2+0.5;
v=v/2+0.5;
u=u*(N-1)+1;
v=v*(M-1)+1;
fv=floor(v);fv1=floor(v)+1;pv=v-fv;fv1(fv1>M)=M;
fu=floor(u);fu1=floor(u)+1;pu=u-fu;fu1(fu1>N)=N;
resultPic(x+1,y+1,:)=double(oriPic(fv,fu,:)).*(1-pv).*(1-pu)+...
double(oriPic(fv1,fu,:)).*(pv).*(1-pu)+...
double(oriPic(fv,fu1,:)).*(1-pv).*(pu)+...
double(oriPic(fv1,fu1,:)).*(pv).*(pu);
end
end
resultPic=uint8(resultPic);
end
函數(shù)調(diào)用及圖像存儲(chǔ):
這里后面長寬數(shù)值可以任意設(shè)定,但是要求長寬數(shù)值一致,如果按照當(dāng)前寫法,結(jié)果被存儲(chǔ)至result文件夾:
if ~exist('result','dir')
mkdir('result');
end
for i=1:6
resultPic=createCubeMapFace(oriPic,i,500,500);
figure(i)
imshow(resultPic)
imwrite(resultPic,['result\',num2str(i),'.jpg'])
end
另: 如圖所示
圖片序號(hào)[1,2,3,4,5,6]分別對(duì)應(yīng)圖片[右,后,左,前,上,下]
![](/d/20211017/ffbcdb825241ee4d53cf3161f12d2ee0.gif)
1.3 完整代碼
function panoramic2box
oriPic=imread('889027-884424860.jpg');
[rows,cols,~]=size(oriPic);
for i=cols:-1:1
tempListR=oriPic(floor(rows/4):CEIL(3*rows/4),i,1);
tempListG=oriPic(floor(rows/4):CEIL(3*rows/4),i,1);
tempListB=oriPic(floor(rows/4):CEIL(3*rows/4),i,1);
if all(round(tempListR-mean(tempListR))==0)all(tempListR==tempListG)all(tempListR==tempListB)
oriPic(:,i,:)=[];
else
break;
end
end
oriPic=oriPic(:,end:-1:1,:);
for i=size(oriPic,2):-1:1
tempListR=oriPic(floor(rows/4):CEIL(3*rows/4),i,1);
tempListG=oriPic(floor(rows/4):CEIL(3*rows/4),i,1);
tempListB=oriPic(floor(rows/4):CEIL(3*rows/4),i,1);
if all(round(tempListR-mean(tempListR))==0)all(tempListR==tempListG)all(tempListR==tempListB)
oriPic(:,i,:)=[];
else
break;
end
end
oriPic=oriPic(:,end:-1:1,:);
for i=rows:-1:1
tempListR=oriPic(i,floor(cols/4):CEIL(3*cols/4),1);
tempListG=oriPic(i,floor(cols/4):CEIL(3*cols/4),1);
tempListB=oriPic(i,floor(cols/4):CEIL(3*cols/4),1);
if all(round(tempListR-mean(tempListR))==0)all(tempListR==tempListG)all(tempListR==tempListB)
oriPic(i,:,:)=[];
else
break;
end
end
oriPic=oriPic(end:-1:1,:,:);
for i=size(oriPic,1):-1:1
tempListR=oriPic(i,floor(cols/4):CEIL(3*cols/4),1);
tempListG=oriPic(i,floor(cols/4):CEIL(3*cols/4),1);
tempListB=oriPic(i,floor(cols/4):CEIL(3*cols/4),1);
if all(round(tempListR-mean(tempListR))==0)all(tempListR==tempListG)all(tempListR==tempListB)
oriPic(i,:,:)=[];
else
break;
end
end
oriPic=oriPic(end:-1:1,:,:);
% =========================================================================
if ~exist('result','dir')
mkdir('result');
end
for i=1:6
resultPic=createCubeMapFace(oriPic,i,500,500);
figure(i)
imshow(resultPic)
imwrite(resultPic,['result\',num2str(i),'.jpg'])
end
% =========================================================================
function resultPic=createCubeMapFace(oriPic,id,height,width)
[M,N,~]=size(oriPic);
resultPic=zeros([height,width,3]);
an=sin(pi/4);
ak=cos(pi/4);
faceTransform=[0,0;
pi/2,0;
pi,0;
-pi/2,0;
0,-pi/2;
0,pi];
ftu=faceTransform(id,1);
ftv=faceTransform(id,2);
for y=0:height-1
for x=0:width-1
nx=y/height-0.5;
ny=x/width-0.5;
nx=nx*2*an;
ny=ny*2*an;
if (ftv == 0)
u=atan2(nx, ak);
v=atan2(ny*cos(u),ak);
u=u+ftu;
elseif(ftv>0)
d=sqrt(nx*nx+ny*ny);
v=pi/2-atan2(d,ak);
u=atan2(ny,nx);
else
d=sqrt(nx*nx+ny*ny);
v=-pi/2+atan2(d,ak);
u=atan2(-ny,nx);
end
u=u/(pi);
v=v/(pi/2);
while(v-1)
v=v+2;
u=u+1;
end
while(v>1)
v=v-2;
u=u+1;
end
while(u-1)
u=u+2;
end
while(u>1)
u=u-2;
end
u=u/2+0.5;
v=v/2+0.5;
u=u*(N-1)+1;
v=v*(M-1)+1;
fv=floor(v);fv1=floor(v)+1;pv=v-fv;fv1(fv1>M)=M;
fu=floor(u);fu1=floor(u)+1;pu=u-fu;fu1(fu1>N)=N;
resultPic(x+1,y+1,:)=double(oriPic(fv,fu,:)).*(1-pv).*(1-pu)+...
double(oriPic(fv1,fu,:)).*(pv).*(1-pu)+...
double(oriPic(fv,fu1,:)).*(1-pv).*(pu)+...
double(oriPic(fv1,fu1,:)).*(pv).*(pu);
end
end
resultPic=uint8(resultPic);
end
end
1.4 其他幾組切割結(jié)果
圖片源自:https://www.cgmodel.com/article/9004.html
![](/d/20211017/0490ef9768e73e77257adb6a3e35d2fb.gif)
![](/d/20211017/4da0a027fc7c6a89a00b63b33b81a36c.gif)
![](/d/20211017/605175d2604407b52b88905947ad396f.gif)
![](/d/20211017/6e6cee225bff7a256ef0150fe0b0bff7.gif)
![](/d/20211017/70ac0968127db16572f51f43c08b77ce.gif)
![](/d/20211017/e82a2e8ea94fe396bb4aecfa6946cc37.gif)
part2 盒圖展示
2.1 曲面繪制
使用surf繪制各個(gè)曲面后,并為各個(gè)曲面貼圖:
for i=1:6
oriPic.(['p',num2str(i)])=imread(['result\',num2str(i),'.jpg']);
end
[rows,cols,~]=size(oriPic.p1);
[baseXY,baseZ]=meshgrid(1:cols,rows:-1:1);
ax=gca;hold(ax,'on')
surf(baseXY(:,end:-1:1)-(1+rows)/2,-(rows-1)./2.*ones(size(baseXY)),baseZ,'CData',oriPic.p1,'EdgeColor','none','FaceColor','interp')
surf(-(rows-1)./2.*ones(size(baseXY)),baseXY-(1+rows)/2,baseZ,'CData',oriPic.p2,'EdgeColor','none','FaceColor','interp')
surf(baseXY-(1+rows)/2,(rows-1)./2.*ones(size(baseXY)),baseZ,'CData',oriPic.p3,'EdgeColor','none','FaceColor','interp')
surf((rows-1)./2.*ones(size(baseXY)),baseXY(:,end:-1:1)-(1+rows)/2,baseZ,'CData',oriPic.p4,'EdgeColor','none','FaceColor','interp')
surf(baseXY'-(1+rows)/2,baseXY-(1+rows)/2,ones(size(baseXY)),'CData',oriPic.p6(end:-1:1,end:-1:1,:),'EdgeColor','none','FaceColor','interp')
surf(baseXY'-(1+rows)/2,baseXY-(1+rows)/2,rows-1+ones(size(baseXY)),'CData',oriPic.p5(:,end:-1:1,:),'EdgeColor','none','FaceColor','interp')
![](/d/20211017/23e076a59da2908f83066423ef0601e0.gif)
![](/d/20211017/c576803251a23f74e446d13e1bcb0e05.gif)
2.2 視角調(diào)整
通過設(shè)置axes屬性將視角調(diào)整至盒子里面
ax=axes('parent',fig,'position',[-0.45 -0.45 1.9 1.9]);hold(ax,'on')
ax.ZLim=[0,rows+1];
ax.XLim=[0-(1+rows)/2,rows+1-(1+rows)/2];
ax.YLim=[0-(1+rows)/2,rows+1-(1+rows)/2];
ax.Color=[0 0 0];
ax.CameraPosition=[0,0,rows/2];
ax.CameraPositionMode='manual';
ax.DataAspectRatio=[1,1,1];
ax.DataAspectRatioMode='manual';
ax.Projection='perspective';
ax.CameraTargetMode='manual';
ax.CameraViewAngle = 7;
ax.View=[-2.7391 90.0000];
ax.CameraTarget=[0 0 (rows-1)/2];
ax.Toolbar.Visible='on';
運(yùn)行后點(diǎn)擊那個(gè)三位旋轉(zhuǎn)按鈕即可開始漫游
![](/d/20211017/bf0f47a6f730b0b04911ca392ddd8894.gif)
此時(shí)的盒圖是無縫隙版本,有縫隙版放在后面
![](/d/20211017/353878ffd3a7ef5522f9c6916194e001.gif)
2.3 完整代碼
無縫隙版:
function showBox
for i=1:6
oriPic.(['p',num2str(i)])=imread(['result\',num2str(i),'.jpg']);
end
[rows,cols,~]=size(oriPic.p1);
[baseXY,baseZ]=meshgrid(1:cols,rows:-1:1);
fig=figure('units','pixels','position',[300 80 500 500],...
'Numbertitle','off','menubar','none','resize','off',...
'name','box');
ax=axes('parent',fig,'position',[-0.45 -0.45 1.9 1.9]);hold(ax,'on')
ax.ZLim=[0,rows+1];
ax.XLim=[0-(1+rows)/2,rows+1-(1+rows)/2];
ax.YLim=[0-(1+rows)/2,rows+1-(1+rows)/2];
ax.Color=[0 0 0];
ax.CameraPosition=[0,0,rows/2];
ax.CameraPositionMode='manual';
ax.DataAspectRatio=[1,1,1];
ax.DataAspectRatioMode='manual';
ax.Projection='perspective';
ax.CameraTargetMode='manual';
ax.CameraViewAngle = 7;
ax.View=[-2.7391 90.0000];
ax.CameraTarget=[0 0 (rows-1)/2];
ax.Toolbar.Visible='on';
surf(baseXY(:,end:-1:1)-(1+rows)/2,-(rows-1)./2.*ones(size(baseXY)),baseZ,'CData',oriPic.p1,'EdgeColor','none','FaceColor','interp')
surf(-(rows-1)./2.*ones(size(baseXY)),baseXY-(1+rows)/2,baseZ,'CData',oriPic.p2,'EdgeColor','none','FaceColor','interp')
surf(baseXY-(1+rows)/2,(rows-1)./2.*ones(size(baseXY)),baseZ,'CData',oriPic.p3,'EdgeColor','none','FaceColor','interp')
surf((rows-1)./2.*ones(size(baseXY)),baseXY(:,end:-1:1)-(1+rows)/2,baseZ,'CData',oriPic.p4,'EdgeColor','none','FaceColor','interp')
surf(baseXY'-(1+rows)/2,baseXY-(1+rows)/2,ones(size(baseXY)),'CData',oriPic.p6(end:-1:1,end:-1:1,:),'EdgeColor','none','FaceColor','interp')
surf(baseXY'-(1+rows)/2,baseXY-(1+rows)/2,rows-1+ones(size(baseXY)),'CData',oriPic.p5(:,end:-1:1,:),'EdgeColor','none','FaceColor','interp')
end
![](/d/20211017/f8d9f88f70b125a8e4e433c38b3441d0.gif)
有縫隙版:
function showBox2
for i=1:6
oriPic.(['p',num2str(i)])=imread(['result\',num2str(i),'.jpg']);
end
[rows,cols,~]=size(oriPic.p1);
[baseXY,baseZ]=meshgrid(1:cols,rows:-1:1);
fig=figure('units','pixels','position',[300 80 500 500],...
'Numbertitle','off','menubar','none','resize','off',...
'name','box');
ax=axes('parent',fig,'position',[-0.45 -0.45 1.9 1.9]);hold(ax,'on')
ax.ZLim=[0,rows+1];
ax.XLim=[0-(1+rows)/2,rows+1-(1+rows)/2];
ax.YLim=[0-(1+rows)/2,rows+1-(1+rows)/2];
ax.Color=[0 0 0];
ax.CameraPosition=[0,0,rows/2];
ax.CameraPositionMode='manual';
ax.DataAspectRatio=[1,1,1];
ax.DataAspectRatioMode='manual';
ax.Projection='perspective';
ax.CameraTargetMode='manual';
ax.CameraViewAngle = 7;
ax.View=[-2.7391 90.0000];
ax.CameraTarget=[0 0 (rows+1)/2];
ax.Toolbar.Visible='on';
surf(baseXY(:,end:-1:1)-rows/2,-rows./2.*ones(size(baseXY)),baseZ,'CData',oriPic.p1,'EdgeColor','none','FaceColor','interp')
surf(-rows./2.*ones(size(baseXY)),baseXY-(1+rows)/2,baseZ,'CData',oriPic.p2,'EdgeColor','none','FaceColor','interp')
surf(baseXY-(1+rows)/2,rows./2.*ones(size(baseXY)),baseZ,'CData',oriPic.p3,'EdgeColor','none','FaceColor','interp')
surf(rows./2.*ones(size(baseXY)),baseXY(:,end:-1:1)-(1+rows)/2,baseZ,'CData',oriPic.p4,'EdgeColor','none','FaceColor','interp')
surf(baseXY'-(1+rows)/2,baseXY-(1+rows)/2,zeros(size(baseXY)),'CData',oriPic.p6(end:-1:1,end:-1:1,:),'EdgeColor','none','FaceColor','interp')
surf(baseXY'-(1+rows)/2,baseXY-(1+rows)/2,rows+ones(size(baseXY)),'CData',oriPic.p5(:,end:-1:1,:),'EdgeColor','none','FaceColor','interp')
end
![](/d/20211017/97ff8fc4e8b66df9585486276f87f3bf.gif)
![](/d/20211017/9919ad35c571eed036ebfc3eabd939f7.gif)
以上就是MATLAB 全景圖切割及盒圖顯示的詳細(xì)內(nèi)容,更多關(guān)于MATLAB 全景圖的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
您可能感興趣的文章:- 在python中計(jì)算ssim的方法(與Matlab結(jié)果一致)
- 使用matlab或python將txt文件轉(zhuǎn)為excel表格
- 詳解python和matlab的優(yōu)勢(shì)與區(qū)別
- 實(shí)例詳解Matlab 與 Python 的區(qū)別
- python調(diào)用matlab的m自定義函數(shù)方法
- 詳解如何在python中讀寫和存儲(chǔ)matlab的數(shù)據(jù)文件(*.mat)
- 簡述:我為什么選擇Python而不是Matlab和R語言