CAT12.7脑结构像分割:安装配置、批处理与质控避坑

发布时间:2026/10/27 7:33:06
CAT12.7脑结构像分割:安装配置、批处理与质控避坑 简介CAT12.7 安装包面向从事神经影像与脑结构 MRI 分析的科研人员和学生尤其适合需要在 SPM 环境下完成 T1 图像预处理、皮层厚度估计与脑形态测量的用户也适合已有 MATLAB 与 SPM 基础、希望减少环境配置阻碍的中高级学习者。压缩包共 822 个文件约 222.93MB包含大量 MATLAB 脚本与函数、跨平台 MEX 组件、HTML 说明页面、NIfTI 影像、PNG 示意图以及 FreeSurfer 格式的脑区 annot 图谱、模板和 mask 等配套数据基本覆盖工具箱运行、分区分析与结果核验所需内容。已有 1731 人学习下载说明该版本在相关学习笔记和实操流程中被较多使用。对于沿用旧版教程、希望复现 T1 处理步骤的读者可从中获得较完整的 CAT12 目录结构、脚本函数、图谱模板与示例数据便于在 MATLAB/SPM 中配置路径、检查依赖并开展皮层表面与脑区指标分析也能为旧版流程迁移和新版工具对比提供参考。1. 一个装着上万行 MATLAB 代码的 CAT12.7 版本安装包到底解决什么问题凌晨两点一份三十个被试的 T1 结构像还在机器上排队跑分割跑到第二十七个突然抛错退出前二十六个的结果白跑一遍——这种崩溃只要经历过一次就会开始重视安装包和批处理脚本本身。CAT12.7 版本安装包解决的就是这件事它把基于 SPM12 的计算解剖工具箱完整打包下来让 T1 加权像的组织分割、颅内体积估计、基于体素和基于表面的形态学分析能在本机一次性对齐环境。适合两类人手上有一批 DICOM 或 NIfTI 结构像、要算出灰质体积或皮层厚度指标的影像数据处理开发者以及想把分割步骤嵌进自己分析流水线、需要稳定复现结果的研究型工程师。它本质是一份源码软件不是双击就能用的桌面应用。2. 目录结构与运行环境cat12、spm12 和 MATLAB 三方怎么对齐拿到安装包之后最忌讳的一件事就是直接解压、双击、启动然后被一堆 Undefined function 挡在门外。CAT12 不是独立程序它是一层跑在 SPM12 之上、SPM12 又跑在 MATLAB 之上的工具箱三者版本必须像齿轮一样咬住。这一章先把目录看清楚再把路径理清楚最后处理没有 MATLAB 授权的那种情况。2.1 解压后先看这五个位置解压安装包之后正常情况下会看到两类顶层目录一个是spm12一个是cat12。后者才是主角前者是依赖。进入cat12之后真正需要认识的只有下面这几块其余大多是函数文件和数据模板位置作用动不动它cat12/cat12.m工具箱入口命令行输入cat12就调用它不改cat12/cat_*.m核心函数分割、配准、表面重建都在这一层二次开发时才碰cat12/tpm/组织概率图模板分割的起点不手动改cat12/templates_*归一化用的标准空间模板不手动改cat12/atlases/图谱目录ROI 统计靠它可以自己加cat12/external/第三方工具表面处理相关按需cat12/docs/手册与变更记录出问题先翻这里读为什么要先看清tpm和templates_*这两个目录决定了分割和归一化的默认行为很多结果不对的报障追到最后是有人为了省空间把模板目录删了或者拷了个旧版本模板混进来。我第一次整理工具箱时就把tpm单独挪到了别处结果每次分割都报找不到组织概率图翻了半小时日志才发现是自己埋的雷。另外要认一下cat12/external下面有没有随包带的表面处理组件。做基于表面的分析时这一层缺东西会在后期重建阶段才暴露前面分割一切正常等到算厚度才断排查成本非常高。装完先跑一个被试把全链路走通比事后救火划算得多。2.2 MATLAB 路径顺序与启动自检CAT12 的路径注册有一个顺序要求SPM12 必须先于 CAT12 进入搜索路径。原因是 CAT12 启动时会做一次 SPM 版本探测探测不到就直接终止。反过来把 CAT12 放前面虽然函数也能找到但版本检查拿到的可能是空值。% 先清场避免旧版本残留干扰 restoredefaultpath; % 1) SPM12 先入路径注意这里用 addpath 而不是 genpath addpath(/opt/toolboxes/spm12); % 2) CAT12 需要递归加入它下面还有子目录依赖 addpath(genpath(/opt/toolboxes/cat12)); % 3) 固化下来下次启动不用重敲 savepath; % 4) 自检能打印出版本号才算装通 disp(which(spm)); disp(which(cat12));这段里几个细节值得说。restoredefaultpath是我踩坑之后养成的前置动作很多函数冲突类报错其实是用户目录下残留了一份老的spm文件夹新旧混用导致行为诡异。addpath和genpath的区别在于SPM12 只加顶层目录就够了它的子目录由自身的初始化逻辑处理CAT12 则必须用genpath把子目录全部铺开否则调用到深层函数时会报未定义。验证环节不要只看which的返回值还要真正启动一次图形界面% 启动 SPM 主界面这是 CAT12 能加载的前提 spm(defaults,FMRI); spm_jobman(initcfg); % 再启动 CAT12正常会弹出一个独立窗口 cat12;spm(defaults, ...)里的参数决定了一组全局默认值做结构像处理一般用FMRI或PET都可以差别主要在滤波和缩放策略上。spm_jobman(initcfg)这一步很多人漏掉它负责初始化批处理系统的配置缓存漏了之后在某些 MATLAB 版本上调用spm_jobman(run, ...)会报配置结构不完整。窗口能弹出来、下拉菜单里能看到 CAT12 条目环境就算对齐了。2.3 没有 MATLAB 授权时走独立版现实里经常遇到的情况是分析机器上没有 MATLAB 商业授权或者授权被别的节点占着。安装包里如果带了独立运行版本走的是 MATLAB Runtime 路线原理是编译器把工具箱和运行库打包成不依赖 MATLAB 的可执行文件。独立版的验证方式和工具箱版完全不同不需要进 MATLAB直接在终端跑# 先确认运行库能被找到 export LD_LIBRARY_PATH/opt/toolboxes/MCR/v97/runtime/glnxa64:$LD_LIBRARY_PATH # 用最小输入试跑输出目录必须提前建好 /opt/toolboxes/cat12_standalone/run_cat12.sh \ /opt/toolboxes/MCR/v97 \ /data/sub-01/anat/sub-01_T1w.nii \ /data/sub-01/out第一行是运行库路径v97这类版本号必须和打包时用的 MATLAB 版本严丝合缝对上差一个版本就会报找不到libmwmclmcrrt.so。第二段的三个参数依次是运行库根目录、输入文件、输出目录输入输出都建议用绝对路径相对路径在独立版里经常因为工作目录切换而失效。独立版的代价是灵活性下降图形界面能做的事它都能做但批处理的字段没法在运行时随意改要改就得重新生成配置文件。所以我的一般做法是——有 MATLAB 授权就用工具箱版跑调试把参数调稳之后再固化成独立版丢到计算节点上批量跑。两套环境都在手边比死磕一套要省时间。3. 核心链路拆解一张 T1 从进 cat12 到出 mwp1 的全过程搞清目录只算进了门真正决定结果质量的是分割这一段。CAT12 的分割不是一步而是一条由配准、组织分类、归一化、调制串起来的链路每一环都有一组可以调的参数参数错了结果看起来能出图但数值完全不能用。这一章把这条链路拆开讲并给出可以直接抄的批处理结构。3.1 配准、组织分割与归一化的三步顺序一张原始 T1 进来第一步是仿射配准把个体脑袋摆到标准空间附近同时估计出六参数的刚体变换。这一步的初值来自头皮剥离后的图像所以头动严重或者视野不全的数据在这里就会出问题表现为后续组织概率图错位。第二步是组织分类把每个体素判成灰质、白质、脑脊液、颅骨、软组织、空气六类。CAT12 在这一步用的是自适应最大后验估计配合局部自适应分割强度比早期版本对不均匀场更耐受。这一步还会顺带估计出总颅内体积是后面做比例校正的基础。第三步是空间归一化与调制。归一化把个体空间映射到标准模板空间调制则是把形变场的雅可比行列式乘回图像强度保证体积守恒——换句话说调制后的灰质图上每个体素的数值代表的是原始体积而不是概率密度。顺序不能颠倒但可以跳过。做 ROI 分析时很多人只做分割不做归一化直接拿个体空间的灰质图配图谱做基于体素的分析就必须做归一化加调制。判断标准很简单结果要和别人的坐标对齐就得归一化只在个体空间里量体积可以省掉这一步。我见过有人在归一化之后才发现自己其实只需要个体体积白跑一整轮。3.2 一个 segmentation 批处理结构长什么样图形界面点出来的操作最后都会变成一个 matlabbatch 结构。理解这个结构等于拿到了把 GUI 变成脚本的钥匙。下面是最小可用的一段% 初始化批处理系统 spm_jobman(initcfg); % 清空上一次残留防止字段串味 clear matlabbatch; % 输入NIfTI 路径后面必须带 ,1 表示取第一卷 matlabbatch{1}.spm.tools.cat.estwrite.data { /data/sub-01/anat/sub-01_T1w.nii,1 }; % 并行进程数内存不够就调小见第 5 章 matlabbatch{1}.spm.tools.cat.estwrite.nproc 2; % 仿射配准方式默认即可异常数据可换 matlabbatch{1}.spm.tools.cat.estwrite.opts.affreg mni; % 组织概率图模板路径必须是本机真实存在的绝对路径 matlabbatch{1}.spm.tools.cat.estwrite.opts.tpm { /opt/toolboxes/cat12/tpm/TPM.nii }; % 局部自适应分割强度默认 0.5对比度差的数据可上调 matlabbatch{1}.spm.tools.cat.estwrite.extopts.LASstr 0.5; % 配准正则化强度越小越严格 matlabbatch{1}.spm.tools.cat.estwrite.extopts.regstr 0.5; % 输出打开灰质与白质的调制归一化结果 matlabbatch{1}.spm.tools.cat.estwrite.output.GM.native 1; matlabbatch{1}.spm.tools.cat.estwrite.output.GM.warped 1; matlabbatch{1}.spm.tools.cat.estwrite.output.GM.mod 1; matlabbatch{1}.spm.tools.cat.estwrite.output.WM.native 1; matlabbatch{1}.spm.tools.cat.estwrite.output.WM.warped 1; matlabbatch{1}.spm.tools.cat.estwrite.output.WM.mod 1; % 跳过表面重建只做体素级分析能省一半时间 matlabbatch{1}.spm.tools.cat.estwrite.output.surface 0; % 真正执行 spm_jobman(run, matlabbatch);逐段说。data里的,1是 SPM 的约定标记取文件的第几帧4D 数据必须写清楚3D 数据不写某些版本也能跑但容易在批量时出岔子养成习惯就好。nproc控制并行它的取值直接决定内存峰值后面避坑章节会专门说。opts.tpm给的是六类组织概率图模板CAT12 内部会按这个文件的位置推断同级目录下的其他模板所以路径必须是完整的绝对路径写成相对路径在某些工作目录下会静默失败输出看着正常但组织分类明显跑偏。extopts.LASstr是局部自适应分割强度这个参数最值得动手调默认 0.5 对常规 3T 数据够用遇到 1.5T 或者对比度偏弱的扫描把它调到 0.6 到 0.7能明显改善深部灰质的分类效果。代价是过度平滑边界会糊所以别一上来就调。extopts.regstr控制配准正则化值越小形变越自由。脑室显著扩大或者有占位效应的数据适当放松到 0.3 左右能减少配准失败但会带来形变过度的风险得看成像质量决定。output.GM.native / warped / mod三个开关分别对应个体空间、标准空间、调制后结果。全打开最保险代价是磁盘占用翻几倍。做基于体素的形态学分析实际只需要mod为 1 且warped为 1 的组合也就是那批mwp1文件native留作个体空间 ROI 用。output.surface 0是提速的关键表面重建很吃时间不做皮层分析就关掉一个被试能省十几分钟。3.3 输出文件命名规则与体素尺寸选择跑完之后输出目录会多出一堆前缀文件不认识命名规则很容易拿错数据。规则是按前缀字母叠加p表示组织分割结果w表示归一化到标准空间m表示调制l表示另外一些标记。组合起来p1个体空间灰质概率图数值范围 0 到 1mwp1归一化并调制后的灰质图做 VBM 统计用的就是它mwp2对应的白质图p0原始图像经过偏差校正后的版本拿错文件的后果很直接用p1去做组间比较比较的是概率不是体积结论基本没有意义。我见过最典型的一个翻车是有人把wp1归一化但没调制当成体积指标跑出来组间差异方向全是反的回头查了两周才发现少了一个m前缀。体素尺寸的选择是另一个容易含糊的点。归一化时默认会重采样到 1.5 mm 各向同性做 VBM 通常够用如果样本量小、预期效应也小可以降到 1 mm 提高空间分辨率但文件体积和计算量会涨到三四倍平滑核也要相应调整。反过来只做粗略的 ROI 体积统计保持 1.5 mm 甚至 2 mm 更划算。3.4 质量检测报告与 IQR 评级CAT12 每个被试跑完会生成一份 XML 报告和一张预览图里面最值得看的是图像质量评级。它把多个指标综合成一个百分制分数再映射成 A 到 E 的等级。经验阈值是A 和 B 放心用C 需要人工看图确认D 和 E 建议剔除或者重跑。这个评级不是玄学它主要反映配准残差、组织对比度和噪声水平。评级偏低常见于三种情况扫描时头动明显、T1 对比度不足、视野切掉了小脑或顶部。前两种调参数救不回来只能剔除第三种如果只是轻微截断可以尝试调整配准初值。批量处理时一定要把这套指标抽出来汇总否则三十个被试里混进两个 D 级统计结果就被污染了。下一章会给一个从 XML 里提数的脚本直接生成可排序的表格。4. 批处理落地把 GUI 操作换成可重复执行的脚本图形界面点一遍能出结果点三十遍就是灾难而且不可复现。这一章把上一章的批处理结构封装成能跑在命令行、能断点续跑、能输出失败清单的脚本。目标是一个被试出错不影响整批第二天早上看日志就能知道哪个该重跑。4.1 单被试的命令行调用先解决不进 MATLAB 界面也能跑的问题。现代版本用-batch参数最省事#!/bin/bash # 单被试分割失败时保留日志 matlab -batch addpath(/opt/toolboxes/spm12); \ addpath(genpath(/opt/toolboxes/cat12)); \ spm(defaults,FMRI); \ spm_jobman(initcfg); \ run(/opt/pipeline/seg_one.m) \ -logfile /data/logs/sub-01.log-batch的好处是执行完自动退出退出码能反映是否异常方便外层脚本判断。-logfile把标准输出重定向到文件出问题时不用靠记忆复现。注意命令里的分号不能省整串是一条 MATLAB 语句。对应的seg_one.m就是把第 3 章的批处理结构包一层函数输入输出做成参数function seg_one(inFile, outDir) % 单个被试的分割入口路径全部走绝对路径 if ~exist(outDir, dir); mkdir(outDir); end clear matlabbatch; matlabbatch{1}.spm.tools.cat.estwrite.data {[inFile ,1]}; matlabbatch{1}.spm.tools.cat.estwrite.nproc 2; matlabbatch{1}.spm.tools.cat.estwrite.opts.tpm { /opt/toolboxes/cat12/tpm/TPM.nii}; matlabbatch{1}.spm.tools.cat.estwrite.extopts.LASstr 0.5; matlabbatch{1}.spm.tools.cat.estwrite.output.GM.mod 1; matlabbatch{1}.spm.tools.cat.estwrite.output.GM.warped 1; matlabbatch{1}.spm.tools.cat.estwrite.output.surface 0; % 结果统一落到指定输出目录避免污染原始数据目录 matlabbatch{1}.spm.tools.cat.estwrite.output.warps [1 0]; try spm_jobman(run, matlabbatch); catch ME % 把错误原样抛出由外层脚本捕获写进失败清单 fprintf(2, SEG_FAILED: %s\n, ME.message); rethrow(ME); end end函数化的意义在于隔离。把批处理写死在脚本里加一个被试就得改一次代码做成inFile / outDir两参数外层只负责遍历职责清楚。try-catch里那句fprintf(2, ...)是写给日志看的2是标准错误流方便外层的 grep 抓取。rethrow保证异常不被吞掉退出码才会非零。4.2 批量遍历与断点续跑批量脚本的核心不是循环是跳过已完成。判断依据建议用输出文件是否存在而不是维护一个状态文件——状态文件和数据目录一旦不同步就会出现以为跑过了其实没有的惨案。% 批量遍历跳过已完成的被试 rootDir /data/raw; outRoot /data/derivatives; subs dir(fullfile(rootDir, sub-*)); failed {}; for i 1:numel(subs) sid subs(i).name; inFile fullfile(rootDir, sid, anat, [sid _T1w.nii]); outDir fullfile(outRoot, sid); % 关键判据调制后的灰质图存在就跳过 probe dir(fullfile(outRoot, sid, mwp1*.nii)); if ~isempty(probe) fprintf(SKIP %s\n, sid); continue; end if ~exist(inFile, file) fprintf(MISSING %s\n, sid); failed{end1} sid; %#okSAGROW continue; end try seg_one(inFile, outDir); fprintf(DONE %s\n, sid); catch failed{end1} sid; %#okSAGROW end end % 失败清单落盘第二天直接照着重跑 writelines(failed, /data/logs/failed.txt);跳过判据选mwp1*.nii而不是随便一个输出文件是因为分割中途崩溃时会留下部分输出用最靠后的产物做判据最安全。writelines在老版本 MATLAB 上不存在换成fopenfprintf循环即可别因为一个函数把整段脚本卡住。还有一个容易被忽略的点输出目录和原始数据目录必须分开。有人图省事让 CAT12 直接输出到原始数据所在目录结果预处理产物和原始 DICOM、NIfTI 混在一起后续再遍历时把所有mwp1也当输入扫进去了重复计算还把磁盘塞满。4.3 日志与失败清单日志不是跑完再看的东西是跑的时候用来定位的。我一般的做法是每被试一个日志文件文件名带被试编号和日期外加一份汇总的失败清单。日志里至少要有四类信息开始时间、输入路径、异常信息、结束时间。少了时间戳多个任务并发时根本分不清先后。如果不想自己造轮子-logfile已经能兜住大部分需求唯一要补的是把每个被试的失败原因单独摘出来。上面那个catch里打印的SEG_FAILED前缀就是为此设计的跑完之后一句命令就能汇总grep -h SEG_FAILED /data/logs/*.log | sort | uniq -c | sort -rn这条命令的输出直接告诉你哪类错误最常见比一个个翻日志高效得多。真正常见的就那么几种下一章逐一拆。5. 避坑与排查五条血泪经验对着看这一章是我自己踩过的、以及在别人机器上复现过的五类问题按现象、原因、解决写。放在这里而不是散在各章是因为出问题时人是慌的需要一份能直接对照的清单。5.1 启动就报未定义函数现象输入cat12之后提示Undefined function or variable spm或者 CAT12 窗口一闪而过。原因路径顺序错了或者根本只加了 CAT12 没加 SPM12。CAT12 的启动函数第一步就是调用 SPM 做版本探测探测不到直接退出异常信息还不一定友好。解决严格按先addpath(/opt/toolboxes/spm12)、再addpath(genpath(/opt/toolboxes/cat12))的顺序注册注册完savepath固化。如果仍然报错用which spm确认拿到的是不是你期望的那一份用户目录下残留的旧版本优先级可能更高。5.2 跑到一半内存爆掉现象批量处理时前几个被试正常跑到中途 MATLAB 直接崩溃或者系统开始疯狂换页日志停在某个被试没有任何输出。原因nproc开太大。每个并行进程都会复制一份分割所需的中间数据峰值内存大约是单进程的两到三倍。默认值在某些版本上是 4机器只有 16 GB 内存时撑不住。解决把nproc降到 1 或 2先测单被试的峰值内存再定。经验值是一张 1 mm 分辨率的 T1 全流程峰值在 2 GB 上下并行数乘上去不能超过物理内存的七成。另外别在同一天既跑并行又开大图查看器两者抢内存非常凶。5.3 输出目录里找不到 mwp1现象分割跑完了日志显示成功但输出目录只有p1、p2没有mwp1。原因output.GM.mod或output.GM.warped有一个没打开。这两个开关是独立的只开native 1就只出个体空间的结果。解决三个开关按需组合做组间体积比较至少要warped 1且mod 1。改完记得清掉旧的 matlabbatch 结构字段是叠加的不清场容易留下上一轮的残留值。5.4 路径里有中文或空格现象某些被试报文件读取失败另一些同样命名规则的却正常报错信息指向的路径看起来完全正确。原因SPM 底层的文件读写对非 ASCII 字符和空格的支持一直不太好尤其是批量拼接路径时空格会被当成参数分隔符。解决原始数据、输出目录、工具箱路径三者全部用纯英文、无空格、无特殊符号的路径。这一条看起来最没技术含量但它是排查成本最高的坑之一因为报错位置往往和真实原因隔了好几层。我现在的习惯是项目初始化时就建好/data/raw、/data/derivatives两个顶层目录所有人往里放数据从源头掐掉这个问题。5.5 质量评级普遍偏低现象整批被试的评级集中在 C 和 D单看某一张图像又觉得没什么大问题。原因多数情况下是配准残差偏大常见于视野不全、头动明显或者 T1 对比度弱的数据。也可能是一批数据用了同一个不合适的配准初值。解决先抽三到五张图人工确认排除图像本身的问题确认是参数导致的话把extopts.regstr从 0.5 适度放松同时把extopts.LASstr上调一档重跑一个小样本对比评级变化。如果调整之后评级没有改善就不要再救了这批数据的成像质量本身达不到分析要求硬调参数只会把噪声压进结果里。6. 二次开发改参数、写评分脚本、把流程封装成自己的工具装通、跑通之后真正的价值在于把这套东西改造成贴合自己项目的流水线。三个方向最值得投入。第一个是参数固化。所有会随项目变化的参数——平滑核大小、体素尺寸、输出开关——都抽到一个配置文件里脚本只读配置。我习惯用一张表管起来参数位置常见取值影响LASstrextopts0.5 / 0.6局部自适应强度低对比度数据上调regstrextopts0.3 / 0.5配准正则化越小形变越自由nproc顶层1 / 2并行数受内存约束体素尺寸归一化1.0 / 1.5分辨率与计算量权衡surfaceoutput0 / 1是否做表面重建第二个是质量评分自动化。从每个被试的 XML 报告里把评级提出来汇总成 CSV按分数排序前几名重点看。核心逻辑不复杂% 从 cat12 输出的 XML 里提取质量评级相关字段 f dir(/data/derivatives/sub-*/cat_*_seg.xml); rows cell(numel(f), 2); for i 1:numel(f) txt fileread(fullfile(f(i).folder, f(i).name)); % 用正则抓评级字母比解析整个 XML 结构轻量 tok regexp(txt, qualityrating([A-E])/qualityrating, tokens); rows{i,1} f(i).folder; rows{i,2} tok{1}{1}; end T cell2table(rows, VariableNames, {subject,rating}); writetable(T, /data/logs/qc.csv);fileread把整个文件读成字符串regexp抓目标字段避开了完整 XML 解析的层级遍历对固定格式的报告足够稳。字段名要以实际输出为准不同小版本的标签可能有差异跑之前先打开一份 XML 确认。这段脚本真正的用途不是打分而是把哪个被试该重跑这件事变成可排序的列表省掉人工逐个翻报告的时间。第三个是封装。把分割、QC、汇总三步串成一条命令输入一个数据根目录输出一张结果表。封装时守住一条原则每一步都留中间产物和日志不要把异常吞在自己写的函数里。我在早期版本里图省事把try-catch写成了静默跳过结果一批数据跑完显示全部成功实际上三分之一是空输出等到统计阶段才发现样本量对不上。从那以后我每次改完流水线都会先手动挑三个被试——一个正常的、一个视野不全的、一个明显有头动的——强制走一遍全流程确认正常的那份出结果、异常的那两份被正确标记进失败清单再放开跑整批。这个习惯帮我挡掉过好几次批量事故。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询