前言:
在磁共振影像处理中,mask是一个非常常用的工具,它的作用笔者使用过的包括但不限于:
- 预处理:去除头骨、颈部、颅外等区域(脑提取(Brain extraction)&头骨剥离(Skull stripping))。
- 分割:将大脑分离成特定成分,如白质、灰质、脑脊液等。
- 标准化和配准:mask可以确保只有相关脑区参与到配准计算,这在某些序列(eg:QSM)中是必不可少的一步。
- 统计分析:在组间比较前进行mask,不仅可以增加同一体素的可比性,还能减少计算量。
mask也有不同的类型,常见的两种原理分别是:
1.二值化掩模:只包含0和1的MRI图像,1表示感兴趣区域,0表示不感兴趣的区域。
2.先验概率掩模:每个体素里包含从0到1的连续变量,指该体素在概率上属于某种成分的可能性。(例如0.5&csf,指该体素在之前的群体模版里有50%可能性属于脑脊液成分。)
![](https://i-blog.csdnimg.cn/direct/54574b0217754d689f46b1ce7bb46e1b.png)
原理
mask提取的过程本质上是通过元素级的乘法,将原始MRI图像中的不感兴趣区域定义为0,感兴趣区保留原始强度。
拿灰质mask为例,其中灰质区域的体素值为1,非灰质区域为0,将这个mask矩阵与原始MRI图像矩阵相乘,非灰质区域就进行了置零。
而脑图谱中的ROI(感兴趣区)提取方法本质上也是通过label的索引,再转化成二值mask来提取。
数学描述
MRI图像是三维矩阵:
- x方向:n个体素;
- y方向:m个体素;
- z方向:k个体素。
定义变量:
-
原始MRI图像。
:灰质mask。
提取出的MRI里的灰质图像。
都是三维矩阵,且其三者的维度相等并等于
对于图像中的每个体素,我们都可以用来表示其位置。
那么提取灰质的过程也就是:
![G(m,n,k)=I((m,n,k))\times M(m,n,k)](https://latex.csdn.net/eq?G%28m%2Cn%2Ck%29%3DI%28%28m%2Cn%2Ck%29%29%5Ctimes%20M%28m%2Cn%2Ck%29)
概率mask原理相同:
某些情况下每个体素单位内不是严格的0或1,而是每个体素属于某种成分的概率。
技术
上文介绍了mask提取MRI图像原理,本质上非常简单,但3D图像还涉及到中心坐标点,朝向,体素点大小,尺寸等许多问题,为了让mask可以完美的覆盖到我们的MRI图像,在技术层面还是要细心做许多工作的。
在这里覆上笔者亲踩的坑,如果图省事直接用matlab的imresize函数简单粗暴解决问题,效果有多差。
![](https://i-blog.csdnimg.cn/direct/60b2a11190594156a1b3458bd29175df.png)
1.准备mask
准备好二值化掩模,将其中感兴趣区设置为1,非感兴趣区设置为0。
![](https://i-blog.csdnimg.cn/direct/bb09d4591b1c41f88f9aed13ad65bf91.png)
2.Reslice:确保mask和MRI采样率(Voxel Size)一致
读取:
在matlab上用spm读取MRI和mask的图像信息。
V = spm_vol('MRIimg.nii');
disp('Image dimensions:');
disp(V.dim);
voxel_size = sqrt(sum(V.mat(1:3,1:3).^2));
disp('Voxel size (mm):');
disp(voxel_size);
![](https://i-blog.csdnimg.cn/direct/aeb34fd21caf4c1ebd6e839f2fddb10c.png)
重采样:
使用cat的toolbox进行自动化Resize,或者自己在matlab上编写代码,示例如下,一般使用常见的邻近法插值即可:
% 将voxel size为3mm的MASK重新采样为1.5mm
filename = 'mask.nii';
V = spm_vol(filename);
[img, XYZ] = spm_read_vols(V);
old_dim = V.dim;
new_dim = round(old_dim .* (3/1.5));
[x, y, z] = ndgrid(1:new_dim(1), 1:new_dim(2), 1:new_dim(3));
new_coords = [x(:)'; y(:)'; z(:)'];
M = V.mat * [diag(3./1.5), zeros(3,1); zeros(1,3), 1];
old_coords = V.mat \ (M * [new_coords; ones(1, size(new_coords, 2))]);
interp_img = interpn(img, old_coords(1,:), old_coords(2,:), old_coords(3,:), 'nearest');
new_img = reshape(interp_img, new_dim);
new_V = V;
new_V.dim = new_dim;
new_V.mat = M;
new_V.fname = 'F:\XIUJUEmaterial\resampled_1.5mm_mask.nii';
spm_write_vol(new_V, new_img);
disp('重采样完成!');
3.确保mask和MRI图像配准
通过将MRI和mask重叠的方式,它们对齐在同一空间。
如果没有重叠,需配准到标准空间(spm配置教程)。
![](https://i-blog.csdnimg.cn/direct/66900aac8ea04b0baf84c6b25bdfef57.png)
4.【可选】进行mask填充
因为我们从网站上下载的脑图谱mask和自己处理的T1img维度可能不一样,如果T1大于mask的范围,我们需要将mask的边缘用零值填充,使其和T1一致,再进行运算。
mri = spm_read_vols(spm_vol('T1.nii'));
mask = spm_read_vols(spm_vol('Mask.nii'));
[x1, y1, z1] = size(mri);
[x2, y2, z2] = size(mask);
pad_x = max(0, x1 - x2);
pad_y = max(0, y1 - y2);
pad_z = max(0, z1 - z2);
% 填充
mask_padded = padarray(mask, [pad_x, pad_y, pad_z], 0, 'post');
% 裁剪
mask_final = mask_padded(1:x1, 1:y1, 1:z1);
% 写入MASK原文件
V = spm_vol('Mask.nii');
V.dim = size(mask_final);
spm_write_vol(V, mask_final);
4.进行提取
可以用spm-imgCacluater进行图像相乘。
![](https://i-blog.csdnimg.cn/direct/ccd31c0a28fb4fb1b3a82f7e2f245f4a.png)
5.【可选】裁剪
如果进行了第四步,用填充后的mask进行抓取,那在进行组间比较前需要再裁剪,否则会有很多体素值为0,影响多重比较校正的计算。下文的代码介绍将图像裁剪为113*137*113维度。
% 读取MRI图像
mri_file = 'MRI.nii';
V = spm_vol(mri_file);
img = spm_read_vols(V);
% 找到非零值的索引
[x, y, z] = ind2sub(size(img), find(img ~= 0));
% 计算非零值的中心
center_x = round(mean(x));
center_y = round(mean(y));
center_z = round(mean(z));
% 计算裁剪的起始和结束索引
start_x = center_x - 56; end_x = center_x + 56;
start_y = center_y - 68; end_y = center_y + 68;
start_z = center_z - 56; end_z = center_z + 56;
% 确保裁剪索引在图像范围内
start_x = max(1, start_x); end_x = min(size(img, 1), end_x);
start_y = max(1, start_y); end_y = min(size(img, 2), end_y);
start_z = max(1, start_z); end_z = min(size(img, 3), end_z);
% 裁剪图像
img_cropped = img(start_x:end_x, start_y:end_y, start_z:end_z);
% 确保裁剪后的尺寸正确
[crop_x, crop_y, crop_z] = size(img_cropped);
if crop_x ~= 113 || crop_y ~= 137 || crop_z ~= 113
warning('裁剪后的尺寸不是113x137x113,可能需要额外的处理');
% 如果尺寸不匹配,可以考虑在这里添加额外的裁剪或填充步骤
end
% 创建新的头文件
V_new = V;
V_new.fname = 'path_to_save_cropped_image.nii';
V_new.dim = size(img_cropped);
% 更新变换矩阵以反映新的图像位置
% 这确保了裁剪后的图像在原始空间中的正确定位
orig_to_world = V.mat;
crop_to_orig = eye(4);
crop_to_orig(1:3, 4) = [start_x; start_y; start_z] - 1;
V_new.mat = orig_to_world * crop_to_orig;
% 保存新图像
spm_write_vol(V_new, img_cropped);
总结:
笔者进行VBM(体素形态学)组间比较时发现不同组因T1图像不同,分割后的灰质图像维度并不一致,为了让每个体素单位的统计检验更可靠,学习将三组在同一空间再次应用灰质掩模后比较。
![](https://i-blog.csdnimg.cn/direct/e096a2f428084b278296dfc3c32f0ca4.png)