LabVIEW实现SSH远程命令执行:libssh2库封装与避坑实践

简介:这是一份面向 LabVIEW 开发者的 SSH 客户端扩展库,基于开源 libssh2 封装,可在 NI LabVIEW 中直接发起 SSH 连接,与远程服务器进行通信。它适用于需要远程命令执行、文件上传下载、自动化运维或设备管理的工程场景,使用者最好具备一定 LabVIEW 基础,便于直接复用或二次修改。压缩包约 9.24MB,内容以 LabVIEW 封装库、VIPM 打包组件和示例 VI 为主;由于上游未给出文件总数与类型拆分,具体目录可在解压后按需查阅。随包示例覆盖从远程服务器下载文件、上传文件到远程服务器、在服务器上执行单条命令并读取响应三类典型操作,与 libssh2 C 库中的 scp、scp_write、ssh2_exec 示例相对应,既能看到完整接线方式,也能快速迁移到自己的项目中。目前已有 1107 人学习下载,适合需要快速为 LabVIEW 增加 SSH 客户端能力的工程师作为参考模板。

1. 为什么要在LabVIEW里做SSH客户端:libssh2-labview的破圈价值

你负责的设备是嵌入式Linux板卡,上位机却是LabVIEW,每次想登进去敲两条命令、拉个日志,都要开终端、输密码、踩一堆exports的坑。某天我发现了一个叫libssh2-labview的库,它把libssh2这个C语言SSH客户端库整个搬进了LabVIEW,不需要在电脑上额外跑一个Python或OpenSSH中间进程,连登录带执行命令全部由VI直接调用动态库完成。这套方案看起来只是封装了一层CLFN,实际上解决了LabVIEW工程师最头疼的问题:怎么用G语言和SSH协议握手、认证、建通道。如果你正在做自动化测控系统、设备远程维护、或者黑盒测试里要临时改设备配置,这个库值得你下载下来拆一遍。

2. 核心模块拆解:libssh2封装层的设计与连接流程

2.1 库的整体架构:VI、动态库和回调函数的分工

libssh2-labview不是一个大而全的框架,而是一组基于CLFN(Call Library Function Node)的包装VI。顶层是应用开发者直接托拽的API VI,比如“SSH Connect”、“SSH Execute Command”、“SSH Disconnect”。中间层是几个包装VI,负责把LabVIEW的数据类型(字符串、数值、布尔)转换成C语言需要的指针和长度。底层就是libssh2的DLL以及它依赖的OpenSSL DLL。

我拆这个库的时候,发现它的目录结构非常规整,大致是这么四层:

libssh2-labview/ ├── lvlibs/ │ └── libssh2_lib.lvlib ├── viuser/ │ ├── SSH_Connect.vi │ ├── SSH_Authenticate.vi │ ├── SSH_Execute_Command.vi │ └── SSH_Disconnect.vi ├── support/ │ ├── libssh2.dll │ ├── libeay32.dll │ └── ssh_exec.vi └── examples/ └── Simple SSH Command Demo.vi

应用层VI不直接调DLL,而是调中间层。比如SSH_Execute_Command.vi内部会先调support/ssh_exec.vi,这个中间层负责把LabVIEW字符串转换成char*,再通过CLFN调用libssh2_channel_exec。为什么要隔一层?因为直接调CLFN的话,内存管理、错误码映射、句柄类型转换会散落在每个调用点,一旦libssh2更新API,你就要改几十个VI。隔一层后,只需要改中间层。

架构上最值得学习的是它把libssh2的会话指针封装成了一个整数句柄。LabVIEW里没法直接持有C指针,所以库内部用了一个四字节的整数来保存LIBSSH2_SESSION*,每个VI都用这个句柄来索引当前的会话。这有点像一个简易的句柄表,避免把指针变成浮点数或字符串导致精度丢失。

2.2 关键数据映射:会话句柄与通道句柄在G语言里的表现

libssh2里有几个核心对象:LIBSSH2_SESSION、LIBSSH2_CHANNEL、LIBSSH2_KNOWNHOSTS。这个库是如何用LabVIEW数据类型表示它们的?

我看了一下它的内部簇定义,大概是这样的(用文字示意):

