需要有一个名为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的大小大约是能让图片表示清晰为前提下最小的大小,图片太大的话运行会卡,太小的话不清晰
% 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];
大部分设置大家都能看懂,这里讲解一下一些比较少见的设置:
2.1 为什么 axes的’position’属性不设置[0 0 1 1]?因为是3D坐标轴,设置为[0 0 1 1]后旋转起来效果是这样的,所以我们axes要设置的比figure大一圈:
因为我们后期要频繁改变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');
有了小型立方体,中型的绘制起来就简单了起来,甚至可以用一个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
大型立方体参数设置时就没那么简单,如果直接乘以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
本来想直接在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,现在
关注打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?