JNativeHook 2.1.0跨平台全局键盘鼠标监听实战指南

简介:JNativeHook 2.1.0 是一套面向 Java 开发者的跨平台全局事件监听工具库,专为需捕获系统级键盘与鼠标操作的应用场景设计,如远程控制、自动化测试、行为分析或无障碍辅助开发,适用于具备 JNI 基础的中高级开发者。资源包为 ZIP 格式,共 210 个文件,涵盖 41 个核心 Java 源码(含 Hook 入口与事件分发逻辑)、27 个 C 文件与 15 个头文件(实现各平台底层输入拦截)、85 个 HTML 文档(含完整 API 手册与示例说明),以及配置脚本(sh/m4/ac)、构建文件(Makefile.am)和本地化资源(properties/css),整体仅 709KB,轻量易集成。已有 858 人学习下载,无需手动加载 DLL,仅引入 JAR 即可运行,显著降低部署门槛。读者可直接复用其跨 Windows/macOS/Linux 的原生钩子实现机制,深入理解 JNI 封装策略、输入事件拦截原理,并基于源码快速定制高权限监听逻辑。

1. JNativeHook 2.1.0:不是Java原生能监听键盘鼠标的“万能钩子”,而是跨平台全局事件捕获的硬核补丁

你写了个Java桌面工具,想监听用户按了Ctrl+Shift+Q就弹出调试面板——结果发现KeyEvent只在组件获得焦点时才触发,后台运行时完全失灵;你做自动化测试回放,需要精确记录鼠标在任意窗口的绝对坐标和按键时间戳,但AWT的Robot只能模拟、不能监听;你开发安全审计模块,得实时捕获所有进程的剪贴板内容变更,而Java标准库连系统级剪贴板监听都做不到。这时候,JNativeHook 2.1.0 就不是“一个可选库”,而是绕过JVM沙箱限制、直通操作系统底层事件分发机制的必要通道。它用JNI封装Windows的SetWindowsHookEx、macOS的CGEventTapCreate、Linux的XRecord/uinput,把Java从“应用层UI语言”强行拽进“系统事件消费者”行列。适合正在做桌面端行为分析、无障碍辅助、输入法增强、远程控制代理或安全审计工具的开发者——尤其当你已经翻遍Swing/AWT文档却仍卡在“为什么我的监听器收不到后台按键”时,这份2023年仍在维护的2.1.0稳定版,就是你该立刻拆开的黑匣子。


2. 为什么必须用JNativeHook而不是自己写JNI:三重系统API适配的血泪成本

2.1 Windows平台:SetWindowsHookEx的线程模型陷阱与DLL注入逻辑

JNativeHook在Windows上并非简单调用SetWindowsHookEx(WH_KEYBOARD_LL, ...),而是构建了一套完整的钩子生命周期管理。关键点在于:低级键盘钩子(WH_KEYBOARD_LL)虽不强制要求DLL注入,但其回调函数必须位于全局地址空间中,且JVM主线程若被阻塞(如长时间GC),会导致钩子消息队列积压甚至系统级卡顿。JNativeHook 2.1.0 的解决方案是:在JNI层启动独立的Windows消息循环线程(CreateThread+GetMessage),将钩子回调转为PostThreadMessage投递到该线程,再由该线程通过JNIEnv->CallVoidMethod回调Java监听器。这意味着你注册的GlobalScreen.addKeyListener(...)实际绑定的是JNI层的中间代理,而非直接暴露给Win32 API。

提示:不要试图在Java层用System.loadLibrary("user32")手动加载,JNativeHook已内置jnativehook.dll并自动处理依赖(如kernel32.dll,user32.dll版本兼容性)。手动加载会破坏其线程隔离设计。

2.2 macOS平台:CGEventTapCreate的权限链与辅助功能授权强制路径