LabVIEW类型C类型用途
U32句柄LIBSSH2_SESSION*客户端会话上下文
U32句柄LIBSSH2_CHANNEL*一个SSH通道,一条独立的执行流
U32句柄LIBSSH2_KNOWNHOSTS*已知主机列表,用于防中间人
字符串char*用户名、密码、命令、远端输出
数值uint32_t退出码、错误码

这种设计有一个好处:你把句柄存在LabVIEW的移位寄存器或者功能全局变量里,就能在多个VI之间传递,而不会出现LabVIEW强制类型转换导致的高位截断。很多开发者踩过一个坑:把C指针直接放进I32的表示法,结果在64位系统上指针被截断成32位,导致访问违例。这个库的做法是强制用U32表示句柄,并提供一个“句柄验证VI”来检查传入的句柄是否是当前合法的会话。

通道句柄同样用U32存储。注意一个会话可以打开多个通道,比如同时执行两条命令。库里的SSH_Channel_Open.vi和SSH_Channel_Close.vi专门管理这些句柄,底层对应的是libssh2_channel_open_session和libssh2_channel_close。

2.3 连接与认证流程:从TCP握手到session_startup

整个核心流程我拆成了五步,每一步对应一个CLFN调用。这里我用C伪代码展示底层逻辑,方便你看懂LabVIEW包装VI内部到底调了什么:

// 1. 初始化libssh2库,注意每个进程只需要调用一次 libssh2_init(0); // 2. 创建会话对象,同时打开TCP socket LIBSSH2_SESSION *session = libssh2_session_init(); int sock = socket(AF_INET, SOCK_STREAM, 0); connect(sock, &server_addr, sizeof(server_addr)); // 3. 握手:交换SSH协议版本和密钥,这一步会阻塞 libssh2_session_handshake(session, sock); // 4. 用户认证:密码模式或公钥模式 libssh2_userauth_password(session, username, password); // 5. 打开通道,执行命令 LIBSSH2_CHANNEL *channel = libssh2_channel_open_session(session); libssh2_channel_exec(channel, "uname -a");

在LabVIEW中,SSH_Connect.vi从功能上合并了第2、3步。它接收远程IP、端口,内部先调用LabVIEW的TCP Open Connection建立TCP连接,再把连接句柄传给libssh2。这里有个容易忽略的细节:libssh2自身不负责TCP连接,你要么把LabVIEW已经打开的TCP网络连接句柄传进去,要么在本地打开一个socket并传socket descriptor。这个库的做法是在包装VI里直接调用Windows Socket API来获取和TCP连接对应的socket句柄,因为LabVIEW的TCP API返回的是LabVIEW内部句柄,不是C的socket fd,直接传给libssh2会失效。

认证过程也一样。库的SSH_Authenticate.vi提供两种方式:密码认证和公钥认证。公钥认证时,你需要传私钥文件路径和公钥文件路径,底层调用libssh2_userauth_publickey_fromfile。这里最容易翻车的是密码里带特殊字符,比如@、$,LabVIEW的字符串控件默认会做反斜杠转义,导致传给libssh2的密码是转义后的版本。所以在这个库的设计里,调用认证VI前,密码必须经过一个“raw string”处理,禁止LabVIEW自动转义。

看一个完整的认证后执行命令的VI序列:

SSH_Connect.vi (ip, port, timeout) -> output sessionHandle SSH_Authenticate_UserPwd.vi (sessionHandle, username, password) -> output authOK SSH_Execute_Command.vi (sessionHandle, "ls -la /var/log") -> output stdoutString SSH_Disconnect.vi (sessionHandle)

SSH_Execute_Command.vi内部逻辑我重点讲一下。它先libssh2_channel_open_session,再libssh2_channel_exec,然后循环调用libssh2_channel_read读取远端输出。循环会一直读到返回0(无数据)或返回负值(出错)。这里有一个阻塞陷阱:libssh2_channel_read在数据没有完全到达前会阻塞,导致LabVIEW界面卡死。库作者的解决方法是把读取循环放在超时结构里,如果一个时间片内没有新数据就强制跳出,并把已读到的部分返回。这是很多自己封装libssh2的人最容易忽略的地方。

