MATLAB竟也能制作3D相册?教你用MATLAB制作立体动态相册

article/2025/8/23 19:57:38

效果

在这里插入图片描述
在这里插入图片描述

教程部分

1 图片导入与大小重设

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

path='.\album\';%文件夹名称
files=dir(fullfile(path,'*.jpg')); 
picNum=size(files,1);%遍历路径下每一幅图像
for i=1:picNumfileName=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')
ax.CameraPosition=[5 5 5];

大部分设置大家都能看懂,这里讲解一下一些比较少见的设置:

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:6surfPicA(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:6if preDis<150surfPicA(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);elsesurfPicA(ii).XData=surfPic(ii).XData.*1.5;surfPicA(ii).YData=surfPic(ii).YData.*1.5;surfPicA(ii).ZData=surfPic(ii).ZData.*1.5;endendendlastDis=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:picNumfileName=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:6surfPicA(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));endfps=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:6if preDis<150surfPicA(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);elsesurfPicA(ii).XData=surfPic(ii).XData.*1.5;surfPicA(ii).YData=surfPic(ii).YData.*1.5;surfPicA(ii).ZData=surfPic(ii).ZData.*1.5;endendendlastDis=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
%         
%         
%         
%     endend

http://chatgpt.dhexx.cn/article/p823AbyQ.shtml

相关文章

HTML 3d立体旋转相册

效果&#xff1a;&#xff08;实际是动态旋转&#xff09; 目录&#xff1a;&#xff08;根据自己需要替换图片就行了 大照片是400*400 小照片是100*100&#xff09; 提取码&#xff1a;1122 代码链接 index.html <!DOCTYPE html> <html lang"en"> <…

3D立体相册不过是冷锋蓝plus版 html+css

一.话不多&#xff0c;先看效果&#xff1a; 转念一想&#xff0c;好像很久很久没出css特效的文章了&#xff0c;特别是工作之后&#xff0c;更少了。偶然翻看电脑内存的时候&#xff0c;发现这个自己1年多以前写的特效&#xff0c;甚美&#xff0c;又勾起我一段尘封的回忆。。…

创意相册、3D立体相册

3D表白相册 精美的3D动态相册&#xff0c;快去做给她吧&#xff01; 点我下载 换的图片格式要一样&#xff0c;实在不一样就去代码里面改后缀名 https://download.csdn.net/download/weixin_43474701/60386577

3D立体相册,一个可旋转的立体相册

11359.gif 主要功能&#xff1a;立体球体展示 可自行添加本地照片 可旋转&#xff0c;照片可放大 商城下载&#xff1a; App Store github下载 用的代码是用的云标签的code&#xff0c;代码略有改动 主要代码调用 // 调用展示 self.sphereView [[YoungSphere alloc] initWithF…

还在买鲜花送女神?手把手教你搭建3D立体相册网站,包女神稀饭

是不是一款人见人爱的相册网站&#xff0c;看下图演示马上知晓。360度3D立体旋转&#xff0c;随意放大缩小任一张照片&#xff0c;合适每一个女生的小胃口&#xff0c;保证女神眼前一亮&#xff0c;对您刮目相看。 我们的特点是——情人节圣诞节女神生日纪念日都适合当礼物&am…

css3 3D立体相册实现

这几天无聊&#xff0c;看到有博主弄的电子相册有点意思&#xff0c;就照葫芦画瓢也实现了一个&#xff0c;一个半透明的正方体包含着一个小正方体&#xff0c;相册自动旋转&#xff0c;当获得焦点时变化效果&#xff0c;截图如下&#xff1a; 一&#xff0c;代码目录结构 二&a…

3D立体相册 html+css

前言 用css的transform属性做一个3D相册~~~ 值translate表示偏移&#xff1b; scale表示缩放&#xff1b; rotate就是转动。 一、先看效果 二、实现步骤 1.我们知道一个正方体有6个面&#xff0c;所以定义一个父亲元素然后定义6个子元素作为6个面。每个面放一张图片。里面q1…

搭载3D立体相册网页 加入背景音乐 真香!

一、3D立体相册 HTML代码 <!DOCTYPE html> <html lang="en"><head><meta

七夕表白程序:3D 立体表白相册(素材+源码),用它的都成功了!

马上就要七夕了&#xff0c;学编程的你没有什么拿得出手的礼物吗&#xff1f;不如用我们所学知识来做个简单的 3D 立体表白相册吧&#xff01;&#xff08;特效绝对杠杠的&#xff09; 希望大家&#xff08;以及大家的那一位&#xff09;喜欢! 效果截图如下&#xff1a;&…

