经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » MATLAB » 查看文章
教你用Matlab制作立体动态相册
来源:jb51  时间:2022/3/1 13:39:22  对本文有异议

效果

教程部分

1 图片导入与大小重设

需要有一个名为album的文件夹和当前m文件在同一文件夹,另外ablum文件夹内至少要有一张jpg格式图片

  1. path='.\album\';%文件夹名称
  2. files=dir(fullfile(path,'*.jpg'));
  3. picNum=size(files,1);
  4.  
  5. %遍历路径下每一幅图像
  6. for i=1:picNum
  7. fileName=strcat(path,files(i).name);
  8. img=imread(fileName);
  9. img=imresize(img,[120,120]);
  10. imgSet{i}=img;
  11. end

我们注意到,这里用了一次imresize将突破变为120x120大小,这里重设大小有三个作用:

  • 将不是方形的图片变为方形
  • 将图像设置固定大小,方便构造网格放置图片
  • 120x120的大小大约是能让图片表示清晰为前提下最小的大小,图片太大的话运行会卡,太小的话不清晰

2 fig axes设置

  1. % fig axes设置
  2. fig=figure('units','pixels','position',[50 50 600 600],...
  3. 'Numbertitle','off','resize','off',...
  4. 'name','album3d','menubar','none');
  5. ax=axes('parent',fig,'position',[-0.5 -0.5 2 2],...
  6. 'XLim', [-6 6],...
  7. 'YLim', [-6 6],...
  8. 'ZLim', [-6 6],...
  9. 'Visible','on',...
  10. 'XTick',[], ...
  11. 'YTick',[],...
  12. 'Color',[0 0 0],...
  13. 'DataAspectRatioMode','manual',...
  14. 'CameraPositionMode','manual');
  15. 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函数来绘制,要贴图首先要将曲面绘制出来,就要先构造曲面网格:

  1. % 用于绘制图片的网格
  2. [XMesh,YMesh]=meshgrid(linspace(-1,1,120),linspace(-1,1,120));
  3. ZMesh=ones(120,120);

3.2 绘制小型立方体

  1. % 绘制图片立方体
  2. surfPic(1)=surf(XMesh,YMesh,ZMesh,'CData',imgSet{mod(0,picNum)+1},'EdgeColor','none','FaceColor','interp');
  3. surfPic(2)=surf(XMesh,YMesh(end:-1:1,:),-ZMesh,'CData',imgSet{mod(1,picNum)+1},'EdgeColor','none','FaceColor','interp');
  4. surfPic(3)=surf(ZMesh,XMesh,YMesh(end:-1:1,:),'CData',imgSet{mod(2,picNum)+1},'EdgeColor','none','FaceColor','interp');
  5. surfPic(4)=surf(XMesh,ZMesh,YMesh(end:-1:1,:),'CData',imgSet{mod(3,picNum)+1},'EdgeColor','none','FaceColor','interp');
  6. surfPic(5)=surf(-ZMesh,XMesh,YMesh(end:-1:1,:),'CData',imgSet{mod(4,picNum)+1},'EdgeColor','none','FaceColor','interp');
  7. 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绘制图像,并设置透明度即可:

  1. % 依靠小立方体数据绘制中等立方体
  2. for i=1:6
  3. surfPicA(i)=surf(surfPic(i).XData.*1.5,surfPic(i).YData.*1.5,surfPic(i).ZData.*1.5,...
  4. 'CData',surfPic(i).CData,'EdgeColor','none','FaceColor','interp','FaceAlpha',0.7);
  5. end

3.4 大型立方体参数设置

大型立方体参数设置时就没那么简单,如果直接乘以2.5,图片与图片之间会没有缝隙,因此我们XData,YData,ZData数据虽然都要变大,但是要乘以不一样的数值,而且各个方向上乘的数值不同,因此我们可以事先设立一个矩阵,用来存储其参数:

  1. % 用来调整放大比例的矩阵
  2. resizeMat=[2 2 2.5;2 2 2.5;2.5 2 2;
  3. 2 2.5 2;2.5 2 2;2 2.5 2];

想直接画大型正方形可以试试如下代码:

  1. % 最大图片绘制
  2. % for i=1:6
  3. % surfPicB(i)=surf(surfPic(i).XData.*resizeMat(i,1),...
  4. % surfPic(i).YData.*resizeMat(i,2),...
  5. % surfPic(i).ZData.*resizeMat(i,3),...
  6. % 'CData',surfPic(i).CData,'EdgeColor',...
  7. % 'none','FaceColor','interp','FaceAlpha',0.7);
  8. % end

4 立方体旋转