3. 运行与调试:从零跑通一个SSH执行命令的Demo

3.1 准备运行环境:DLL、依赖和LabVIEW版本

拿到这个库后,别急着打开VI,先把support目录下的DLL放到合适的位置。libssh2.dll依赖于libeay32.dll和ssleay32.dll(OpenSSL 1.0.x版本),如果缺了这些,库在加载时会直接报“无法定位程序输入点”的错误,或者干脆不显示任何错误而返回一个错误代码。我习惯把这些DLL统一放到LabVIEW的项目根目录下的deps/文件夹,然后通过配置CLFN的“指定路径”指向这个绝对路径。注意,直接双击VI运行可能一切正常,但打包成可执行程序后,DLL路径会变化,必须用Build Specifications的“包含动态DLL”选项把DLL打包到data目录,否则成品应用运行时会黑匣子一样崩溃。

LabVIEW版本方面,我看到这个库的源码是基于LabVIEW 2015之后的数据类型写的,使用了uint64和集群常量。建议用LabVIEW 2018以上版本,因为低版本对U32簇常量的支持有点弱,会出现“VI无法保存为当前版本”的提示。

3.2 部署示例VI:配置参数和执行命令

打开examples/Simple SSH Command Demo.vi,前面板上有四个输入:IP Address、Port、Username、Password。这里有三个关键设置:

  • Port默认是22;但如果你连接的是非标准端口(比如某个设备的SSH绑在2222),需要直接修改这个值。有些网友在这个位置填了字符串“22”,会直接被LabVIEW强制转换错误,连线变红,是因为示例VI里这个控件的表示法为U16,字符串不能直接连上去。解决方法是右键控件选择“替换为数值输入控件”,或者写一个字符串转U16的转换节点。
  • Password输入框的属性里必须关闭“密码显示”模式吗?不需要,但要注意开启Limit Input?这一点倒是无所谓。
  • Command输入框默认写的是uname -a。你可以改成常用设备检查命令,比如df -h或cat /proc/cpuinfo。注意一次只能执行一条命令,如果命令里带管道符|或重定向>,部分远端shell环境下会不工作,原因是libssh2的channel_exec通过exec调用shell,而这种方式不等于交互式shell,管道符需要shell解析。如果必须用管道,我建议命令外再套一层:bash -c "df -h | head -n 5"。

3.3 执行与结果回读:同步阻塞和异步轮询两种模式

这个库的示例里用的是最简单的同步模式,点击运行按钮后,整个VI会卡在读取循环直到命令执行结束。可以看到前面板的输出字符串里滚动输出结果。

我写了一个测试流程来验证:

1. 点击 Run 前,先在远端设备上启动一个耗时的命令(比如 sleep 5 && echo done) 2. 观察VI界面,发现整个界面冻结约5秒 3. 输出字符串一次性返回“done”

这说明它的默认读取逻辑是阻塞的。如果想要异步模式,库的SSH_Execute_Command.vi第三个输入端Timeout (ms)设置为0或负值,内部就会进入非阻塞轮询模式,每次调用只读取当前缓冲区已有的数据并立即返回。这时你需要用循环反复调用它,直到返回的Command Finished为TRUE。这种模式适合放在LabVIEW的状态机里,不会阻塞用户事件。实际开发时我一般把Timeout设为100ms,这样每次轮询间隔可控,CPU消耗也比纯非阻塞低。

3.4 调试技巧:学会看libssh2错误码和日志输出

跑不通的时候,第一反应不是去查LabVIEW的连线,而是看SSH Connect返回的Error Code。libssh2的错误码是负值,常见几个:

错误码含义
-1SSH2_ERROR_NONE 正常,实际上正常时返回0
-7无法建立会话
-16认证失败,通常是用户名或密码错误
-28通道打开失败,可能是达到最大通道数
-37SSH2_ERROR_SOCKET_SEND,socket无法发送数据,常见于远端断线

