如何在Vision API中从上到下排序TextBlock?解决文本读取顺序错乱问题
解决Vision API OCR文本读取顺序错误的问题
嘿,我碰到过不少开发者遇到这个问题——Google Vision API的OCR检测返回的TextBlock默认是按检测算法的内部逻辑排序的,完全不是我们常规的从上到下、从左到右的阅读顺序,所以才会出现页面底部文本先被读取的混乱情况。
问题根源
Vision API的检测结果顺序取决于它识别文本块的先后优先级,和文本在页面上的空间位置没有直接关联。如果不对结果做额外处理,直接按默认顺序遍历,自然会出现顺序错乱的问题。
解决方案:按空间位置重新排序文本块
我们可以把返回的SparseArray<TextBlock>转换成可排序的集合,然后根据每个文本块的**垂直坐标(y轴)和水平坐标(x轴)**来排序,模拟人类的阅读顺序:
- 优先按文本块顶部的y坐标排序,y值越小(越靠上)越靠前
- 对于同一行的文本块(y坐标相近),再按左侧的x坐标排序,x值越小(越靠左)越靠前
修改后的receiveDetections方法示例
@Override public void receiveDetections(Detector.Detections<TextBlock> detections) { mGraphicOverlay.clear(); SparseArray<TextBlock> items = detections.getDetectedItems(); // 把SparseArray转换成List以便排序 List<TextBlock> textBlockList = new ArrayList<>(); for (int i = 0; i < items.size(); i++) { textBlockList.add(items.valueAt(i)); } // 自定义排序规则:先按y轴区分行,再按x轴排序同行文本 Collections.sort(textBlockList, new Comparator<TextBlock>() { @Override public int compare(TextBlock o1, TextBlock o2) { // 获取文本块的顶部y坐标 float y1 = o1.getBoundingBox().top; float y2 = o2.getBoundingBox().top; // 设定行间距阈值,判断是否属于同一行(可根据实际场景调整) float lineThreshold = 25; if (Math.abs(y1 - y2) < lineThreshold) { // 同一行内按x轴从左到右排序 float x1 = o1.getBoundingBox().left; float x2 = o2.getBoundingBox().left; return Float.compare(x1, x2); } else { // 不同行按y轴从上到下排序 return Float.compare(y1, y2); } } }); // 遍历排序后的文本块进行处理 for (TextBlock textBlock : textBlockList) { if (textBlock != null && textBlock.getValue() != null) { mGraphicOverlay.add(new TextGraphic(mGraphicOverlay, textBlock)); // 这里可以添加你的文本处理逻辑,比如拼接、输出等 String detectedText = textBlock.getValue(); // ... } } }
小提示
lineThreshold的值可以根据你的实际场景调整:如果文本行间距较大,适当增大阈值;如果是密集排版的文本,减小阈值能更精准地判断同行文本。- 如果需要支持竖排文本(比如中文竖排),只需要调换排序逻辑,优先按x轴区分列,再按y轴排序同列文本即可。
内容的提问来源于stack exchange,提问作者Gunaseelan
相关产品推荐
相关产品推荐