抖音上很火的3D立体动态相册

带背景音乐网站效果: http://www.fengzhao.icu/photos/html/%E6%8A%96%E9%9F%B3%E4%B8%8A%E5%BE%88%E7%81%AB%E7%9A%843D%E7%AB%8B%E4%BD%93%E5%8A%A8%E6%80%81%E7%9B%B8%E5%86%8C.html 如何创建网站:参考我的这篇文章 https://blog.csdn.net/allen_csdns/article/details…

【Python入门】Python做游戏——跳跃小鸟

如何运行 安装依赖pip install keras pip install pygame pip install scikit-image pip install h5py作者使用的是theano训练的,训练好的模型文件要使用theano作为Keras的后端才能调用,在配置文件~/.keras/keras.json中(没有可创建)确认/修改backend为theano(如果没有安装…

教你用Python做小游戏

第一步&#xff1a;你好&#xff0c;兔子 运行IDLE&#xff0c;打开一个新的文本编辑窗口。输入以下的代码&#xff1a; # 1 - Import library import pygame from pygame.locals import *# 2 - Initialize the game pygame.init() width, height 640, 480 screenpygame.dis…

怎么用python做游戏_如何用python做游戏

你有没有想过电脑游戏是怎样制作出来的&#xff1f;其实它没有你想象的那样复杂&#xff01; PyGame是一个Python的库&#xff0c;能够让你更容易的写出一个游戏。它提供的功能包括图片处理和声音重放的功能&#xff0c;并且它们能很容易的整合进你的游戏里。去官网点击这里下载…

为了上班摸鱼我用Python制作十五个小游戏,普通到地狱级难度,看看你能挑战到哪【内附源码】

今天给大家带来十五个Python小游戏&#xff0c;找回童年的同时学习编程还可以摸鱼&#xff0c;源码附上结尾领取。 一、接金币&#xff08;1分&#xff09; 普通难度&#xff1a;❤ 玩法介绍&#xff1a; 吃金币&#xff0c;控制左右键&#xff0c;有手就行。 ​ 源码分享…

用python做一个简单的游戏,用python写一个小游戏

大家好&#xff0c;本文将围绕如何用python做一个简单的小游戏展开说明&#xff0c;python编写的入门简单小游戏是一个很多人都想弄明白的事情&#xff0c;想搞清楚用python做一个简单的游戏需要先了解以下几个事情。 1、Python游戏开发&#xff0c;Python实现贪吃蛇小游戏与吃…

用 Python 做游戏有多简单

大家好&#xff0c;今天我用两篇文章来介绍一下&#xff0c;如果使用 Python 做游戏。 这个游戏是使用 PyGame 做的&#xff0c;贴图素材是从 itch.io[1] 找的。我之前也没有用过 PyGame&#xff0c;这次属于是现学现用&#xff0c;参考的教程是 PyGame: A Primer on Game Prog…

Python做游戏其实很简单,只是你觉得难...

很多小伙伴都喜欢小游戏源码&#xff0c;想学一手Python做小游戏&#xff0c;问我做游戏难不难&#xff0c;要怎么做&#xff0c;接下来我就介绍一下&#xff0c;如何用Python做游戏。 游戏演示 2048小游戏 表白弹窗 贪吃蛇 五子棋 俄罗斯方块 超多小游戏&#xff0c;让你一个…

Python不能做游戏?一小时做出一个游戏!

嗨喽&#xff5e;小伙伴们&#xff0c;我又来了&#xff0c; 写在前面的话&#xff1a; 【 一直都听他们说&#xff0c;python做不出好的游戏&#xff0c;个人是不赞同的&#xff0c;我只能说&#xff0c;python可以用来写游戏&#xff0c;但不适合。 举个最简单的例子&…

【含源码】用python做游戏有多简单好玩

有很多同学问我还有其他什么小游戏吗&#xff0c;游戏是怎么做的&#xff0c;难不难。我就用两篇文章来介绍一下&#xff0c;如何使用Python做游戏。 兔子与灌 俄罗斯方块 休闲五子棋 走迷宫 推箱子 消消乐 超多小游戏玩转不停↓ 更多小游戏可以评论区讨论哦&#xff0c;喜欢…

python做小游戏之一小迷宫游戏

趣味python一迷宫小游戏 读取外部迷宫地图 既然是编写小游戏&#xff0c;那么自然少不了pygame模块&#xff0c;编译环境使用的是pycharm。 迷宫小游戏设计思想是&#xff0c;我们自己绘制迷宫地图文档&#xff0c;然后程序根据我们设计的地图把迷宫绘制到pygame游戏界面当中来…