调试时,我建议在SSH_Execute_Command.vi内部加入一个libssh2_session_last_error的调用来获取详细错误文本。但这个库原本没有暴露这个VI,你需要自己加一个CLFN节点,引用libssh2_session_last_error(session, &errmsg, &errmsg_len),然后把errmsg指针转换为字符串返回。我在改这个库时就是加了这么一个VI,才把“连接被重置”这种问题从黑匣子变成了可见消息。还有一个通用技巧:在调用libssh2_init前设置libssh2_trace(session, LIBSSH2_TRACE_SOCKET),这样SSH协议的收发数据包会打印到标准输出,LabVIEW里需要通过Print Output窗口查看。这个库没默认开启,但在调试协议问题的时候非常好用。

4. 常见问题与避坑:SSH连接中的那些玄学

4.1 连接失败,错误码-37

现象:运行SSH_Connect.vi,前面板报错-37,但远端设备用PuTTY都能正常连接。
原因:这是socket发送错误,但很多时候根因不是网络断,而是LabVIEW TCP连接句柄和libssh2期望的socket描述符类型不匹配。尤其是你在同一台电脑上先用了TCP Open Connection,又把这个LabVIEW句柄传给了libssh2,它以为是个C int类型的socket fd,结果是内存垃圾。
解决:不要混用LabVIEW TCP函数和libssh2。直接让库内部的Socket Connect子VI来创建连接,这个子VI内部是用Windows Socket API完成的,返回的是真正的SOCKET描述符。如果你非要自己连好再传,必须把LabVIEW连接句柄转换为一个refnum并强制类型转换为uintptr_t,但这种方法在64位系统上极易踩坑,不建议。

4.2 认证成功但没有命令输出

现象:SSH_Authenticate返回成功,SSH_Execute_Command也返回了,但是Output字符串是空的。
原因:不靠近端命令的所谓“成功返回”,libssh2_channel_exec发出命令后,你需要一直读到EOF才算真正结束。常见的错误是只调用了一次channel_read,此时远端命令才刚启动,缓冲区还没有数据。
解决:按上一节讲的,把读取循环放到一个while循环中,循环条件是bytes_read > 0,同时设置最大循环次数或超时。还有一种情况是命令本身没有输出(例如cd /tmp),此时应该返回退出码0而不是空字符串。这个库的Command Finished标志就是用来区分这种情况的。

4.3 中文乱码问题

现象:设备端返回的中文日志在LabVIEW前面板里显示成乱码,或者是一堆十六进制。
原因:远程SSH服务器默认发送的是UTF-8编码,而LabVIEW的字符串是Unicode,从字节到字符的转换需要用到Byte Array to String并指定编码。很多示例VI里直接用了String from Byte Array(默认ASCII),自然乱码。
解决:把读取到的原始字节数组先转换成UTF-8字符串。在LabVIEW中,用Unicode Code Point相关的转换函数,或者使用System Exec.vi辅助。更直接的做法是在sshell_exec.vi的输出端加一个Byte Array to Unicode String,输入编码选择UTF-8。我遇到过一些设备输出GBK编码的(比如某些国产板卡),这时候你需要根据设备手册切换编码,不能一刀切。

4.4 实时模块下内存泄漏或崩溃

现象:在LabVIEW Real-Time模块下运行库,连续执行几百次SSH连接后,系统内存不断增加,偶尔还会整个RT进程挂掉。
原因:libssh2库本身是用C的malloc分配内存的,而RT系统下LabVIEW的内存池和C运行时环境是分离的。库内部如果每个VI都在循环里创建session而忘记释放,内存不会自动回收。还有一个原因是这个库的DLL是用Visual Studio编译的,使用的CRT版本和RT target不兼容。
解决:每次执行完SSH_Disconnect后,务必调用libssh2_session_free来释放会话。如果库没有提供该VI,你需要自己封装一个。RT下尽量连接本地设备,而不是跨网段连接;另外,如果你把DLL放在c:\ni-rt\目录下打包,运行时会出现DLL签名错误,正确做法是把DLL转换成嵌入式组件,或者使用Libssh2 Linux RT Library的编译版本。这个问题属于平台特性,网上很少被提到,我是在跑了一夜压力测试后才定位到。

5. 二次开发改造:把库重构为一个可配置的SSH组件

5.1 用LabVIEW类封装连接状态,替代全局变量

