ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

广泛场光学成像体素分析实战:MATLAB全流程与代码

广泛场光学成像体素分析实战:MATLAB全流程与代码 简介这是一份面向神经科学研究人员的小鼠宽场光学成像体素分析MATLAB实现资源内容紧扣开源论文复现覆盖数据预处理、功能连接性分析、刺激激活分析、基于聚类的统计阈值处理并延伸至格兰杰因果、深度学习与数据增强等前沿方法。作者huanghm88将全流程写成可直接运行的脚本及逐段解释从数据加载、掩模与种子区创建到单/双侧功能连接、刺激时间历程、显著性聚类判断再到将结果叠加到皮层分区图完整呈现了宽场成像数据从原始图像到可解释结论的分析链路。资源共1个docx文件压缩包约43KB文字说明与代码示例均集中于此轻量且便于查阅。目前已有65人学习下载适合具备神经科学、医学影像或生物工程背景的研究人员快速上手在评估不同刺激/药物干预下小鼠大脑功能连接差异及异常活动模式时可直接参考其中的脚本结构与参数调整思路。1. 体素分析为什么是广泛场光学成像的标配做小鼠皮层广泛场光学成像的人通常很快会遇到同一个问题相机一开就是几千帧、上万个像素单只小鼠一个 session 的数据就是几十 GB。这时候如果还像处理单细胞成像一样逐 ROI 去圈区域、提荧光轨迹不仅耗时而且会丢掉大量空间信息。体素分析的核心思路是把每个像素当作一个独立的观测单元在整幅图像上做统一的统计建模从而把“看视频”变成“算矩阵”。这也是广泛场成像区别于双光子成像的关键——它不追求单细胞分辨率而是用全局视角捕捉多个脑区之间的协同活动。本文面向的是已经能用 MATLAB 读写图像、但还没系统整理过体素分析流程的神经科学和生物医学工程研究者。我会从数据预处理、逐像素统计建模到降维和连通性分析给出可以直接改路径运行的 MATLAB 代码并把每一步的参数选择理由和常见坑点讲清楚。这套流程在课题组里验证过多只小鼠的嗅球、体感和前额叶皮层数据迁移到新的实验范式时通常只需要改参数不需要改框架。2. 原始数据到像素时间序列广泛场成像的预处理链路2.1 帧对齐与运动校正刚性配准的参数选择广泛场成像的运动伪影主要来自心跳、呼吸和小鼠头部的微小位移。虽然不像双光子成像那样需要逐帧逐像素的非刚性配准但帧间 1~2 个像素的漂移就足以毁掉后续的体素级统计结果尤其是事件相关分析中对时间锁定的要求很高。因此第一步是刚性配准一般在 MATLAB 中用imregcorr基于相位相关做亚像素级对齐。% 读取前200帧估计参考帧避免全序列特征漂移 info imfinfo(raw_data.tif); nFrames numel(info); refFrame zeros(info(1).Height, info(1).Width); for i 1:200 refFrame refFrame double(imread(raw_data.tif, i)); end refFrame refFrame / 200; % 逐帧配准先用粗对齐再精对齐 fixedRef refFrame; for i 1:nFrames moving double(imread(raw_data.tif, i)); [tform, ~] imregcorr(moving, fixedRef, translation); alignedFrames(:,:,i) imwarp(moving, tform, OutputView, imref2d(size(fixedRef))); end这段代码先把前 200 帧平均作为参考帧因为单帧信噪比太低直接拿第一帧做参考容易被热噪声带偏。imregcorr只做平移配准不处理旋转和缩放这对固定在小鼠头部的成像窗口是合理的——翻转或旋转相机的事情理论上不该发生如果发生了说明实验装置有问题程序纠正不如重新采集。OutputView参数强制输出尺寸与参考帧一致确保所有帧的像素坐标对应同一个解剖位置。配准完成后需要检查逐帧位移量。我通常会把imregcorr输出的位移画出来如果某帧位移超过 3 个像素直接剔除而不是强行配准因为大位移往往伴随形变刚性变换无法修正保留反而会引入伪影。2.2 抹除血管伪影与空间滤波不是所有像素都值得分析广泛场成像的表面荧光信号有很大一部分来自血管里的荧光染料或内源性信号这些信号随心跳波动与神经活动无关。血管伪影在空间上是高频的在时间上是低频的处理策略是空间上做平滑去除高频成分时间上做高通滤波去除低频漂移。但这两个滤波的顺序和参数直接影响体素分析的质量。% 空间平滑高斯核 sigma2 像素 smoothedData zeros(size(alignedFrames)); for i 1:size(alignedFrames,3) smoothedData(:,:,i) imgaussfilt(alignedFrames(:,:,i), 2); end % 时间滤波去除前5%最低频成分对应呼吸和漂移 fs 20; % 采样率单位Hz根据采集软件设置 d designfilt(highpassiir, FilterOrder, 4, ... HalfPowerFrequency, 0.05, SampleRate, fs); for x 1:size(smoothedData,1) for y 1:size(smoothedData,2) smoothedData(x,y,:) filtfilt(d, squeeze(smoothedData(x,y,:))); end end空间平滑的 sigma 值值得多说一句。2 像素的 sigma 在 10~20 μm/像素的成像系统上大约对应 20~40 μm刚好抹掉小血管但不至于模糊皮层功能拓扑结构。如果 sigma 开到 5 以上相邻脑区的边界会糊掉后续的聚类分析就可能把两个功能区域合并成一个。时间高通滤波的截止频率选 0.05 Hz 而不是 0.01 Hz是因为广泛场成像里任务相关的低频漂移比如 0.01~0.03 Hz 的慢波如果是实验关注的信号就不该滤掉0.05 Hz 主要去除的是 DC 漂移和部分呼吸成分。用filtfilt是因为零相位滤波不引入时间延迟而designfilt生成的 IIR 滤波器配合零相位处理比直接用detrend更可控。2.3 荧光到神经活动的映射ΔF/F 逐体素计算的正确写法配准和滤波之后下一层是核心的转换把荧光强度变为反映神经活动的相对变化量。广泛场成像里最通用的是 ΔF/F但这里的“F”到底用整段视频的中位数、基线窗口的平均值还是平滑后的基线不同文献做法不同结果差异很大。我的默认方案是基线用全序列第 10~30 百分位数的均值这样对偶发的神经事件不敏感。% 逐像素计算基线荧光 F0取时间维度上第 10~30 百分位均值 F0 zeros(size(smoothedData,1), size(smoothedData,2)); for x 1:size(smoothedData,1) for y 1:size(smoothedData,2) trace squeeze(smoothedData(x,y,:)); p10 prctile(trace, 10); p30 prctile(trace, 30); F0(x,y) mean(trace(trace p10 trace p30)); end end % 计算 dF/F注意分母下限保护 dFF zeros(size(smoothedData)); for i 1:size(smoothedData,3) dFF(:,:,i) (smoothedData(:,:,i) - F0) ./ (F0 eps); end分母里的 eps不是可选项。广泛场成像中透过颅骨成像时某些像素的基线可能趋近于零比如血管阴影或颅骨增厚区域直接除会导致这些像素的 dF/F 数值爆炸。加上eps之后低基线像素的 dF/F 会被压缩到接近 0不参与下游统计。如果实验中对 dF/F 的幅度有定量要求还应该把 F0 换成一个同 session 内刺激前静息期的平均荧光不过这个改动只影响幅值不改变空间激活模式。3. 体素级统计建模从 dF/F 到激活图和显著性3.1 逐像素 GLM设计矩阵的构建与回归系数解释有了逐像素的时间序列下一步是回答“哪个脑区对刺激有显著响应”。最稳健的方式是逐体素拟合一般线性模型。把每个像素的时间序列作为因变量设计矩阵里放刺激时间点的方波函数卷积血流动力学响应函数以及可选的回归项。广泛场成像的血流动力学响应函数虽然可以用经典的双 gamma 函数近似但建议用实际数据估计——这不需要额外实验只要在刺激序列里留出一段空白期就能实现。% 构建刺激向量示例为 5s 刺激、20s 间隔共 10 个 trial fs 20; stimDuration 5 * fs; totalTime 250 * fs; % 单 trial 总时长 regressor zeros(totalTime, 1); for t 1:10 onset (t-1) * totalTime 1; regressor(onset : onset stimDuration - 1) 1; end % 用双 gamma 函数粗略卷积后作为初始回归量 hrf gampdf(0:1/fs:10, 6, 1) - 0.2 * gampdf(0:1/fs:10, 16, 3); hrf hrf / sum(hrf); predicted conv(regressor, hrf); predicted predicted(1:numel(regressor)); % 构建设计矩阵回归量 常数项 漂移项 designMatrix [predicted, ones(totalTime, 1), (1:totalTime)];这段代码的关键是为每个 trial 生成独立的刺激方波但在设计矩阵里用的是拼接后的单列刺激向量。如果试次之间的间隔足够长比如 20 秒以上单列向量就可以无需为每个 trial 单独设一列。设计矩阵中加入常数项和线性漂移项是为了吸收整体亮度变化避免把硬件漂移误判为任务相关活动。GLM 拟合用的是\运算符MATLAB 里自动走最小二乘路线。对一张 256×256 的图像逐像素拟合 3 个回归系数的计算量不算大但循环写法要避免重复申请变量空间。betaMap zeros(size(dFF,1), size(dFF,2)); tstatMap zeros(size(dFF,1), size(dFF,2)); for x 1:size(dFF,1) for y 1:size(dFF,2) yData squeeze(dFF(x,y,:)); beta designMatrix \ yData; residual yData - designMatrix * beta; dof numel(yData) - size(designMatrix,2); sigma std(residual); % 计算刺激回归系数的 t 统计量 tstat beta(1) / (sigma * sqrt(inv(designMatrix*designMatrix) * (01))); betaMap(x,y) beta(1); tstatMap(x,y) tstat; end endt 统计量计算时用的inv(designMatrix*designMatrix)是设计矩阵协方差矩阵的逆这个表达式在单回归量时等于回归系数标准误的分母。整个公式本质是“系数除以标准误”。注意这里没有做多重比较校正所以生成的 t 值图只能用于初步评估。实际发表的图需要加 FDR 校正这个在 3.3 节给出实现。3.2 事件相关平均逐像素响应幅值与时间窗选择GLM 回答“有没有显著响应”事件相关平均回答“响应长什么样”。逐像素做刺激前的基线校正把每个 trial 的刺激前 2 秒均值当作基线将刺激后的响应标准化为该基线之上的变化百分比。这个计算在体素层面进行但需要先把数据按 trial 切片再平均。preTime 2 * fs; % 刺激前窗口2秒 postTime 10 * fs; % 刺激后窗口10秒 nTrials 10; trialMatrix zeros(size(dFF,1), size(dFF,2), postTime, nTrials); for t 1:nTrials onset (t-1) * totalTime 1; baseline mean(dFF(:,:, max(1,onset-preTime):onset), 3); for i 1:postTime idx onset i - 1; trialMatrix(:,:,i,t) dFF(:,:,idx) - baseline; % 逐像素减去该trial自己的基线 end end avgResponse mean(trialMatrix, 4);这段代码有个容易忽略的细节baseline是逐像素的二维矩阵所以减基线时用的是dFF(:,:,idx) - baseline而不是全局标量。广泛场成像中不同脑区的基线荧光水平本来就不一样使用全局减基线会让腹侧和背侧区域的相对激活幅度失真。时间窗的选择上10 秒的刺激后窗口对大多数感觉刺激足够但如果做的是奖赏或社交任务响应会延伸到刺激结束后 10~15 秒需要把 postTime 加大到 600 帧以上。逐像素事件相关得到的是一个 4 维矩阵x, y, time, trial可以按兴趣区域把空间维度压缩后画平均时间曲线也可以选特定时间点生成激活图。一般我会先看全脑像素中响应峰值出现的平均时间再把激活图的时间点选在峰值附近 ±2 帧内而不是固定在刺激后某个硬编码的时间点。3.3 多重比较校正FDR 体素级阈值怎么算逐体素做统计检验必然遇到多重比较问题。一帧 256×256 的图像上有 65,536 个像素即使没有真实效应也有约 3,276 个像素会在 p0.05 的阈值下被误判为显著。广泛场成像的空间平滑使得邻近像素高度相关Bonferroni 校正过于保守业界常用的是 Benjamini-Hochberg FDR 控制。% 输入tstatMap 是逐像素 t 统计量矩阵dof 是自由度 pMap 2 * tcdf(-abs(tstatMap), dof); % 双尾检验 p 值 pVec pMap(:); pVec pVec(~isnan(pVec)); sortedP sort(pVec); n numel(sortedP); fdrThreshold 0.05; k find(sortedP (1:n) * fdrThreshold / n, 1, last); if isempty(k) threshold 0; % 无显著像素 else threshold sortedP(k); end significantMask pMap threshold;FDR 的计算逻辑并不复杂把 p 值排序后找到满足p(i) i * q / n的最大的 i以该 p 值为阈值。这里的 q0.05 表示控制的是“假发现比例”而非“假阳性概率”意味着显著像素里允许有 5% 是假的。广泛场成像场景下 q 取 0.05 是常规选择但如果用于筛选后续追踪的目标脑区建议把 q 降到 0.01因为后续单脑区的信号提取需要比较可靠的空间种子点。4. 降维与连通性体素分析的高级应用4.1 主成分分析压缩体素维度预处理还是信号提取当体素维度过高而 trial 数相对有限时逐体素 GLM 的统计效力会打折扣。PCA 在广泛场成像中主要有两种用途一是作为下游分析的预处理来降噪——把 65,536 个像素压缩到前 20 个主成分丢掉的主要是随机噪声二是作为信号提取手段把主成分得分映射回像素空间后得到空间模式。两者的区别在于是否用得分序列做后续回归前者不关心成分含义后者必须在意。% 将 dFF 三维矩阵展开为 [时间 x 像素] [nRows, nCols, nTime] size(dFF); pixelTime reshape(dFF, nRows*nCols, nTime); % 注意转置后有 NaN 的行需要剔除用 mean 而非 nanmean 时的默认处理 reduced pixelTime; reduced(isnan(reduced)) 0; % 对数据居中化 reduced reduced - mean(reduced, 1); % 计算主成分。这里用 svd 而不是 pca 函数便于直接观察解释方差 [U, S, V] svd(reduced, econ); explainedVar diag(S).^2 / sum(diag(S).^2); topN find(cumsum(explainedVar) 0.8, 1, first);SVD 计算完成后U 的列是主成分时间序列V 的列是空间加载。解释方差累计 80% 的主成分数量通常只有 10~30 个这比直接用 65,536 维体素做后续聚类要稳定得多。把主成分得分重塑回二维图像就是空间模式图它反映了该成分主要在哪几个脑区表达。注意svd之前必须先做像素级去均值否则第一主成分会很大程度上对应整体亮度波动背景。4.2 种子点相关分析从像素到功能连接图的实现广泛场成像的一个常见问题是各脑区之间的协同活动如何刻画种子点相关分析是其中最直接的体素级方法。选一个感兴趣的种子区域取该区域所有像素的平均时间序列然后计算它与全脑每个像素时间序列的相关系数最终生成一个功能连接图。这里的细节在于种子区域的定义方式——用解剖坐标还是用激活图聚类。% 假设 seedMask 是二值掩膜已通过 ROI 工具或 GLM 激活图获得 seedTrace squeeze(mean(mean(dFF .* seedMask, 1), 2)); seedTrace seedTrace(:); corrMap zeros(nRows, nCols); for x 1:nRows for y 1:nCols pixelTrace squeeze(dFF(x,y,:)); pixelTrace pixelTrace(:); if std(pixelTrace) 1e-6 || std(seedTrace) 1e-6 corrMap(x,y) 0; continue; end R corrcoef(seedTrace, pixelTrace); corrMap(x,y) R(1,2); end end相关系数图通常需要经过 Fisher z 变换后再做统计检验因为皮尔逊相关系数的分布不是正态的尤其当相关值接近 ±1 时。变换公式是z 0.5 * log((1r)/(1-r))后续的组间比较用 z 值而非原始 r 值。另外逐体素做相关计算开销不小256×256 分辨率的图像要跑 65,536 次corrcoef在普通工作站上大约需要几分钟。如果需要提速可以把像素矩阵一次性标准化后做矩阵乘法用pixelNorm * seedNorm代替循环。4.3 静息态广泛场成像的体素级频段分解静息态数据分析中dF/F 信号需要先按频段拆分再在特定频段上做体素间连接。广泛场成像中最常见的是把 0.01~0.1 Hz 的频带作为低频波动的关注区间这对应神经血管耦合中较慢的振荡成分。逐体素做小波分解太慢工程化的做法是设计带通滤波器后对每个像素滤波再进行种子点分析也就是把 4.2 节的输入信号换成带通滤波后的版本。fs 20; flow 0.01; fhigh 0.1; d designfilt(bandpassiir, FilterOrder, 6, ... HalfPowerFrequency1, flow, HalfPowerFrequency2, fhigh, ... SampleRate, fs); bandData zeros(size(dFF)); for x 1:nRows for y 1:nCols bandData(x,y,:) filtfilt(d, squeeze(dFF(x,y,:))); end end带通滤波器的阶数选 6在 0.01 Hz 和 0.1 Hz 之间有足够的过渡带衰减又不至于产生相位畸变——配合filtfilt使用后相位响应为零。这里的一个常见误区是直接对原始 dF/F 滤波而不是对去趋势后的信号滤波。如果数据里有明显漂移先做时间高通或去趋势再带通否则低频成分会被线性拟合的部分吸收掉。5. 验证体素分析结果的三个实用技巧5.1 置换检验确定时空聚类阈值前面 FDR 校正只校正了像素维度上的多重比较但没有考虑空间邻近性。广泛场成像的平滑特性使得相邻像素的统计量高度相关一个真实的激活区域会在图像上形成一块连续区域而零散的孤立像素更可能是假阳性。因此更稳健的做法是置换检验与聚类阈值结合打乱 trial 标签记录最大聚类大小作为零分布再以 95% 分位数为阈值筛选真实聚类。nPerm 1000; maxClusterSize zeros(nPerm, 1); for perm 1:nPerm permOrder randperm(nTrials); % 对每个 trial 内的时间点做整体置换避免破坏时间自相关 permData trialMatrix(:,:,:,permOrder); permMean mean(permData, 4); % 用简单的阈值法提取聚类 permStat max(abs(permMean), [], 3); bw permStat prctile(permStat(:), 95); cc bwconncomp(bw, 8); if numel(cc.PixelIdxList) 0 maxClusterSize(perm) max(cellfun(numel, cc.PixelIdxList)); end end thresholdSize prctile(maxClusterSize, 95);置换次数 1000 次足够获得稳定的 95% 分位数估计。置换单位是 trial 而不是单帧因为相邻帧之间存在高自相关逐帧置换会严重低估真实聚类大小。bwconncomp使用 8 连通判断相邻像素这比 4 连通更容易把斜向连接的像素聚合在一起适合成像数据天然具有的空间平滑特性。5.2 信号相关性检查逐像素时间序列与种子点的一致性度量在向组里汇报结果之前我总是会做一步人为检查在激活图中随机挑 5 个像素把它们的时间序列和 GLM 预测的响应曲线叠加画出来目测拟合质量。这里有一个容易被忽略的坑逐体素 GLM 的 t 值图只反映信噪比不能直接当作“激活强度”去解释。两个像素的 t 值相同完全可能是因为一个激活强但噪声大另一个激活弱但噪声小。因此如果要报告响应幅度必须返回去看 betaMap而不是 tstatMap。% 在显著区域中挑选 5 个高 t 值像素打印其 beta 估计值 idx find(significantMask); [~, sortedIdx] sort(tstatMap(idx), descend); sampleIdx idx(sortedIdx(1:5)); for i 1:5 fprintf(Pixel %d: beta%.3f, t%.2f\n, ... sampleIdx(i), betaMap(sampleIdx(i)), tstatMap(sampleIdx(i))); end这个检查在 MATLAB 命令行里就能完成不需要写文件。输出里如果出现 beta 值很小但 t 值很高的像素说明该位置的噪声极低信号虽然小但稳定如果 beta 大但 t 值一般则提示该区域激活幅度可观、但 trial-to-trial 波动也大。两者分别适合不同的后续解释场景。5.3 组水平分析的标准化策略共配准与参数映射表多只小鼠的数据做组水平分析前需要把每只小鼠的图像配准到一个共同模板上。广泛场成像没有类似 fMRI 那种标准脑模板常见的做法是用解剖学 landmarks 做仿射配准或者用每只小鼠的血管模式图做特征匹配。MATLAB 里fitgeotrans支持affine变换输入两组对应的控制点坐标即可。控制点的选取通常基于嗅球、前囟、lambda 缝等解剖标志。组水平统计的最小单位是每只小鼠的体素级 beta 图或 t 图。把这些图配准到模板空间后逐体素做单样本 t 检验得到组水平的激活图。此时需要注意的是每只小鼠的 trial 数目可能不同自由度也不同所以做组水平检验时应该把每只小鼠的对比图像先标准化为单位方差避免高 trial 数的小鼠主导结果。常用的标准化因子是sqrt(nTrials)直接除以该因子后再进组水平 t 检验。本文还有配套的精品资源点击获取
返回列表