contains_unichar_id异常

在使用Tesseract 4.0进行图像文字识别时遇到崩溃问题,错误发生在调用"TessBaseAPIRecognize()"时。经过调试和分析,确定不是空指针或野指针导致,而是与字库相关。通过尝试使用不同版本的字库,发现30多M的"4.00"版本字库解决了崩溃问题。问题在于原始字库中可能缺少某些字符,导致识别特定字符时程序崩溃。

近日在使用Tesseract4.0时踩了个坑,在识别一张质量较差的图片时崩溃了。

原图文字被切成多行,每一行文字调用一次Tesseract识别。在某一次崩了,偶发bug。

Release崩溃截图如下:

进入Debug模式崩溃截图如下:

 调试发现,是在在某次调用"TessBaseAPIRecognize()" 时崩溃了。

百度搜索"读取位置0x000000时发生访问冲突",都说是空指针,野指针的问题。

但实际调试发现"handle"正常,并不是指针问题。

然后根据Release崩溃信息去看源码,如图:

断言在"contains_unichar_id(unichar_id)",分析这个英文意思:包含字符id 。

这个字符的ID不存在?字符不就是在字库里吗?

换个字库试试看

github找到Tesseract4.0的字库,如图:

 其中"4.0.0"与“master”版本字库都是20多M大小(好像是一样的)

"4.00"版本字库30多M

我之前使用的字库是20多M,那直接换这30多M的字库试一下。

换掉字库之后,运行竟然成功了。。。

识别结果如下:

发现第5行有个特殊字符,程序崩溃 。。。。。。

似乎问题就在字库这了

这不是个坑货吗,字库里没有的字就崩溃?

 

此问题纯个人分析,如有不同看法,欢迎交流