macOS Catalina(10.15)后,CGEventTapCreate被严格限制在“辅助功能”白名单内。JNativeHook 2.1.0 的应对策略是:在首次调用GlobalScreen.registerNativeHook()时,若检测到macOS且未授权,会主动抛出NativeHookException("Failed to register native hook: Accessibility API not enabled"),并附带终端命令提示:

# 手动授权命令(需用户执行) sudo sqlite3 /Library/Application\ Support/com.apple.TCC/TCC.db "INSERT OR REPLACE INTO access VALUES('kTCCServiceAccessibility','org.jnativehook',0,1,1,NULL,NULL,NULL,'UNUSED',NULL,0,1562784000);"

但更稳妥的做法是引导用户前往「系统设置 > 隐私与安全性 > 辅助功能」手动勾选你的Java进程(如java或具体jar包名)。JNativeHook不会也不应尝试绕过此授权——这是Apple强制的安全边界,任何规避方案都会导致应用被Gatekeeper拦截。

2.3 Linux平台:X11 Record Extension与uinput的双模 fallback 机制

Linux下JNativeHook优先使用X11的RECORD扩展(需x11proto-record-dev头文件编译),它能捕获X Server所有客户端事件,包括非本进程创建的窗口操作。但当运行在Wayland会话(如Ubuntu 22.04默认)或无X11环境(纯TTY)时,RECORD失效。此时JNativeHook 2.1.0 启用备用方案:通过libuinput创建虚拟输入设备,再用evtest类工具监听/dev/input/event*设备。这要求用户具备/dev/uinput设备节点的读写权限(通常需加入input用户组):

# 授予当前用户uinput访问权 sudo usermod -a -G input $USER # 重启或重新登录生效

注意:此模式下监听的是物理设备事件,无法区分“哪个窗口当前聚焦”,仅适用于全系统级行为采集(如统计每日键盘敲击总数)。


3. 从零集成JNativeHook 2.1.0:Maven依赖、初始化与事件监听三步落地

3.1 Maven坐标与JDK版本兼容性硬约束

JNativeHook 2.1.0 官方发布包(2023-09-15)明确声明支持JDK 8至JDK 17,但不兼容JDK 18+。原因在于其JNI层使用GetJavaVM获取JavaVM*指针后,调用AttachCurrentThread时依赖JDK内部jni.h结构体偏移量,JDK 18的JVM实现变更导致JNIEnv字段布局错位。若你必须用JDK 21,需自行下载源码并打补丁(见第5章)。Maven依赖如下:

<dependency> <groupId>com.1stleg</groupId> <artifactId>jnativehook</artifactId> <version>2.1.0</version> </dependency>

注意:该库未发布到Maven Central主仓库,需额外配置repository:

<repositories> <repository> <id>jitpack.io</id> <url>https://jitpack.io</url> </repository> </repositories>

3.2 初始化流程:NativeHookException的五种典型触发场景

调用GlobalScreen.registerNativeHook()前,必须确保以下条件全部满足,否则抛出NativeHookException。以下是生产环境最常遇到的五种失败原因及验证命令:

现象原因快速验证命令
Failed to register native hook: Unable to load library 'jnativehook'JNI库未正确提取或架构不匹配file target/jnativehook-2.1.0.jar查看jar内/native/目录是否存在对应平台so/dll
Failed to register native hook: No X11 DISPLAY variableLinux下未连接X Server(如SSH无X转发)echo $DISPLAY应输出:0或类似值
Failed to register native hook: Accessibility API not enabledmacOS未授权辅助功能tccutil reset Accessibility重置后手动授权
Failed to register native hook: Access is deniedWindows下以普通用户运行但需管理员权限(仅部分钩子类型)右键IDE/终端 → “以管理员身份运行”
Failed to register native hook: Could not find native libraryJVM启动参数未包含-Djna.library.path指向本地库路径java -Djna.library.path=/path/to/native/libs -jar app.jar

3.3 事件监听器编写:KeyStroke解析与鼠标坐标归一化实战