原始库用功能全局变量来保存会话句柄,这在单线程场景下没问题,但如果你想在多个VI并行调用时共享同一个SSH连接,FGV无法保证线程安全。我会用LabVIEW类包装它:定义一个SSHClient.lvclass,类私有数据中包含会话句柄、sock、超时时间和状态枚举。类的公开方法只有Open、Authenticate、ExecuteCommand、Close。这样每个实例对应一个SSH连接,可以同时打开多台设备,且不会互相干扰。改造量不大,就是把这几个VI的连线改成类方法的输入输出。

5.2 增加自动重连和命令队列

SSH连接在长测中经常因为网络抖动而断开,原始库断连后只能手动重新运行。我给它加了一个看门狗循环:每次命令执行前检查libssh2_session_banner获取Banner,如果返回错误就触发重连。重连机制要用退避策略,否则设备刚启动时会产生几百次无效连接。命令队列我用队列数据结构配合状态机,同一时刻只允许一个命令在跑,其余进入队列等待,输出结果对应一个批次号回调。改造后的组件在老化测试中运行了三千次命令,没有出现一次假死。

5.3 验证改造结果:用模拟服务测试

改造完别急着上真设备,先用一个本地SSH模拟器做回归验证。我使用Python的paramiko库启动一个测试SSH服务端,监听2222端口,命令输出固定为一串字符串。然后在LabVIEW中调用你自己封装的类,断言输出是否匹配。这个验证方法能帮你快速发现句柄泄漏、超时不退出等问题。我就是靠这个模拟器,在十分钟内定位到了5个连接句柄没有释放的问题。

另外,如果你想进一步扩展,这个库也能支持SFTP下载文件,但需要自己添加libssh2_sftp_init的封装。我建议先把现有的SSH基础链路稳下来,再考虑文件传输。最后说个我自己踩过的教训:任何对libssh2的改动,都要在目标设备上做真实场景回归,不能只靠模拟器。因为嵌入式设备的SSH服务端配置和PC上完全不一样,比如禁用密码认证、仅允许密钥、或者开启了ForceCommand,都会让你的代码在模拟器上通过、在真机上翻车。从那以后我每次改完都会强制走一遍“模拟器→虚拟机→真实设备”三层验证流程,这也是我推荐你拿这个库做二次开发时最值得保留的习惯。希望帮到你。

本文还有配套的精品资源,点击获取

相关新闻

GPU到国产AI加速卡迁移实战:推理服务适配与性能调优全记录

GPU到国产AI加速卡迁移实战:推理服务适配与性能调优全记录

今年我们接了个有点棘手的活儿:把线上一个日调用量千万级的NLP推理服务,从国际主流的GPU平台平滑迁到国产AI加速卡上。任务听起来不复杂——换个硬件,模型重新导出一下不就行了?实际上从立项到灰度上线,我们整整折腾了…

2026/10/21 5:06:01 阅读更多 →
用Coze工作流搭建情绪共鸣短视频自动化生产线,实战30万涨粉全拆解

用Coze工作流搭建情绪共鸣短视频自动化生产线,实战30万涨粉全拆解

做过短视频的朋友应该都有这种感觉:刷到那种一条视频几百万赞、几十万评论的账号,点进去看内容,发现画面不算精致、文案也不算长,评论区里却全是“这就是我”“谁懂啊”“说到心坎里了”的共鸣留言。这类内容就是最近两年流量表现…

2026/10/21 5:06:01 阅读更多 →
基于YOLO的钢材表面缺陷检测系统设计与PyQt5界面实战

基于YOLO的钢材表面缺陷检测系统设计与PyQt5界面实战

做工业视觉的人对钢材表面缺陷检测这个问题应该不陌生。热轧钢板在产线上高速通过,表面随时可能出现划痕、斑块、氧化皮、夹杂物这类缺陷,靠人工盯着屏幕看,时间一长就是视觉疲劳,漏检率根本控不住。我最近完整搭了一套基于深度学…

2026/10/21 5:06:01 阅读更多 →

最新新闻

SpringBoot整合SSM实验室预约系统:从设计到答辩完整实战

SpringBoot整合SSM实验室预约系统:从设计到答辩完整实战

