使用 matlab 绘制3d volume
为了3d重建血管,折腾imagej、imaris、MATLAB的volshow、python的第三方库等等软件
使用上述方法进行3d重建时,发现几个痛点:
- 不方便设置axes的ticklabel
- 不方便多图统一角度
- 想画yz方向的最大强度投影
- 想保存pdf文件,而不是png图片
于是就想写代码自己实现,但是之前没接触过3d重建的代码,折腾了好久,最终在MATLAB fileexchange一个个查,最终发现vol3d 2这个库很好用,可以3d重建,但是也有几个问题
- 没有设置xyz的volpixelsize功能
- 如果自己调整xyz比例,就会发现层与层之间有黑线
- y轴方向是反的
于是我对vol3d v2的代码进行了修改,添加了volpixelsize的参数、linear interp插值、将图像方向调成与imaris 一致等功能。
volume_view
函数用于在MATLAB中可视化三维体数据。它可以接受多种参数来定制显示效果,包括颜色数据、透明度、纹理、坐标数据等。
function [model] = volume_view(varargin)
varargin
: 可变数量的输入参数。可以是以下键值对:'cdata'
: 三维或四维数组,表示体数据的颜色信息。'volsize'
: 向量,指定体数据的目标尺寸。'alpha'
: 三维数组,表示体数据的透明度信息。'parent'
: 图形对象的父对象,通常是一个坐标轴对象。'texture'
: 字符串,指定纹理类型,默认为'3D'
。'xdata'
,'ydata'
,'zdata'
: 向量,指定体数据在各个坐标轴上的范围。
model
: 结构体,包含体数据的可视化模型及其相关属性。
[x, y, z] = meshgrid(-255:256, -255:256, -140:140);
% 定义哑铃参数
r_ball = 100; % 球体半径
r_bar = 30; % 连接杆半径
l_bar = 200; % 连接杆长度
% 创建哑铃形状
dumbbell = ((x.^2 + y.^2 + (z-l_bar/2).^2 <= r_ball^2) | ...
(x.^2 + y.^2 + (z+l_bar/2).^2 <= r_ball^2) | ...
(x.^2 + y.^2 <= r_bar^2 & abs(z) <= l_bar/2));
%%%%%%%%%%%%%%%%% 设置xyz代表的实际视野大小 %%%%%%%%%%%%%%%%%
volsize = [285,285,1400];
%%%%%%%%%%%%%%%%% 绘图 %%%%%%%%%%%%%%%%%
% 对数据进行3D高斯滤波降噪
sigma = 1.0;
h = fspecial3('gaussian', [3 3 3], sigma);
imgStackDenoised = imfilter(dumbbell, h, 'replicate');
% % 对数据进行3D中值降噪
%imgStackDenoised = medfilt3(imgStack, [3 3 3]);
%%%%%%%%%%%%%%%%% 绘图 %%%%%%%%%%%%%%%%%
% 绘制数据
figure;
h = volume_view('cdata', double(imgStackDenoised), 'texture', '3D','volsize',volsize);
view(32,15); % 调整视角
% set(gca, 'color', [0, 0, 0]); % 设置背景颜色
% 自定义绿色颜色映射
greens = [linspace(0, 0, 256)', linspace(0, 1, 256)', linspace(0, 0, 256)'];
colormap(greens);
% 调整colormap范围,调整对比度
clim([0, 1]);
% 设置tickss
xticks(0:100:volsize(1));
yticks(0:100:volsize(2));
zticks(0:100:volsize(3));
xlabel('X (μm)');
ylabel('Y (μm)');
zlabel('Z (μm)');
本项目基于vol3d v2改进
原版的vol3d v2不能设置volsize,直接调用,绘制的比例不对,y和z的方向都是颠倒的
% 绘制数据
figure;
h = vol3d('cdata', double(imgStack), 'texture', '3D','volsize',[285,285,1400]);
view(32,15);
axis tight;
set(gca, 'color', [0, 0, 0]); % 设置背景颜色
% 设置数据纵横比
daspect([512/285 512/285 281/1400]);
% 自定义绿色颜色映射
cmap = [linspace(0, 0, 256)', linspace(0, 1, 256)', linspace(0, 0, 256)'];
colormap(cmap);
clim([0, 35000]);
% 添加轴标签
xlabel('X (um)');
ylabel('Y (um)');
zlabel('Z (um)');
绘图的时候尽管可以加代码修改,比如自己设置daspect,调整为正确的比例和ticklabel,但没有线性插值如果volszie过大会使得层与层之间会有明显的空隙。
% 绘制数据
figure;
h = vol3d('cdata', double(imgStack), 'texture', '3D','volsize',[285,285,1400]);
view(32,15);
axis tight;
set(gca, 'ZDir', 'reverse');
set(gca, 'YDir', 'reverse');
set(gca, 'color', [0, 0, 0]); % 设置背景颜色
% 设置数据纵横比
daspect([512/285 512/285 281/1400]);
% 自定义绿色颜色映射
cmap = [linspace(0, 0, 256)', linspace(0, 1, 256)', linspace(0, 0, 256)'];
colormap(cmap);
clim([0, 35000]);
% 计算实际尺寸对应的数据索引
x_actual_range = 0:100:285;
y_actual_range = 0:100:285;
z_actual_range = 0:100:1400;
% 将实际尺寸转换为数据索引
x_ticks = x_actual_range * (512/285);
y_ticks = y_actual_range * (512/285);
z_ticks = z_actual_range * (281/1400);
% 设置刻度位置
xticks(x_ticks);
yticks(y_ticks);
zticks(z_ticks);
% 设置刻度标签为实际的物理尺寸
xticklabels(arrayfun(@(x) sprintf('%.0f', x), x_actual_range, 'UniformOutput', false));
yticklabels(arrayfun(@(y) sprintf('%.0f', y), y_actual_range, 'UniformOutput', false));
zticklabels(arrayfun(@(z) sprintf('%.0f', z), z_actual_range, 'UniformOutput', false));
% 添加轴标签
xlabel('X (um)');
ylabel('Y (um)');
zlabel('Z (um)');
我对代码进行了修改
- 支持设置xyz的volsize
- 设置volsize会进行线性插值,减少黑线
- 设置volsize绘图会正确显示xyz轴的ticklabel
- 将原来y轴颠倒的图像调正,和在imaris viewer软件里显示的方向一致