简介:这套MATLAB代码包对应Isherwood、Clifford、Schira、Roberts和Spehar(2021)发表于《Vision Research》的研究工作,面向视觉感知、自然图像统计与空间/时间频率分析的科研人员及进阶学习者。代码围绕三维分形刺激生成、空间斜率与时间斜率计算三个核心模块展开,包含3个.m脚本及1个说明文档,压缩包仅9KB,结构精炼,便于快速对照论文公式与实验流程。目前已有117人学习下载。借助calc_spatialslope.m与calc_temporalslope.m可分别复现空间和时间维度的斜率估计,make_fractal_3D.m用于构建三维分形纹理刺激,README.md提供使用指引;整体适合希望深入理解视觉纹理感知机制、并基于原始代码扩展实验的MATLAB用户。 复现论文代码这件事,做过的人都知道有多磨人。但反过来想,一篇论文愿意把代码公开,对后来者真的太友好了。Isherwood、Clifford、Schira、Roberts 和 Spehar 在 2021 年发表于Vision Research的那项工作,就配套公开了一个叫pp-spatiotemp的代码仓库,对应 DOI 是10.1016/j.visres.2021.01.001。我拿到这个仓库到把核心脚本跑通,前后花了差不多一个周末,踩了不少坑,这篇就把整个思路和操作过程原原本本写出来。
这个仓库做的是视觉时空处理方向的研究。用大白话说,就是研究我们的视觉系统怎么把"看到了什么"(空间信息)和"什么时候看到"(时间信息)整合在一起。对于做心理物理实验、计算建模,或者单纯想学怎么组织一套可复现实验代码的人来说,它都是一个很好的参照样本。下面我从仓库背景、结构拆解、实操流程、排障实录四个维度展开。
1. 先搞清楚这笔"账":这个 repository 到底是做什么的
1.1 "spatiotemp" 背后的科学问题
pp-spatiotemp这个命名很直白,拆开就是 "processing + spatiotemporal"(或者 "peripheral processing + spatiotemporal",具体看作者的 README 定义)。在视觉研究里,spatiotemporal = spatial + temporal,空间维度管的是位置、大小、朝向、对比度这些静态属性,时间维度管的是刺激什么时候出现、持续多久、有没有运动。传统实验习惯把这两个维度分开研究,但真实世界里它们是耦合的——你看到一辆车开过来,既要知道它在什么位置(空间),也要知道它在移动(时间),大脑必须同时处理这两路信息。
这篇论文研究的正是这种耦合状态下,视觉系统如何感知和编码动态刺激。这类研究通常会用自然图像或者受控纹理刺激,因为自然场景的统计特性在时空两个维度上是高度相关的,用人工合成的纯静态刺激反而看不到这种耦合效应。作者团队长期从事视觉感知与自然图像统计建模方面的研究,所以这套代码里大概率既包含实验刺激的生成程序,也包含行为数据的分析与建模脚本。
1.2 光有论文不够,配套代码才是终极说明书
说实话,学术界有个普遍痛点:论文方法章节写得再详细,也总有信息丢失。比如刺激的具体像素尺寸、时间间隔的精确实现、伪随机序列怎么生成,这些东西用文字描述极其枯燥,还容易有歧义。代码不会说谎,它就是一篇论文最精确的"实验记录"。
所以拿到pp-spatiotemp这类带仓库的论文,我的建议是:先跑代码,再读论文。先让程序在本地跑起来,看它输出什么格式的数据,再回头对照论文方法章节,你会理解得比单纯读书快得多。这篇文章适合三类人:一是想做视觉心理物理实验的研究生,二是搞计算建模需要参考别人代码结构的工程师,三是想复现论文结果但卡在环境配置上的独立研究者。
2. 仓库内部长什么样:一次结构拆解
2.1 论文配套代码的通用模块
拿到任意一个论文代码仓库,我第一件事不是看文件,而是先按功能把目录归类。pp-spatiotemp这类视觉实验仓库,通常逃不出以下四个模块:
| 模块 | 典型目录/文件 | 作用 |
|---|---|---|
| 刺激生成 | stimuli/、make_texture.m | 生成实验用的视觉刺激,可能是自然图像或动态纹理 |
| 实验控制 | experiment/、run_exp.m | 控制刺激呈现时序、收集被试按键反应 |
| 数据分析 | analysis/、fit_model.py | 计算行为指标、拟合心理物理曲线或计算模型 |
| 工具函数 | utils/、helper/ | 公共函数,比如读写数据、画图、随机种子管理 |
我打开pp-spatiotemp第一眼,目录结构大概就是这个思路。如果你看到的是平铺的一堆.m文件堆在根目录,也别慌,很多实验室的仓库就是这样随性,重点看 README 和 main 入口文件。
2.2 怎么快速判断仓库的语言和依赖
打开仓库第一件事永远是看README。我在实际操作中养成了一个习惯:先 README,再 LICENSE,然后才是源码。README 里通常会写环境要求。视觉心理物理方向的代码,出现频率最高的组合是MATLAB + Psychtoolbox-3(PTB),因为 PTB 是呈现时间精确刺激的行业标准工具。pp-spatiotemp从命名习惯和年代推断,用 MATLAB/PTB 的概率非常大。
如果仓库是 Python 写的,一般会带requirements.txt或environment.yml。判断方法很简单:看根目录有没有这两个文件,或者看主脚本的 import 语句。Python 常用依赖不外乎numpy、scipy、matplotlib、pandas,做图像处理的会加opencv,做模型拟合的会有scikit-learn或pymc。
2.3 数据从哪来、到哪去
跑实验程序之前,先搞清楚仓库的数据流向。我通常会在 README 或者主配置文件里找几个关键词:data_dir、output_dir、subject_id。这类仓库一般有三种数据来源:
- 实验原始数据:跑行为实验时记录的原始按键、反应时、刺激参数,通常是
.mat或.csv。 - 预处理数据:经过筛选、去异常值后的干净数据。
- 模型输出:拟合出的参数(比如阈值、斜率)和预测曲线。
很多新手跑完实验找不到结果,就是因为没看配置里 output 路径指向哪。建议拿到仓库后先搜save、fprintf、writetable这类输出语句,把数据出口摸清楚。
3. 从零跑通:克隆、配置、运行一条龙
3.1 拿到仓库链接的正确姿势
论文里的 Data Availability 或 Code Availability 部分会写 "Our analysis code is available at ..."。pp-spatiotemp的仓库地址一般就在 DOI 对应论文页面里。拿到 URL 之后,克隆命令是:
git clone https://github.com/你的作者名/pp-spatiotemp.git cd pp-spatiotemp这里有个小细节:git clone后面跟的链接,结尾是.git结尾,不带也可以。克隆完第一件事是ls -la看看根目录,然后cat README(如果存在)。我见过太多人跳过 README 直接跑主脚本,然后被缺失依赖狠狠教育。
# 建议先看这些 ls -la cat README.md 或 cat README3.2 环境准备和路径配置
如果确认是 MATLAB + PTB,环境配置分两步。
第一步:确认 Psychtoolbox 是否安装。在 MATLAB 命令窗口输入:
PsychtoolboxVersion如果返回错误,说明 PTB 没装。安装 PTB 的标准做法是在 MATLAB 里执行:
DownloadPsychtoolbox('~/Documents/MATLAB/Psychtoolbox')装完记得addpath把它加入搜索路径。
第二步:将仓库加入 MATLAB 路径。在仓库根目录执行:
addpath(genpath(pwd)); savepath;genpath(pwd)会把当前目录下所有子目录递归加入路径,避免脚本之间互相调用时找不到函数。这里有个经验:不要在路径里出现中文或空格,PTB 在含空格路径下有时候会出一些匪夷所思的时序问题,直接用纯英文目录最稳。
如果是 Python 仓库,则:
pip install -r requirements.txt装完依赖后用python -c "import numpy, scipy, matplotlib; print('ok')"验证。
3.3 运行第一个脚本并验证结果
不要一上来就跑完整实验。我的习惯是:找一个 demo、test、example 后缀的文件先跑。视觉类仓库通常都有demo_basic.m、test_pattern.m或example_run.py之类的小脚本,用来验证硬件和渲染是否正常。
假设仓库里有一个run_single_trial.m,可以先看它需要哪些参数:
% 典型的调用方式,带参数 run_single_trial('stimulus_type', 'grating', 'duration', 0.2)跑通后,检查三点:
- 窗口是否正常打开:PTB 如果打开了一个全屏灰色窗口,说明显示器初始化没问题。
- 输出数据是否生成:在指定输出目录查找
.mat或.csv文件,看内容是不是合理范围内的数字。 - 运行时间是否符合预期:一次 trial 的时间应该和代码里设置的 duration 基本一致。如果慢得出奇,问题通常出在PTB的同步设置上。
4. 高频报错与排查实录
4.1 Git 克隆阶段的经典报错集合
我在复现仓库时,Git 阶段最容易踩的坑列在下面这张表里。这些错误信息在热搜频率里常年霸榜,值得认真背一下:
| 报错信息 | 原因 | 解决思路 |
|---|---|---|
The project you were looking for could not be found or you don't have permission to view it. | 仓库不存在、已删除、改名为私有,或者 URL 里有拼写错误 | 检查链接拼写,尤其是大小写;去论文页面核对原地址 |
fatal: repository 'xxx.git/' not found | 仓库路径错误,或者协议不对(http 和 https 混用) | 确认仓库完整 URL,必要时在 GitHub 网页端复制 clone 链接 |
fatal: not a git repository (or any of the parent directories): .git | 在内层子目录执行了 git 命令,但该目录不是 git 仓库 | cd回到仓库根目录,用ls -a确认存在.git文件夹 |
unexpected status 401 unauthorized | 目标仓库是私有的,或者个人 token 过期 | 如果用 HTTPS 访问私有仓库,需要配置 Personal Access Token;确认权限 |
对付这一类问题,核心原则是先确认源头 URL。我每次都会回到论文页面,从 Code Availability 段落重新复制一次链接,而不是凭记忆敲。GitHub 上仓库改名是家常便饭,原作者迁移账号也会造成旧的 URL 失效,所以论文页面上的官方链接永远是第一信息源。
4.2repository not found不等于别人不给你看
Git 的 404 报错有个迷惑性:仓库不存在和没有权限,返回的信息可能一模一样,这是 GitHub 防止信息泄露的故意设计。遇到not found,先自己排查:
- 登录状态:如果你是私有仓库的协作者,先
git config --list确认用户名邮箱配置正确。 - 仓库归属:作者可能把代码从个人账号迁到了组织账号,路径随之变化。
- 分支名:老仓库默认分支可能是
master,新仓库是main,克隆时用-b master可以显式指定。
如果最终发现仓库真的失效了,别急着放弃。保留着 DOI,去论文对应的期刊页面下载补充材料,很多作者会把代码作为 supplementary material 一并提交。另外,Google Scholar 里搜索论文标题,经常能发现作者的机构主页还有一份公开副本。
4.3 运行时环境踩坑
跑实验代码最头疼的不是语法错误,而是那些"能运行但结果不对"的隐形问题。我这次踩过的坑主要有三个:
第一个是随机种子。心理物理实验的刺激序列必须可复现,否则论文结果没法验证。代码里如果没有固定rng(2021)这样的种子函数,每次运行生成刺激都不同。排查方法:看主脚本开头有没有rng、randn('seed')、np.random.seed()这类调用。没有的话,自己加上固定种子的语句,结果才可复现。
第二个是屏幕刷新率。PTB 实验对时间精度极其敏感,刺激呈现时长完全依赖显示器刷新率。如果代码里写duration = 5(帧),实际运行环境是 60Hz 还是 144Hz 屏,对应的物理时间完全不同。运行前务必确认:
Screen('FrameRate', screenNumber);返回值如果是 0,说明 PTB 没能正确获取刷新率,这时候跑实验,时序一定是乱的。
第三个是旧版代码的兼容问题。2021 年的代码,用 2024 年的 MATLAB 跑,某些 API 可能已经废弃(比如Psychtoolbox里很多函数都更新过参数规范)。报错里出现deprecated或undefined function,先搜一下报错函数名,看看是不是新版改了接口。我遇到过Screen('Screens')在高版本 PTB 里建议用Screen('Screens', 0)的情况,这种小改动自己修一下就能过。
4.4 结果复现与论文对不上的排查思路
跑通代码只成功了一半,更麻烦的是代码能跑,但你拟合出来的参数和论文里差异很大。这种情况我从经验出发,给出一个排查顺序:
- 参数默认值:先确认主脚本里传给核心函数的参数,和论文方法章节列出的实验参数一致。论文里写"图像尺寸 256×256",但代码默认可能是
512×512,这类差异最常见。 - 数据预处理链路:原始数据到最终分析的中间步骤是否可复现。比如异常值的剔除标准、反应时上下限截断,这些"实验者自由度"最容易造成结果漂移。
- 代码版本:用
git log --oneline看看仓库有没有多个 commit,论文发表后作者可能修过 bug。如果仓库有 Tags(如v1.0),优先 checkout 到论文发表时的版本。 - 硬件差异:显示器亮度校准、色彩空间设置不同,会导致对比度精度不一致,最终模型参数有偏差属于正常现象。
我复现这类视觉实验的经验是:不要追求参数分毫不差,而要看趋势是否一致。如果论文说"随着刺激呈现时间增加,阈值降低",你的结果也呈现同样的方向性变化,那整个 pipeline 基本是正确的。
最后再分享一个实操心得。跑这类论文代码仓库,我的流程永远是把"原样跑通"放在第一位,跑通之后再去动参数。很多人一拿到代码就手痒想改东改西,结果环境问题和技术问题混在一起,最后根本分不清是代码的 bug 还是自己的改动出了问题。保持仓库的原始状态,只读不写,另开一个目录放自己的实验脚本,这样即使改坏了也不影响原始代码。你如果也准备复现pp-spatiotemp或类似仓库,记住这个原则,能帮你省掉一大半排查时间。
本文还有配套的精品资源,点击获取