首頁 > 軟體

教你用Matlab製作立體動態相簿

2022-03-01 16:00:10

效果

教學部分

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將突破變為120x120大小,這裡重設大小有三個作用:

  • 將不是方形的圖片變為方形
  • 將影象設定固定大小,方便構造網格放置圖片
  • 120x120的大小大約是能讓圖片表示清晰為前提下最小的大小,圖片太大的話執行會卡,太小的話不清晰

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製作立體相簿的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com