<think> 我们正在讨论Windows消息处理中的WM_CHAR消息。根据引用内容,WM_CHAR是字符消息的一种,通常由TranslateMessage函数在翻译虚拟键代码后产生。它携带了字符的Unicode值(在Unicode窗口中)或ANSI字符值(在ANSI窗口中)。下面我将详细介绍WM_CHAR消息。 ### WM_CHAR消息概述 WM_CHAR消息是Windows操作系统发送给应用程序窗口的消息,用于传递一个已翻译的字符输入。当用户按下一个键时,系统会生成WM_KEYDOWN消息,然后通过TranslateMessage函数(在消息循环中)将其转换为WM_CHAR消息。WM_CHAR消息包含实际输入的字符信息,而不是虚拟键码。 ### 消息参数 - `wParam`: 包含字符的Unicode值(在Unicode窗口中)或ANSI字符值(在ANSI窗口中)。 - `lParam`: 包含有关击键的重复计数、扫描码、扩展键标志、上下文代码、前一个键状态标志和转换状态标志的信息。这些信息与WM_KEYDOWN消息的lParam相同。 ### 处理WM_CHAR 在窗口过程中,我们可以捕获WM_CHAR消息并处理它。例如: ```c++ case WM_CHAR: { TCHAR ch = (TCHAR) wParam; // 获取字符 // 处理字符输入,例如添加到文本缓冲区 return 0; } ``` ### WM_CHAR与WM_IME_CHAR的区别 根据引用[1]: - 当输入法关闭时,直接输入字符(如数字键)会生成WM_CHAR消息。 - 当输入法打开时,输入字符可能会先产生WM_IME_CHAR消息(对于某些输入法),然后产生WM_CHAR消息。在中文输入法下,输入一个中文字符可能会产生多个WM_CHAR消息(例如,对于“笨”,会收到两个WM_CHAR消息,分别对应其两个字节的ANSI编码)。 注意:在Unicode程序中,通常使用WM_CHAR消息直接获取Unicode字符,而不需要处理多字节分解的问题。 ### 使用场景 WM_CHAR消息主要用于文本输入的处理,例如在编辑控件、文本框或其他需要用户输入文本的地方。相比于WM_KEYDOWN,WM_CHAR已经将按键转换成了字符,因此更方便处理文本输入。 ### 注意事项 1. **字符集**:在Unicode窗口(使用RegisterClassW注册)中,WM_CHAR的wParam是UTF-16编码的Unicode字符。在ANSI窗口(RegisterClassA)中,则是当前代码页的ANSI字符。 2. **死键处理**:对于某些键盘布局,可能存在死键(例如重音符号),这时可能会先收到WM_DEADCHAR消息,然后才是WM_CHAR消息。 3. **系统字符**:系统键(如Alt+字母)会产生WM_SYSCHAR消息,通常由系统处理,应用程序一般忽略。 ### 示例代码片段 以下是一个简单的消息循环和处理WM_CHAR的示例: ```c++ MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); // 将WM_KEYDOWN转换为WM_CHAR DispatchMessage(&msg); } // 窗口过程 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_CHAR: { TCHAR ch = (TCHAR)wParam; // 例如,将字符添加到字符串 // 这里可以处理文本输入 break; } // 处理其他消息... } return DefWindowProc(hWnd, message, wParam, lParam); } ``` ### 引用说明 - 引用[1]展示了输入法开启和关闭时WM_IME_CHAR和WM_CHAR的发送情况。 - 引用[2]说明了WM_CHAR消息的产生机制(由TranslateMessage转换而来)以及窗口过程通常只处理WM_CHAR。 - 引用[3]描述了WM_KEYDOWN消息中lParam的位含义(扩展键标志等),这些信息同样适用于WM_CHAR消息的lParam。 §§相关问题§§ 1. 在Windows编程中,如何处理多字节字符输入(如中文字符)? 2. TranslateMessage函数具体做了哪些转换? 3. WM_CHAR和WM_KEYDOWN在游戏开发中分别有什么作用? </think> ### WM_CHAR消息详解 `WM_CHAR`是Windows消息系统中的核心字符输入消息,用于向应用程序传递已处理的键盘字符输入。以下是详细说明: #### 📜 定义与作用 1. **消息类型**:字符消息(Character Message) 2. **触发机制**:由`TranslateMessage()`函数将`WM_KEYDOWN`虚拟键消息转换而来[^2] 3. **核心作用**:传递可显示的字符值(如字母、数字、符号),而非原始扫描码 4. **与输入法关系**:输入法开启时仍会生成,但可能伴随`WM_IME_CHAR`(见引用[1]示例) #### ⚙️ 消息参数解析 ```c wParam: // 字符值 Unicode窗口 → UTF-16编码值 ANSI窗口 → 当前代码页字符值 lParam: // 包含按键状态信息(32位) bits 0-15: 重复计数(自动重复次数) bits 16-23: 扫描码(OEM硬件相关) bit 24: 扩展键标志(1=右侧Ctrl/Alt键)[^3] bits 25-28: 保留 bit 29: 上下文标志(1=Alt按下) bit 30: 前键状态(1=按下) bit 31: 转换状态(0=按下,1=释放) ``` #### 🔧 典型处理流程 在窗口过程函数中: ```cpp case WM_CHAR: { TCHAR ch = (TCHAR)wParam; // 获取字符 UINT repeatCount = LOWORD(lParam); BOOL isExtended = (lParam & 0x01000000) ? TRUE : FALSE; // 示例:处理字符输入(如文本编辑器) if (ch >= 32 || ch == '\t' || ch == '\n') { // 过滤控制字符 AddCharacterToBuffer(ch, repeatCount); } return 0; } ``` #### ⚠️ 重要特性 1. **输入法兼容性** - 中文输入时可能收到多字节分开发送(如引用[1]中"笨"→0xB1BF拆分为0x00B1+0x00BF) - 推荐使用`WM_UNICHAR`处理UTF-32字符避免拆分问题 2. **与其它消息关系** ```mermaid graph LR A[物理按键] --> B(WM_KEYDOWN) B --> C{TranslateMessage?} C -->|Yes| D[WM_CHAR] C -->|No| E[跳过字符处理] D --> F[文本输入逻辑] ``` 3. **特殊字符处理** | 字符值 | 说明 | 处理方法 | |--------|-------------------|-------------------| | 0x08 | Backspace | 删除前字符 | | 0x0D | 回车(Enter) | 换行/确认操作 | | 0x1B | ESC键 | 取消操作 | | 0x09 | Tab键 | 焦点切换 | #### 使用建议 1. **优先处理场景** - 文本编辑器、输入框控件 - 快捷键组合检测(需结合`GetKeyState()`) 2. **规避陷阱** ```cpp // 错误:直接用于控制键检测 case WM_CHAR: if (wParam == VK_LEFT) {...} // VK_LEFT不会触发WM_CHAR! // 正确:控制键应使用WM_KEYDOWN case WM_KEYDOWN: if (wParam == VK_LEFT) MoveCursorLeft(); ``` 3. **多语言支持** 推荐启用Unicode窗口(`RegisterClassW`)以原生支持: ```cpp // Unicode程序更佳实践 case WM_CHAR: wchar_t unicodeChar = (wchar_t)wParam; // 直接获取UTF-16字符 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值