Tesseract OCR搭配androidx.camera使用时无法正确识别文字问题
核心原因
同一场景下系统相机拍摄的图片可正常识别,说明Tesseract本身配置、语言包、识别逻辑没有问题,故障100%出在CameraX输出的图片和系统相机输出图片的属性差异上,按以下优先级排查即可:
排查点与对应解决方案
图片旋转角度未对齐
CameraX输出的原始图片像素方向不会自动跟随设备旋转,仅在EXIF或ImageInfo中标记旋转角度,Tesseract默认按像素原始方向识别,不会主动解析旋转标记,方向错误时识别结果必然是乱码;而系统相机输出的图片已经提前把像素旋转到了人眼可视的正确方向,不存在这个问题。
排查时先把CameraX保存的图片导出到电脑查看,确认是否存在方向颠倒、横置的情况。
处理逻辑:拍摄后读取ImageProxy.getImageInfo().getRotationDegrees()拿到正确旋转角度,转Bitmap时通过Matrix主动旋转像素,再传给Tesseract,参考代码:// 从ImageProxy取到原始Bitmap后执行旋转 val rotation = imageProxy.imageInfo.rotationDegrees val rotateMatrix = Matrix().apply { postRotate(rotation.toFloat()) } val correctBitmap = Bitmap.createBitmap( originBitmap, 0, 0, originBitmap.width, originBitmap.height, rotateMatrix, true )不要依赖Tesseract自动处理图片方向。
图片格式/色彩转换逻辑错误
自己手写YUV_420_888转Bitmap逻辑时,很容易出现通道顺序错配、行偏移(rowStride/pixelStride未正确处理)、色彩空间不匹配的问题,最终生成的Bitmap会出现色偏、斜向条纹、像素错位,识别结果自然是乱码;系统相机返回的是标准sRGB色彩空间的ARGB/JPEG格式,和Tesseract的输入要求完全匹配。
排查时把你转换后的Bitmap直接存到本地,肉眼检查有没有颜色异常、条纹、错位。
处理逻辑:不要自己实现YUV转RGB代码,优先使用ImageCapture自带的文件保存能力,直接输出标准JPEG文件后读取;如果必须内存内处理,使用官方封装的转换逻辑,转完先做肉眼校验。测试阶段可以把ImageCapture的拍摄模式从CAPTURE_MODE_MINIMIZE_LATENCY改成CAPTURE_MODE_MAXIMIZE_QUALITY,排除低码率压缩带来的过度噪点干扰。图片拉伸/裁剪/分辨率不足
如果给Preview和ImageCapture设置的目标比例、目标分辨率不一致,CameraX会自动对输出图片做裁剪拉伸,导致文字变形;如果代码里为了提速把拍摄得到的图片过度压缩到过小尺寸,文字细节丢失也会导致识别乱码。系统相机默认输出传感器原生比例的高分辨率图片,不存在变形、清晰度不足的问题。
排查时对比CameraX输出图和系统相机输出图的比例、文字清晰度,确认有没有拉伸、裁切、模糊的情况。
处理逻辑:Preview和ImageCapture绑定相同的目标宽高比、目标分辨率,传给Tesseract的图片保证文字区域像素密度不低于300DPI,不要做无意义的过度压缩。异常EXIF信息干扰
部分厂商设备上CameraX输出的JPEG会携带错误的EXIF元数据(比如错误的色彩配置、错误的方向标记),Tesseract读取文件时如果自动解析EXIF做预处理,会被错误信息误导,导致识别异常。
排查时把CameraX输出图片的EXIF信息全部清除后再传给Tesseract,如果识别恢复正常就能定位是这个问题。
处理逻辑:优先传修正后的纯Bitmap对象给Tesseract做识别,不要直接传文件路径让Tesseract自行读取解析,避免异常EXIF的干扰。
快速验证技巧:把CameraX拍摄得到的图片用系统相册自带的编辑功能随便做个无关紧要的修改(比如旋转1度再转回来)后另存,再传给Tesseract,如果此时识别正常,就可以确定是上述四类属性问题,和Tesseract逻辑无关。
内容的提问来源于stack exchange,提问作者Jhonatan