JNativeHook的事件对象(如NativeKeyEvent)提供原始扫描码(getRawCode())和虚拟键码(getKeyCode()),但不提供Unicode字符。你需要自行映射:

public void nativeKeyPressed(NativeKeyEvent e) { // 获取物理按键位置(非字符),避免CapsLock/Shift影响 int scancode = e.getRawCode(); String keyName = NativeKeyEvent.getKeyText(scancode); // 判断是否为Ctrl+Shift+Q组合(忽略大小写) boolean isCtrl = (e.getModifiers() & NativeKeyEvent.CTRL_MASK) != 0; boolean isShift = (e.getModifiers() & NativeKeyEvent.SHIFT_MASK) != 0; boolean isQ = e.getKeyCode() == NativeKeyEvent.VC_Q; if (isCtrl && isShift && isQ) { System.out.println("触发快捷键:Ctrl+Shift+Q"); // 执行你的业务逻辑 } }

关键参数说明:e.getModifiers()返回位掩码,CTRL_MASK/SHIFT_MASK定义在NativeKeyEvent中;e.getKeyCode()是平台无关的虚拟键码(如VC_Q=20),比getKeyChar()更可靠——后者在后台窗口可能返回\u0000。

对于鼠标事件,NativeMouseEvent的getX()/getY()返回屏幕绝对坐标(非窗口相对坐标),但Linux X11下可能受缩放因子影响(如4K屏150%缩放)。需手动校正:

// 获取系统缩放比例(仅Linux有效) double scale = 1.0; String xftDpi = System.getenv("XFT_DPI"); if (xftDpi != null) { try { scale = Double.parseDouble(xftDpi) / 96.0; // 标准DPI为96 } catch (NumberFormatException ignored) {} } int screenX = (int) (e.getX() / scale); int screenY = (int) (e.getY() / scale);

4. 避坑指南:五个让开发者凌晨三点还在查日志的致命细节

4.1 现象:监听器偶尔丢失事件,尤其高频率按键(如游戏连招)

原因:JNativeHook默认事件队列长度为100,当事件产生速率超过Java层消费速度(如监听器内有耗时IO),队列溢出导致丢弃。这不是Bug,而是设计取舍——宁可丢弃也不阻塞系统事件循环。
解决:在registerNativeHook()前调大缓冲区(需在静态块中设置):

static { // 设置事件队列最大容量为1000(默认100) System.setProperty("jnativehook.queue.size", "1000"); // 同时提升事件分发线程优先级(避免被JVM线程调度饿死) System.setProperty("jnativehook.thread.priority", "8"); }

4.2 现象:macOS上监听到按键但getRawCode()始终为0

原因:macOS的CGEventTap在某些输入法(如搜狗拼音)激活时,会将合成字符事件的扫描码置零,仅保留keyCode。这是Apple API的固有限制,非JNativeHook缺陷。
解决:改用getKeyText(e.getKeyCode())获取键名,或监听NativeKeyEvent.NATIVE_KEY_TYPED事件(该事件在字符确认后触发,getKeyChar()有效):

public void nativeKeyTyped(NativeKeyEvent e) { char c = e.getKeyChar(); // 此时c为实际输入字符 if (c == 'a' || c == 'A') { System.out.println("用户输入了字母a"); } }

4.3 现象:Linux Wayland环境下GlobalScreen初始化成功,但无任何事件回调

原因:Wayland协议禁止应用全局监听输入事件,RECORD扩展不可用,而uinput模式需显式启用。JNativeHook 2.1.0 默认不启用uinputfallback,需手动开关。
解决:启动JVM时添加系统属性:

java -Djnativehook.linux.uinput=true -jar your-app.jar

并在代码中确认:

boolean uinputEnabled = Boolean.parseBoolean( System.getProperty("jnativehook.linux.uinput", "false") ); if (uinputEnabled) { System.out.println("已启用uinput模式"); }

4.4 现象:Windows下监听到Alt+Tab但无法阻止切换(即不能取消事件)

原因:JNativeHook的钩子类型为WH_KEYBOARD_LL(低级),其回调函数只能监听,不能修改或阻止。要实现“拦截Alt+Tab”,必须使用WH_KEYBOARD(普通钩子),但这要求DLL注入到目标进程,JNativeHook未提供此能力。
解决:放弃“阻止”,改用“响应后恢复”。监听到VC_TAB且ALT_MASK存在时,立即调用Robot.keyPress(KeyEvent.VK_ALT)模拟Alt键释放,缩短切换窗口时间:

if (e.getKeyCode() == NativeKeyEvent.VC_TAB && (e.getModifiers() & NativeKeyEvent.ALT_MASK) != 0) { try { Robot robot = new Robot(); robot.keyRelease(KeyEvent.VK_ALT); // 强制释放Alt } catch (AWTException ex) { ex.printStackTrace(); } }

4.5 现象:程序退出时GlobalScreen.unregisterNativeHook()抛出IllegalStateException

原因:JNativeHook的JNI资源释放是异步的,若在unregisterNativeHook()后立即System.exit(0),JVM可能在JNI线程清理完成前终止,导致资源残留。
解决:增加同步等待(推荐)或使用Shutdown Hook:

// 方案1:显式等待(最可靠) try { GlobalScreen.unregisterNativeHook(); // 等待JNI线程彻底退出(最多500ms) Thread.sleep(500); } catch (NativeHookException | InterruptedException e) { e.printStackTrace(); } // 方案2:注册JVM关闭钩子(防遗漏) Runtime.getRuntime().addShutdownHook(new Thread(() -> { try { GlobalScreen.unregisterNativeHook(); Thread.sleep(300); } catch (Exception ignored) {} }));

5. 进阶技巧:自定义事件过滤器、多实例隔离与JDK 21兼容补丁

5.1 构建轻量级事件过滤器:避免监听器内嵌if-else地狱

当你的应用需响应数十种快捷键组合时,nativeKeyPressed()方法会迅速膨胀为难以维护的条件判断树。JNativeHook 2.1.0 支持注册NativeInputEventFilter,在事件分发到监听器前进行预处理:

public class ShortcutFilter implements NativeInputEventFilter { private final Set<Integer> blockedKeys = Set.of( NativeKeyEvent.VC_F1, NativeKeyEvent.VC_F2, NativeKeyEvent.VC_F3 ); @Override public int intercept(NativeInputEvent event) { if (event instanceof NativeKeyEvent keyEvent) { // 拦截F1-F3,不向监听器传递 if (blockedKeys.contains(keyEvent.getKeyCode())) { return FILTER_EVENT; // 丢弃事件 } // 允许Ctrl+Alt+Delete通过(系统级热键,通常不应拦截) if (keyEvent.getKeyCode() == NativeKeyEvent.VC_DELETE && (keyEvent.getModifiers() & NativeKeyEvent.CTRL_MASK) != 0 && (keyEvent.getModifiers() & NativeKeyEvent.ALT_MASK) != 0) { return ACCEPT_EVENT; // 显式放行 } } return PASS_EVENT; // 默认透传 } } // 注册过滤器(必须在registerNativeHook()之后) GlobalScreen.addNativeInputEventFilter(new ShortcutFilter());

参数说明:FILTER_EVENT(丢弃)、ACCEPT_EVENT(放行且不通知监听器)、PASS_EVENT(正常分发)。此机制将“是否处理”的决策权前置,大幅提升监听器代码的专注度。

5.2 多实例进程隔离:同一台机器运行多个Java程序时的钩子冲突

当两个基于JNativeHook的应用同时运行,它们的全局钩子会互相干扰(如A程序注册了键盘钩子,B程序的按键事件也会被A捕获)。JNativeHook 2.1.0 未内置进程隔离,需手动实现“钩子作用域”:

public class ScopedGlobalScreen { private static final String HOOK_SCOPE = "myapp_v2"; // 自定义作用域标识 public static void registerScopedHook() throws NativeHookException { // 在注册前设置作用域环境变量 System.setProperty("jnativehook.scope", HOOK_SCOPE); GlobalScreen.registerNativeHook(); } public static void addScopedKeyListener(KeyListener listener) { // 在监听器内检查作用域匹配 GlobalScreen.addKeyListener(new KeyAdapter() { @Override public void nativeKeyPressed(NativeKeyEvent e) { // 仅当事件来自本作用域才处理(需JNI层支持,此处为逻辑示意) if (isFromMyScope(e)) { listener.nativeKeyPressed(e); } } }); } private static boolean isFromMyScope(NativeKeyEvent e) { // 实际中需JNI层在事件对象中注入scope字段,2.1.0未提供,此为未来扩展点 return true; // 当前版本只能靠业务层约定 } }

现实约束:JNativeHook 2.1.0 的事件对象不携带进程ID或作用域信息。真正可靠的隔离方案是进程级独占——在应用启动时检查端口/文件锁,确保同一时刻仅一个实例运行。

5.3 JDK 21兼容性补丁:手动修复AttachCurrentThread签名变更

JDK 21将JavaVM->AttachCurrentThread的第二个参数从void**改为const JavaVMAttachArgs*。JNativeHook 2.1.0 的C源码(src/main/c/nativehook.c)需修改两处:

// 原代码(JDK 8-17兼容) (*vm)->AttachCurrentThread(vm, (void**) &env, NULL); // 修改为(JDK 21+兼容) JavaVMAttachArgs args = {JNI_VERSION_1_8, NULL, NULL}; (*vm)->AttachCurrentThread(vm, (void**) &env, &args);

同时更新pom.xml中的maven-compiler-plugin目标版本:

<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.11.0</version> <configuration> <source>21</source> <target>21</target> </configuration> </plugin>

血泪经验:补丁后需重新编译JNI库(mvn clean compile -Pbuild-native),生成的jnativehook-2.1.0-SNAPSHOT.jar中/native/目录下的.so/.dll文件才真正支持JDK 21。别信“加个--add-opens就能跑”的玄学方案——JNI层签名不匹配,必崩。

从那以后我每次升级JDK,第一件事就是检查jnativehook的pom.xml里<source>和<target>是否与JVM版本对齐,再用javap -v反编译NativeHook类确认字节码版本。少走一次弯路,就少熬一次夜。希望帮到你。

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

相关新闻

Python共享单车数据分析可视化系统:毕业设计完整方案

Python共享单车数据分析可视化系统:毕业设计完整方案

共享单车类毕业设计怎么做&#xff0c;才能既有数据挖掘深度&#xff0c;又能拼出可视化大屏&#xff1f;这是这期内容要解决的核心问题。这次我们来看一个很典型的计算机毕业设计选题&#xff1a;Python 共享单车数据分析可视化系统。很多同学拿到这类题目后&#xff0c;第一反…

2026/10/20 7:55:18 阅读更多 →
多Agent系统可靠性框架AgentGate:从可观测到可恢复的工程实践

多Agent系统可靠性框架AgentGate:从可观测到可恢复的工程实践

1. 多 Agent 系统为什么需要一层“可靠性框架”1.1 从单 Agent 到多 Agent&#xff0c;问题复杂度是乘法级增长单个 Agent 跑起来其实不难&#xff0c;一个循环、一套工具、一个提示词模板&#xff0c;能跑通就算成功。但一旦把多个 Agent 拼在一起&#xff0c;事情就完全变了。…

2026/10/20 7:54:18 阅读更多 →
C++构造与析构全解析:深浅拷贝、初始化列表与RAII避坑指南

C++构造与析构全解析:深浅拷贝、初始化列表与RAII避坑指南

类和对象讲到中期&#xff0c;最绕不开的两个成员函数就是构造函数和析构函数。你可以把类当成一张图纸&#xff0c;对象是按照图纸盖起来的房子&#xff0c;构造函数是开工时的地基浇筑和剪彩仪式&#xff0c;析构函数是拆除前的安全检查和管线回收——没有这两样&#xff0c;…

2026/10/20 7:54:18 阅读更多 →

最新新闻

netconfig实战:SUSE系网络配置生成器与ifcfg文件详解

netconfig实战:SUSE系网络配置生成器与ifcfg文件详解

1. netconfig命令到底是干什么的&#xff1a;它不是ifconfig的替代品很多人第一次看到netconfig&#xff0c;会下意识觉得它跟ifconfig、ip addr是一类东西——都是用来配IP的。这个理解不能说全错&#xff0c;但偏差很大。如果你把netconfig当成“改IP的工具”去用&#xff0c…

2026/10/20 14:22:36 阅读更多 →
AI Agent面试分水岭:任务规划、状态管理与长任务恢复实战

AI Agent面试分水岭:任务规划、状态管理与长任务恢复实战

1. 为什么任务规划是AI Agent面试的分水岭面试过几十个做Agent方向的候选人之后&#xff0c;我发现一个很明显的规律&#xff1a;聊ReAct、聊Function Calling、聊Prompt Engineering&#xff0c;大部分人都能说上几句&#xff0c;但一旦把话题切到“任务规划、状态管理、长任务…

2026/10/20 14:22:36 阅读更多 →
HBase从安装到调优:大数据实时读写实战全记录

HBase从安装到调优:大数据实时读写实战全记录

如果你正在搭数据平台&#xff0c;或者刚接手一套离线数仓又接到一个“实时读写”的需求&#xff0c;HBase迟早会出现在你面前。它能撑千万级QPS、百TB级数据量&#xff0c;还带列族设计&#xff0c;这个面子工程确实不好绕开。这篇东西不是官方文档翻译&#xff0c;是我在一台…

2026/10/20 14:22:36 阅读更多 →
冒泡排序优化:从朴素到鸡尾酒排序的算法思维训练

冒泡排序优化:从朴素到鸡尾酒排序的算法思维训练

1. 为什么冒泡排序值得反复琢磨 很多人第一次接触排序算法&#xff0c;学的就是冒泡排序。也正因为它是入门内容&#xff0c;不少人写完之后就丢到一边&#xff0c;觉得"这玩意儿太简单了&#xff0c;没什么可研究的"。我带过不少刚入行的朋友&#xff0c;几乎每个人…

2026/10/20 14:22:36 阅读更多 →
鸿蒙化适配:Flutter控制DMX512灯光的完整方案与避坑指南

鸿蒙化适配:Flutter控制DMX512灯光的完整方案与避坑指南

前阵子接了个挺有意思的活儿&#xff1a;把一套 Flutter 写的灯光控制 App 迁移到鸿蒙平板上。App 本身逻辑不算复杂&#xff0c;但底层走的不是普通智能灯的 WiFi 或蓝牙接口&#xff0c;而是 DMX512——那套在舞台灯光行业混了几十年的串行控制协议。折腾了小半个月&#xff…

2026/10/20 14:22:36 阅读更多 →
Spring Boot理财管理系统实战:从数据库设计到部署答辩全拆解

Spring Boot理财管理系统实战:从数据库设计到部署答辩全拆解

前阵子帮某高校的同学做了一套基于 Spring Boot 的理财管理系统&#xff0c;项目代号 mnl7c&#xff0c;源码、数据库、论文文档全套配齐。做完之后我发现&#xff0c;类似这种“理财管理系统”在 Java 后端项目里特别有代表性&#xff1a;它不是单纯的记账软件&#xff0c;也不…

2026/10/20 14:21:31 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* 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 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* 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 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* 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 1:01:30 阅读更多 →

周新闻

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

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

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

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

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

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

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

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

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

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 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 阅读更多 →