实验室预约这类系统,在我接触过的毕业设计和实际项目里,出现频率相当高。原因也很直接:它的业务流程足够完整,涉及用户角色、资源管理、状态流转、时间冲突判断这些核心逻辑,却又不像电商或社交系统那样无限膨胀&#…

2026/10/21 5:50:19 阅读更多 →
STM32+PT100工业级温度采集系统设计与实现

STM32+PT100工业级温度采集系统设计与实现

简介:本资源是一套基于STM32单片机的PT100铂电阻高精度温度采集系统完整开发包,面向嵌入式初学者、电子设计竞赛学生及工业测温应用开发者,解决低温至高温范围内稳定、抗干扰温度传感与数字转换的核心问题。压缩包共277个文件,含6…

2026/10/21 5:50:19 阅读更多 →
C++控制台游戏迭代实践:迷宫生成、存档与回合制战斗设计

C++控制台游戏迭代实践:迷宫生成、存档与回合制战斗设计

1. 版本迭代概览:3.17更新到底改了什么"勇闯迷塔"是我用C写的一个控制台小游戏,从最初十几层的纯迷宫探索,到3.17版本加入存档、战斗和新楼层,前后断断续续改了大概一个多月。这次更新正好在3月17日完成打包&#xff0c…

2026/10/21 5:50:19 阅读更多 →
基于CNN卷积神经网络的辣椒类别识别:高性价比计算机视觉毕设实战指南

基于CNN卷积神经网络的辣椒类别识别:高性价比计算机视觉毕设实战指南

每年开题季,都会有一批同学卡在同一个位置上:不想做MNIST手写数字、猫狗分类这种已经被写烂了的题目,又不敢直接挑战语义分割、目标检测这类工程量大得吓人的方向。如果你刚好在这个路口纠结,我推荐一个性价比非常高的选择——基于…

2026/10/21 5:50:19 阅读更多 →
自主移动机器人建图导航实战:lingbot-map模块化方案全解析

自主移动机器人建图导航实战:lingbot-map模块化方案全解析

做自主移动机器人,最磨人的往往不是底盘控制,也不是避障算法,而是那张地图。很多人以为“地图”就是雷达扫一圈输出一张图,实际上它背后牵扯坐标变换、传感器标定、回环检测、粒子滤波、代价地图膨胀这一整条链路。lingbot-map 这…

2026/10/21 5:50:18 阅读更多 →
Elasticsearch集群安全配置:TLS/SSL与密钥库管理全解析

Elasticsearch集群安全配置:TLS/SSL与密钥库管理全解析

给Elasticsearch集群做安全配置这件事,远比想象中麻烦。很多人以为在elasticsearch.yml里加几行TLS/SSL配置就能收工,结果往往是节点之间互相不认证书、Kibana连不上、客户端报handshake failed,最后只能回滚。我这次把一套三节点ES集群从裸H…

2026/10/21 5:49:18 阅读更多 →

日新闻

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

这段时间硬件圈和AI圈都在传一个事:AMD锐龙AI Max PRO 400系列把最高192GB统一内存搬进了PC形态的产品里,按宣传口径,本地跑320B参数的大家伙不再是纸面概念。我第一反应倒不是“内存真大”,而是这话背后的含金量——它把过去只能…

2026/10/21 0:00:11 阅读更多 →
AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

1. 从“封号重开”这个行为说起:用户到底在追求什么“封号重开”这四个字,放在任何产品语境里都带着一股决绝的味道。一个账号从零开始积累使用记录、调教偏好、沉淀工作流,背后是大量的时间和精力成本。正常情况下,没有人愿意主动…

2026/10/21 0:00:11 阅读更多 →
ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

1. 为什么在ROS里硬刚YOLOv3不是“炫技”,而是工程落地的必经之路我第一次在某高校机器人实验室看到那台搭载Jetson TX2的移动底盘原地打转、反复识别错垃圾桶时,就意识到:单纯跑通darknet_ros demo和真正让YOLOv3在ROS里“干活”&#xff0c…

2026/10/21 0:00:11 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/20 20:43:59 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/21 4:27:17 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:45 阅读更多 →