我们只需要设置一个timer函数不断调整CameraPosition即可:

  1. fps=40;theta=0;
  2. rotateTimer=timer('ExecutionMode', 'FixedRate', 'Period',1/fps, 'TimerFcn', @rotateCube);
  3. start(rotateTimer)
  4.  
  5. function rotateCube(~,~)
  6. theta=theta+0.02;
  7. ax.CameraPosition=[cos(theta)*5*sqrt(2),sin(theta)*5*sqrt(2),5];
  8. end

5 获取鼠标与中心点的距离

本来想直接在timer调用的函数里写get(fig,‘CurrentPoint’);来获得鼠标当前位置的,但发现这样写只有鼠标点击窗口才会有反应,并不是鼠标移动就会有反应,因此我们再构造一个WindowButtonMotionFcn回调,!!!这一部分代码要写在上一步代码的前面!!!

  1. lastDis=300;
  2. preDis=300;
  3. set(fig,'WindowButtonMotionFcn',@move2center)
  4. function move2center(~,~)
  5. xy=get(fig,'CurrentPoint');
  6. preDis=sqrt(sum((xy-[300,300]).^2));
  7. end

preDis就是鼠标到图片中心的位置,我为什么要设置一个lastDis呢,因为每次移动鼠标都更新图像实在太卡了,因此我们要加一个判定,当且仅当以下两种情况更新图片大小

  • 之前鼠标距离中心>=150,现在<150
  • 之前鼠标距离中心<150,现在>=150

6 鼠标移动到fig中心时更新图片

将之前的rotateCube函数改成这样:

  1. function rotateCube(~,~)
  2. theta=theta+0.02;
  3. ax.CameraPosition=[cos(theta)*5*sqrt(2),sin(theta)*5*sqrt(2),5];
  4. if (~all([preDis lastDis]<150))&&any([preDis lastDis]<150)
  5. for ii=1:6
  6. if preDis<150
  7. surfPicA(ii).XData=surfPic(ii).XData.*resizeMat(ii,1);
  8. surfPicA(ii).YData=surfPic(ii).YData.*resizeMat(ii,2);
  9. surfPicA(ii).ZData=surfPic(ii).ZData.*resizeMat(ii,3);
  10. else
  11. surfPicA(ii).XData=surfPic(ii).XData.*1.5;
  12. surfPicA(ii).YData=surfPic(ii).YData.*1.5;
  13. surfPicA(ii).ZData=surfPic(ii).ZData.*1.5;
  14. end
  15. end
  16. end
  17. lastDis=preDis;
  18. end

其中:

(~all([preDis lastDis]<150))&&any([preDis lastDis]<150)

是用来判断上一次鼠标位置和当前鼠标位置是否只有一个距离中心<150

另:

for 循环中使用else来判断应该绘制大图片还是中等图片

