SCUT-71 Vision Studio
智能车视觉仿真环境 —— 只写算法,其余交给环境。
这个 VS Code 插件把「编译 → 运行 → 看画面 → 观察变量」串成一条不用读文档的路:
按一下「编译」就能看到你的边缘检测跑在 188×120 的灰度图上,
并且能在侧边栏里自由勾选要看哪些全局变量。
开源地址 / 问题反馈:https://github.com/maomao23314/71-vision-studio
五分钟上手
第一次打开插件、还没打开任何工程时,侧边栏会直接显示一个引导页,
只有三个按钮:新建工程 / 打开已有文件夹 / 环境自检。
不需要先记住命令名 —— 点「新建工程」跟着问答走完就行。
打开侧边栏:左侧活动栏点 SCUT-71 Vision 图标,展开「仿真」视图。
找不到命令?按 Ctrl+Shift+P 打开命令面板,输入 SCUT-71 就能看到全部命令。
新建工程:引导页点 新建工程(或命令面板 → SCUT-71: 新建仿真工程)。
它会连着问你三件事,都有默认值,一路回车也能建:
- 工程名(默认
vision-project)
- 图像尺寸(默认
188x120,按你的摄像头改)
- 每帧处理函数名(默认
camera_process,模板自带的那个)
这三项直接写进工程的 scut_project.json,所以建出来当场就能编译,
不用再去面板里补配置。
(也可以直接打开一个已经有 code/ 的工程文件夹,跳过这一步。)
换成你自己的代码 / 函数名:把你的算法放进 code/,
然后点工具栏最右边的 ⚙ 打开配置面板,在「钩子函数 › 每帧处理函数」里改。
这一栏下面有一个下拉框,列的是 code/ 里真实存在的 void f(void)
(已排除 static)。选一个就填好 —— 不用手打,也不会因为拼错一个字母
而在链接期看到 undefined reference。
把测试图放进工程:命名 1.bmp、2.bmp…(也支持 0.png 起的编号,
后端会自动探测)。放哪都行 ——
- 直接放
pic/:这是默认值,不用配任何东西;
- 或放
pic/1/ 这类子目录:去「测试图集 › 图集目录」填 pic/1。
图集目录可以指向工程内任意目录,也能指到工程外(多个工程共用一份图集)。
模板不附带任何图 —— 图集是你的数据,不是环境该替你决定的东西。
新建工程时插件会建一个空的 pic/1/ 并放一份 README-pic.txt,照着看即可。
图集目录、后缀、起始编号都能在配置面板的「测试图集」里改,
改完立即生效,不需要重新编译。
编译并运行:点工具栏的 编译(或按 Ctrl+Shift+B),
然后用 下一张 ▶ 或 → 开始看。
全程不需要写 launch.json,也不需要写任何注册代码 ——
调试配置由插件在 F5 时现场合成,变量清单由构建期自动符号发现产出。
本机没有编译器也没关系:第一次编译时插件会问你要不要
自动下载一份精简版 LLVM-MinGW(约 165 MB,只下一次)。
它还会自动探测 PATH 上已有的 clang —— 已经装过就不会重复下载。
侧边栏:仿真视图
| 区域 |
作用 |
| 图片1 |
折叠区(默认收起)。RGB 真彩帧(image-rendering: pixelated 放大,边缘不会被插值糊掉)。鼠标移入出现缩放浮层:适应 / 缩小 / 放大 / 1:1;滚轮以光标为锚点缩放,按住左键可拖动 |
| 图片2 |
折叠区(默认收起,和图片1一样)。画什么由你的代码决定:SCUT_EnvCopyOutput(2, …) 整幅搬,SCUT_OutImageSet(2, …) 点着画。缩放、拖动与图片1各自独立 |
| 工具栏 |
编译 · 调试 · ◀ 上一张 / 下一张 ▶ · 测速 · ■ 停止 · ⚙ 设置 |
| 选择要观察的变量 |
折叠区。勾选决定「变量查看」里显示哪些;可搜索、可全选/全不选 |
| 变量查看 |
折叠区(默认展开)。显示勾中的变量值;主动注册的变量【恒显示】并置顶 |
| 计时 |
折叠区。周期数(跨机器可比)在标题上就能看到 |
| 运行日志 |
折叠区(默认折叠)。你代码里 SCUT_Log(...) 的输出出现在这里,标题上显示行数 |
勾选状态通过 webview 的 setState() 持久化(而不是 retainContextWhenHidden,
后者内存开销大且隐藏时行为在官方文档里自相矛盾)。
快捷键
| 动作 |
键 |
| 编译 |
Ctrl+Shift+B |
| 调试 |
F5(视图里的「调试」按钮更明确,不会和别的 C 插件抢 F5) |
| 上一张 / 下一张 |
+ / - 或 ← / →(面板有焦点时) |
| 测速 |
F9(面板有焦点时) |
| 停止 |
Shift+F5(面板有焦点时) |
这几个键由面板自己的脚本处理,"有没有焦点"由浏览器判定:
点一下面板就归它,点回代码就还给编辑器 —— 在 .c 里敲 + 永远是加号。
注意:Ctrl+Shift+B 被本插件占用为「编译仿真程序」,
这会覆盖 VS Code 默认的「运行生成任务」。若你需要原来那个,
可以在 keybindings.json 里改掉本插件的这条绑定。
变量面板
| 分组 |
来源 |
显示 |
| 主动暴露 |
代码里显式 SCUT_Watch / SCUT_WATCH_SCALAR 注册的 |
排前面、置顶、恒显示(不用勾) |
| 自动捕获 |
构建时扫描调试信息发现的全部全局量 |
排后面,勾选后显示 |
勾选后不需要重新编译:变量快照每帧全量发送,勾选只影响显示。
边界:从未被引用过的 static 变量会被编译器整个删掉,发现不了 ——
这与调试器的行为一致。
画调试标注
标注画在覆盖层上,由调度器合成进输出图,所以是彩色的。
把绘图调用放在「每帧后处理函数」里 —— 它不计入处理时间
(车上没有屏幕,绘图算进算法耗时会让你去优化一段车上根本不存在的代码)。
四个绘图函数
| 函数 |
作用 |
SCUT_DrawPoint(x, y, color) |
画一个像素 |
SCUT_DrawLine(x0, y0, x1, y1, color) |
画直线 |
SCUT_DrawRect(x0, y0, x1, y1, color) |
画空心矩形(四条边) |
SCUT_DrawText(x, y, color, fmt, ...) |
画 ASCII 文字,用法同 printf |
坐标越界会自动忽略,不用自己判断。
SCUT_DrawText 只支持 ASCII(内置 8×8 字库)。别拿它显示读数,
要看数值请用 SCUT_Log 或变量面板。
预定义颜色(11 个)
SCUT_COLOR_BLACK SCUT_COLOR_WHITE SCUT_COLOR_RED SCUT_COLOR_GREEN
SCUT_COLOR_BLUE SCUT_COLOR_YELLOW SCUT_COLOR_CYAN SCUT_COLOR_MAGENTA
SCUT_COLOR_ORANGE SCUT_COLOR_GRAY SCUT_COLOR_LIGHTGRAY
挑几个高对比、彼此好区分的就够。
自建颜色
用 SCUT_RGB(r, g, b),每个分量 0..255:
scut_u32 my_orange = SCUT_RGB(255, 128, 0);
SCUT_DrawLine(0, 0, 10, 10, my_orange);
SCUT_DrawPoint(x, y, SCUT_RGB(g, g, g)); /* 灰度也用同一个宏 */
不要手写十六进制字面量。颜色内部是 0x00BBGGRR(跟 Windows COLORREF 一致,
方便老代码迁移),所以 0xFF0000 是蓝色不是红色,极容易记错。
一律用 SCUT_RGB(r,g,b) 或预定义名。
配置放在哪
只有一个地方:工程根目录的 scut_project.json。
它跟着工程走 —— 能进 git、能发给同学、换机器不用重配。
编辑入口是插件自己的配置面板(工具栏 ⚙,或命令面板「SCUT-71: 打开设置」),
也可以直接打开那个 JSON 改文本。
| 分组 |
里面有什么 |
改完要重编译吗 |
| 图像尺寸 |
图像宽度 / 高度 |
✅ 要 |
| 图像数组 |
输入图像数组名、结果图数组名 |
✅ 要 |
| 钩子函数 |
开机函数 / 每帧处理函数 / 每帧后处理函数 |
✅ 要 |
| 测试图集 |
图集目录、图集后缀、图集起始编号 |
❌ 立即生效 |
| 运行期 |
每帧重复次数、测速重复次数 |
❌ 立即生效 |
| 工具链 |
工具链根目录、Python 解释器、自动发现变量 |
❌ 立即生效 |
为什么尺寸必须重编译:C 语言里数组大小必须是编译期常量,
而算法里到处是 int line[SCUT_IMAGE_H];。这是语言的硬约束,
不是设计偷懒。构建时会把尺寸写进 .scut/gen/scut_config.h。
为什么不用 VS Code 的 settings.json:0.9.4 之前用过,踩了三重坑
(配置跟着用户走而不跟着工程走、嵌套分组的键注册不上、
两处真值互相覆盖)。现在配置只有工程 JSON 一个真值。
没有「编译模式」这类开关:优化等级是固定约定 ——
用户代码恒为 -g -O0(断点不漂移、变量看得见),环境自身恒为 -O2。
自动保存
改完不用按保存:停手约 0.6 秒后自动写入,底栏显示「已自动保存到 scut_project.json」。
底栏左边的 自动保存 开关默认开着;关掉后改完要按「保存」或 Ctrl+S。
为什么不逐键写盘:改图像宽度会经过 1 → 10 → 102 这些合法中间值,
逐次写盘时若有构建在跑,可能读到 1 编出 1×120 的契约头。
合并到停手后写一次,中间态一次都不落盘。
改完立刻关面板也不丢:延迟写发生在扩展侧,关面板时会把未落盘的那次补写完。
这个开关不进 scut_project.json —— 它是本机习惯,不是工程事实。
插件自带整个 SDK(装完即用,不需要额外目录)
装上这个 .vsix 就够了。 插件内部打包了一份完整的 SDK 源码:
<扩展安装目录>/sdk/
├── core/include/ ← 编译你的算法时的头文件
├── core/src/ ← 核心库源码
├── bind/scut_bind.c ← 唯一知道编译期图像尺寸的编译单元
├── backends/headless/ ← 提供 main() 的仿真宿主
└── tools/*.py ← 官方构建脚本
所以你不需要在磁盘上另外放一份 SDK 仓库,也不需要把仓库当工作区打开。
插件在安装目录里找不到 SDK 时,才会退回去找仓库(那是给源码开发/F5 调试用的路径)。
为什么 libscut_core.a 是源码而不是预编译好的库?
静态库里的目标文件与产生它的编译器、ABI、CRT 绑死。分发预编译的 .a,
一旦对方工具链不匹配就是一堆指不到病根的链接错误。
所以分发源码,在你自己的机器上用你自己的工具链编一次(约 1.5 秒),
之后增量复用——改算法不再重编环境。
从源码开发插件时,extension/sdk/ 是同步生成的,不入版本库。
同步命令:cd extension && npm run sync-sdk。
需要的工具链
插件不随包分发任何第三方二进制(clang 带不带取决于你选哪条路),
它做的是:告诉你缺什么、为什么缺、以及装完之后要做什么。
| 工具 |
必需? |
从哪来 |
clang / clang++ |
✅ 编译必需 |
LLVM-MinGW(自带 MinGW sysroot)——插件可代下载 |
| Python 3.7+ |
✅ 构建脚本必需(插件不代下载) |
python.org / Anaconda 均可;不需要任何第三方库 |
lldb-dap |
可选(调试用) |
LLVM-MinGW 自带 |
clangd |
可选(建议装) |
LLVM-MinGW 自带;装 clangd 扩展后补全/跳转更准 |
变量自动发现不需要 objdump。
早先这里要求装 binutils 的 objdump(因为 LLVM 21 删掉了
llvm-objdump --dwarf=info,而 llvm-mingw 自带的 objdump 只是个转发脚本)。
现在这条依赖已经去掉:变量发现改成纯 Python 读 .debug_info 的字节,
clang / gcc、DWARF 4 / 5 都能读,机器上装没装 binutils 完全无关。
换句话说——编译能过,变量面板就有内容。
工具链根目录留空时,依次探测:SCUT71_TOOLCHAIN 环境变量
→ 插件自己下载过的目录 → PATH。都找不到会弹窗问你
(指定已有的,或帮你下载一份)——插件不会擅自猜你机器上的安装位置。
配置在哪里改:配置面板的「工具链 › 工具链根目录」,
它存在工程根的 scut_project.json 里。
代价要说清楚:工具链是本机环境,跟着工程走意味着换机器要重填一次。
关于 C_Cpp.intelliSenseEngine
插件通过 configurationDefaults 把 cpptools 的 IntelliSense 默认关掉,
避免它和 clangd 互相打架。这只是默认值,你自己的设置优先级更高,
不会被强制覆盖。
插件不会自己启动语言服务:它只负责在「环境自检」里告诉你
找没找到 clangd。想用补全就装 clangd 扩展(LLVM-MinGW 里自带 clangd.exe,
也可以单独装),不装也不影响编译与仿真。
许可
GPL-3.0。LLVM 相关组件为 Apache-2.0 WITH LLVM-exception。
源码仓库:https://github.com/maomao23314/71-vision-studio