教你用Matlab制作立體動態相冊
效果
教程部分
1 圖片導入與大小重設
需要有一個名為album的文件夾和當前m文件在同一文件夾,另外ablum文件夾內至少要有一張jpg格式圖片
path='.\album\';%文件夾名稱 files=dir(fullfile(path,'*.jpg')); picNum=size(files,1); %遍歷路徑下每一幅圖像 for i=1:picNum fileName=strcat(path,files(i).name); img=imread(fileName); img=imresize(img,[120,120]); imgSet{i}=img; end
我們註意到,這裡用瞭一次imresize將突破變為120×120大小,這裡重設大小有三個作用:
- 將不是方形的圖片變為方形
- 將圖像設置固定大小,方便構造網格放置圖片
- 120×120的大小大約是能讓圖片表示清晰為前提下最小的大小,圖片太大的話運行會卡,太小的話不清晰
2 fig axes設置
% fig axes設置 fig=figure('units','pixels','position',[50 50 600 600],... 'Numbertitle','off','resize','off',... 'name','album3d','menubar','none'); ax=axes('parent',fig,'position',[-0.5 -0.5 2 2],... 'XLim', [-6 6],... 'YLim', [-6 6],... 'ZLim', [-6 6],... 'Visible','on',... 'XTick',[], ... 'YTick',[],... 'Color',[0 0 0],... 'DataAspectRatioMode','manual',... 'CameraPositionMode','manual'); hold(ax,'on')
大部分設置大傢都能看懂,這裡講解一下一些比較少見的設置:
2.1 為什麼 axes的’position’屬性不設置[0 0 1 1]?
因為是3D坐標軸,設置為[0 0 1 1]後旋轉起來效果是這樣的,所以我們axes要設置的比figure大一圈:
2.2 為什麼要設置CameraPositionMode這一奇怪的屬性?
因為我們後期要頻繁改變CameraPosition這一屬性,而CameraPositionMode設置為manual可以讓視角完全按照CameraPosition的數值來調整,至於為什麼要調整視角呢?
當然是因為如果對圖像位置數據進行處理數據量會賊大,因此我們不妨直接轉動axes視角而非轉動圖片。
3 繪制圖形句柄
就是繪制小型立方體,中型立方體和大型立方體,其中鼠標移動到中型立方體中心時中型立方體變成大型立方體,這個可以靠設置圖形對象的XData,YData,ZData數值來改變
3.1 構造網格
由於surf曲面圖可以將圖像貼在上面,還可以設置透明度,我們決定用surf函數來繪制,要貼圖首先要將曲面繪制出來,就要先構造曲面網格:
% 用於繪制圖片的網格 [XMesh,YMesh]=meshgrid(linspace(-1,1,120),linspace(-1,1,120)); ZMesh=ones(120,120);
3.2 繪制小型立方體
% 繪制圖片立方體 surfPic(1)=surf(XMesh,YMesh,ZMesh,'CData',imgSet{mod(0,picNum)+1},'EdgeColor','none','FaceColor','interp'); surfPic(2)=surf(XMesh,YMesh(end:-1:1,:),-ZMesh,'CData',imgSet{mod(1,picNum)+1},'EdgeColor','none','FaceColor','interp'); surfPic(3)=surf(ZMesh,XMesh,YMesh(end:-1:1,:),'CData',imgSet{mod(2,picNum)+1},'EdgeColor','none','FaceColor','interp'); surfPic(4)=surf(XMesh,ZMesh,YMesh(end:-1:1,:),'CData',imgSet{mod(3,picNum)+1},'EdgeColor','none','FaceColor','interp'); surfPic(5)=surf(-ZMesh,XMesh,YMesh(end:-1:1,:),'CData',imgSet{mod(4,picNum)+1},'EdgeColor','none','FaceColor','interp'); surfPic(6)=surf(XMesh,-ZMesh,YMesh(end:-1:1,:),'CData',imgSet{mod(5,picNum)+1},'EdgeColor','none','FaceColor','interp');
3.3 繪制中型立方體
有瞭小型立方體,中型的繪制起來就簡單瞭起來,甚至可以用一個for循環解決,隻需要循環提取小型立方體的XData,YData,ZData數據後乘以1.5繪制圖像,並設置透明度即可:
% 依靠小立方體數據繪制中等立方體 for i=1:6 surfPicA(i)=surf(surfPic(i).XData.*1.5,surfPic(i).YData.*1.5,surfPic(i).ZData.*1.5,... 'CData',surfPic(i).CData,'EdgeColor','none','FaceColor','interp','FaceAlpha',0.7); end
3.4 大型立方體參數設置
大型立方體參數設置時就沒那麼簡單,如果直接乘以2.5,圖片與圖片之間會沒有縫隙,因此我們XData,YData,ZData數據雖然都要變大,但是要乘以不一樣的數值,而且各個方向上乘的數值不同,因此我們可以事先設立一個矩陣,用來存儲其參數:
% 用來調整放大比例的矩陣 resizeMat=[2 2 2.5;2 2 2.5;2.5 2 2; 2 2.5 2;2.5 2 2;2 2.5 2];
想直接畫大型正方形可以試試如下代碼:
% 最大圖片繪制 % for i=1:6 % surfPicB(i)=surf(surfPic(i).XData.*resizeMat(i,1),... % surfPic(i).YData.*resizeMat(i,2),... % surfPic(i).ZData.*resizeMat(i,3),... % 'CData',surfPic(i).CData,'EdgeColor',... % 'none','FaceColor','interp','FaceAlpha',0.7); % end
4 立方體旋轉
我們隻需要設置一個timer函數不斷調整CameraPosition即可:
fps=40;theta=0; rotateTimer=timer('ExecutionMode', 'FixedRate', 'Period',1/fps, 'TimerFcn', @rotateCube); start(rotateTimer) function rotateCube(~,~) theta=theta+0.02; ax.CameraPosition=[cos(theta)*5*sqrt(2),sin(theta)*5*sqrt(2),5]; end
5 獲取鼠標與中心點的距離
本來想直接在timer調用的函數裡寫get(fig,‘CurrentPoint’);來獲得鼠標當前位置的,但發現這樣寫隻有鼠標點擊窗口才會有反應,並不是鼠標移動就會有反應,因此我們再構造一個WindowButtonMotionFcn回調,!!!這一部分代碼要寫在上一步代碼的前面!!!
lastDis=300; preDis=300; set(fig,'WindowButtonMotionFcn',@move2center) function move2center(~,~) xy=get(fig,'CurrentPoint'); preDis=sqrt(sum((xy-[300,300]).^2)); end
preDis就是鼠標到圖片中心的位置,我為什麼要設置一個lastDis呢,因為每次移動鼠標都更新圖像實在太卡瞭,因此我們要加一個判定,當且僅當以下兩種情況更新圖片大小
- 之前鼠標距離中心>=150,現在<150
- 之前鼠標距離中心<150,現在>=150
6 鼠標移動到fig中心時更新圖片
將之前的rotateCube函數改成這樣:
function rotateCube(~,~) theta=theta+0.02; ax.CameraPosition=[cos(theta)*5*sqrt(2),sin(theta)*5*sqrt(2),5]; if (~all([preDis lastDis]<150))&&any([preDis lastDis]<150) for ii=1:6 if preDis<150 surfPicA(ii).XData=surfPic(ii).XData.*resizeMat(ii,1); surfPicA(ii).YData=surfPic(ii).YData.*resizeMat(ii,2); surfPicA(ii).ZData=surfPic(ii).ZData.*resizeMat(ii,3); else surfPicA(ii).XData=surfPic(ii).XData.*1.5; surfPicA(ii).YData=surfPic(ii).YData.*1.5; surfPicA(ii).ZData=surfPic(ii).ZData.*1.5; end end end lastDis=preDis; end
其中:
(~all([preDis lastDis]<150))&&any([preDis lastDis]<150)
是用來判斷上一次鼠標位置和當前鼠標位置是否隻有一個距離中心<150
另:
for 循環中使用else來判斷應該繪制大圖片還是中等圖片
完整代碼
function album3d path='.\album\';%文件夾名稱 files=dir(fullfile(path,'*.jpg')); picNum=size(files,1); %遍歷路徑下每一幅圖像 for i=1:picNum fileName=strcat(path,files(i).name); img=imread(fileName); img=imresize(img,[120,120]); imgSet{i}=img; end % fig axes設置 fig=figure('units','pixels','position',[50 50 600 600],... 'Numbertitle','off','resize','off',... 'name','album3d','menubar','none'); ax=axes('parent',fig,'position',[-0.5 -0.5 2 2],... 'XLim', [-6 6],... 'YLim', [-6 6],... 'ZLim', [-6 6],... 'Visible','on',... 'XTick',[], ... 'YTick',[],... 'Color',[0 0 0],... 'DataAspectRatioMode','manual',... 'CameraPositionMode','manual'); hold(ax,'on') ax.CameraPosition=[5 5 5]; % 用於繪制圖片的網格 [XMesh,YMesh]=meshgrid(linspace(-1,1,120),linspace(-1,1,120)); ZMesh=ones(120,120); % 繪制圖片立方體 surfPic(1)=surf(XMesh,YMesh,ZMesh,'CData',imgSet{mod(0,picNum)+1},'EdgeColor','none','FaceColor','interp'); surfPic(2)=surf(XMesh,YMesh(end:-1:1,:),-ZMesh,'CData',imgSet{mod(1,picNum)+1},'EdgeColor','none','FaceColor','interp'); surfPic(3)=surf(ZMesh,XMesh,YMesh(end:-1:1,:),'CData',imgSet{mod(2,picNum)+1},'EdgeColor','none','FaceColor','interp'); surfPic(4)=surf(XMesh,ZMesh,YMesh(end:-1:1,:),'CData',imgSet{mod(3,picNum)+1},'EdgeColor','none','FaceColor','interp'); surfPic(5)=surf(-ZMesh,XMesh,YMesh(end:-1:1,:),'CData',imgSet{mod(4,picNum)+1},'EdgeColor','none','FaceColor','interp'); surfPic(6)=surf(XMesh,-ZMesh,YMesh(end:-1:1,:),'CData',imgSet{mod(5,picNum)+1},'EdgeColor','none','FaceColor','interp'); % 依靠小立方體數據繪制中等立方體 for i=1:6 surfPicA(i)=surf(surfPic(i).XData.*1.5,surfPic(i).YData.*1.5,surfPic(i).ZData.*1.5,... 'CData',surfPic(i).CData,'EdgeColor','none','FaceColor','interp','FaceAlpha',0.7); end % 用來調整放大比例的矩陣 resizeMat=[2 2 2.5;2 2 2.5;2.5 2 2; 2 2.5 2;2.5 2 2;2 2.5 2]; % 最大圖片繪制 % for i=1:6 % surfPicB(i)=surf(surfPic(i).XData.*resizeMat(i,1),... % surfPic(i).YData.*resizeMat(i,2),... % surfPic(i).ZData.*resizeMat(i,3),... % 'CData',surfPic(i).CData,'EdgeColor',... % 'none','FaceColor','interp','FaceAlpha',0.7); % end lastDis=300; preDis=300; set(fig,'WindowButtonMotionFcn',@move2center) function move2center(~,~) xy=get(fig,'CurrentPoint'); preDis=sqrt(sum((xy-[300,300]).^2)); end fps=40;theta=0; rotateTimer=timer('ExecutionMode', 'FixedRate', 'Period',1/fps, 'TimerFcn', @rotateCube); start(rotateTimer) function rotateCube(~,~) theta=theta+0.02; ax.CameraPosition=[cos(theta)*5*sqrt(2),sin(theta)*5*sqrt(2),5]; if (~all([preDis lastDis]<150))&&any([preDis lastDis]<150) for ii=1:6 if preDis<150 surfPicA(ii).XData=surfPic(ii).XData.*resizeMat(ii,1); surfPicA(ii).YData=surfPic(ii).YData.*resizeMat(ii,2); surfPicA(ii).ZData=surfPic(ii).ZData.*resizeMat(ii,3); else surfPicA(ii).XData=surfPic(ii).XData.*1.5; surfPicA(ii).YData=surfPic(ii).YData.*1.5; surfPicA(ii).ZData=surfPic(ii).ZData.*1.5; end end end lastDis=preDis; end % 棄用方案:太卡 % set(fig,'WindowButtonMotionFcn',@move2center) % function move2center(~,~) % xy=get(fig,'CurrentPoint'); % dis=sum((xy-[300,300]).^2); % for ii=1:6 % if dis<200 % surfPicA(ii).XData=surfPic(ii).XData.*resizeMat(ii,1); % surfPicA(ii).YData=surfPic(ii).YData.*resizeMat(ii,2); % surfPicA(ii).ZData=surfPic(ii).ZData.*resizeMat(ii,3); % else % surfPicA(ii).XData=surfPic(ii).XData; % surfPicA(ii).YData=surfPic(ii).YData; % surfPicA(ii).ZData=surfPic(ii).ZData; % end % end % % % % end end
以上就是教你用Matlab制作立體動態相冊的詳細內容,更多關於Matlab制作立體相冊的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- Matlab繪制散點密度圖的教程詳解
- 利用Matlab制作環形相冊效果詳解
- MATLAB 全景圖切割及盒圖顯示的實現步驟
- 詳解Matlab繪制3D玫瑰花的方法(內附旋轉版本)
- 利用Matlab制作一個賊簡單的粒子聖誕樹