完整代码

  1. function album3d
  2. path='.\album\';%文件夹名称
  3. files=dir(fullfile(path,'*.jpg'));
  4. picNum=size(files,1);
  5.  
  6. %遍历路径下每一幅图像
  7. for i=1:picNum
  8. fileName=strcat(path,files(i).name);
  9. img=imread(fileName);
  10. img=imresize(img,[120,120]);
  11. imgSet{i}=img;
  12. end
  13.  
  14. % fig axes设置
  15. fig=figure('units','pixels','position',[50 50 600 600],...
  16. 'Numbertitle','off','resize','off',...
  17. 'name','album3d','menubar','none');
  18. ax=axes('parent',fig,'position',[-0.5 -0.5 2 2],...
  19. 'XLim', [-6 6],...
  20. 'YLim', [-6 6],...
  21. 'ZLim', [-6 6],...
  22. 'Visible','on',...
  23. 'XTick',[], ...
  24. 'YTick',[],...
  25. 'Color',[0 0 0],...
  26. 'DataAspectRatioMode','manual',...
  27. 'CameraPositionMode','manual');
  28. hold(ax,'on')
  29. ax.CameraPosition=[5 5 5];
  30.  
  31. % 用于绘制图片的网格
  32. [XMesh,YMesh]=meshgrid(linspace(-1,1,120),linspace(-1,1,120));
  33. ZMesh=ones(120,120);
  34.  
  35. % 绘制图片立方体
  36. surfPic(1)=surf(XMesh,YMesh,ZMesh,'CData',imgSet{mod(0,picNum)+1},'EdgeColor','none','FaceColor','interp');
  37. surfPic(2)=surf(XMesh,YMesh(end:-1:1,:),-ZMesh,'CData',imgSet{mod(1,picNum)+1},'EdgeColor','none','FaceColor','interp');
  38. surfPic(3)=surf(ZMesh,XMesh,YMesh(end:-1:1,:),'CData',imgSet{mod(2,picNum)+1},'EdgeColor','none','FaceColor','interp');
  39. surfPic(4)=surf(XMesh,ZMesh,YMesh(end:-1:1,:),'CData',imgSet{mod(3,picNum)+1},'EdgeColor','none','FaceColor','interp');
  40. surfPic(5)=surf(-ZMesh,XMesh,YMesh(end:-1:1,:),'CData',imgSet{mod(4,picNum)+1},'EdgeColor','none','FaceColor','interp');
  41. surfPic(6)=surf(XMesh,-ZMesh,YMesh(end:-1:1,:),'CData',imgSet{mod(5,picNum)+1},'EdgeColor','none','FaceColor','interp');
  42.  
  43. % 依靠小立方体数据绘制中等立方体
  44. for i=1:6
  45. surfPicA(i)=surf(surfPic(i).XData.*1.5,surfPic(i).YData.*1.5,surfPic(i).ZData.*1.5,...
  46. 'CData',surfPic(i).CData,'EdgeColor','none','FaceColor','interp','FaceAlpha',0.7);
  47. end
  48.  
  49. % 用来调整放大比例的矩阵
  50. resizeMat=[2 2 2.5;2 2 2.5;2.5 2 2;
  51. 2 2.5 2;2.5 2 2;2 2.5 2];
  52.  
  53. % 最大图片绘制
  54. % for i=1:6
  55. % surfPicB(i)=surf(surfPic(i).XData.*resizeMat(i,1),...
  56. % surfPic(i).YData.*resizeMat(i,2),...
  57. % surfPic(i).ZData.*resizeMat(i,3),...
  58. % 'CData',surfPic(i).CData,'EdgeColor',...
  59. % 'none','FaceColor','interp','FaceAlpha',0.7);
  60. % end
  61.  
  62.  
  63. lastDis=300;
  64. preDis=300;
  65. set(fig,'WindowButtonMotionFcn',@move2center)
  66. function move2center(~,~)
  67. xy=get(fig,'CurrentPoint');
  68. preDis=sqrt(sum((xy-[300,300]).^2));
  69. end
  70.  
  71.  
  72.  
  73. fps=40;theta=0;
  74. rotateTimer=timer('ExecutionMode', 'FixedRate', 'Period',1/fps, 'TimerFcn', @rotateCube);
  75. start(rotateTimer)
  76.  
  77.  
  78.  
  79. function rotateCube(~,~)
  80. theta=theta+0.02;
  81. ax.CameraPosition=[cos(theta)*5*sqrt(2),sin(theta)*5*sqrt(2),5];
  82. if (~all([preDis lastDis]<150))&&any([preDis lastDis]<150)
  83. for ii=1:6
  84. if preDis<150
  85. surfPicA(ii).XData=surfPic(ii).XData.*resizeMat(ii,1);
  86. surfPicA(ii).YData=surfPic(ii).YData.*resizeMat(ii,2);
  87. surfPicA(ii).ZData=surfPic(ii).ZData.*resizeMat(ii,3);
  88. else
  89. surfPicA(ii).XData=surfPic(ii).XData.*1.5;
  90. surfPicA(ii).YData=surfPic(ii).YData.*1.5;
  91. surfPicA(ii).ZData=surfPic(ii).ZData.*1.5;
  92. end
  93. end
  94. end
  95. lastDis=preDis;
  96. end
  97.  
  98.  
  99.  
  100.  
  101. % 弃用方案:太卡
  102. % set(fig,'WindowButtonMotionFcn',@move2center)
  103. % function move2center(~,~)
  104. % xy=get(fig,'CurrentPoint');
  105. % dis=sum((xy-[300,300]).^2);
  106. % for ii=1:6
  107. % if dis<200
  108. % surfPicA(ii).XData=surfPic(ii).XData.*resizeMat(ii,1);
  109. % surfPicA(ii).YData=surfPic(ii).YData.*resizeMat(ii,2);
  110. % surfPicA(ii).ZData=surfPic(ii).ZData.*resizeMat(ii,3);
  111. % else
  112. % surfPicA(ii).XData=surfPic(ii).XData;
  113. % surfPicA(ii).YData=surfPic(ii).YData;
  114. % surfPicA(ii).ZData=surfPic(ii).ZData;
  115. % end
  116. % end
  117. %
  118. %
  119. %
  120. % end
  121.  
  122. end

以上就是教你用Matlab制作立体动态相册的详细内容,更多关于Matlab制作立体相册的资料请关注w3xue其它相关文章!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号