如何强制 Android 的 Mobile Vision 读取整行文本

gig*_*ig6 5 text-recognition android-vision

我已经按照教程实现了适用于 Android 的 Google Mobile Vision。我正在尝试构建一个应用程序来扫描收据并查找总数。然而,当我扫描以不同格式打印的不同收据时,API 将以似乎任意的方式检测 TextBlock。例如,在一张收据中,如果多个文本单词由单个空格分隔,则它们将被分组到单个 TextBlock 中。但是,如果两个文本单词被大量空格分隔,那么它们将被分隔为独立的 TextBlock,即使它们出现在同一“行”上。我想做的是强制 API 将收据的每一整行识别为单个实体。这可能吗?

小智 0

public ArrayList<T> getAllGraphicsInRow(float rawY) {
    synchronized (mLock) {
        ArrayList<T> row = new ArrayList<>();
        // Get the position of this View so the raw location can be offset relative to the view.
        int[] location = new int[2];
        this.getLocationOnScreen(location);
        for (T graphic : mGraphics) {
            float rawX = this.getWidth();
            for (int i=0; i<rawX; i+=10){
                if (graphic.contains(i - location[0], rawY - location[1])) {
                    if(!row.contains(graphic)) {
                        row.add(graphic);
                    }
                }
            }
        }
        return row;
    }
}
Run Code Online (Sandbox Code Playgroud)

它应该位于 GraphicOverlay.java 文件中,并且本质上获取该行中的所有图形。

public static boolean almostEqual(double a, double b, double eps){
    return Math.abs(a-b)<(eps);
}

public static boolean pointAlmostEqual(Point a, Point b){
    return almostEqual(a.y,b.y,10);
}
public static boolean cornerPointAlmostEqual(Point[] rect1, Point[] rect2){
    boolean almostEqual=true;
    for (int i=0; i<rect1.length;i++){
            if (!pointAlmostEqual(rect1[i],rect2[i])){
                almostEqual=false;
            }
        }
    return almostEqual;
}
private boolean onTap(float rawX, float rawY) {
    String priceRegex = "(\\d+[,.]\\d\\d)";
    ArrayList<OcrGraphic> graphics = mGraphicOverlay.getAllGraphicsInRow(rawY);
    OcrGraphic currentGraphics = mGraphicOverlay.getGraphicAtLocation(rawX,rawY);
    if (graphics !=null && currentGraphics!=null) {
        List<? extends Text> currentComponents = currentGraphics.getTextBlock().getComponents();
        final Pattern pattern = Pattern.compile(priceRegex);
        final Pattern pattern1 = Pattern.compile(priceRegex);

        TextBlock text = null;
        Log.i("text results", "This many in the row: " + Integer.toString(graphics.size()));

        ArrayList<Text> combinedComponents = new ArrayList<>();
        for (OcrGraphic graphic : graphics) {
            if (!graphic.equals(currentGraphics)) {
                text = graphic.getTextBlock();
                Log.i("text results", text.getValue());
                combinedComponents.addAll(text.getComponents());
            }
        }

        for (Text currentText : currentComponents) { // goes through components in the row
            final Matcher matcher = pattern.matcher(currentText.getValue()); // looks for
            Point[] currentPoint = currentText.getCornerPoints();

            for (Text otherCurrentText : combinedComponents) {//Looks for other components that are in the same row
                final Matcher otherMatcher = pattern1.matcher(otherCurrentText.getValue()); // looks for
                Point[] innerCurrentPoint = otherCurrentText.getCornerPoints();

                if (cornerPointAlmostEqual(currentPoint, innerCurrentPoint)) {
                    if (matcher.find()) { // if you click on the price
                        Log.i("oh yes", "Item: " + otherCurrentText.getValue());
                        Log.i("oh yes", "Value: " + matcher.group(1));
                        itemList.add(otherCurrentText.getValue());
                        priceList.add(Float.valueOf(matcher.group(1)));
                    }
                    if (otherMatcher.find()) { // if you click on the item
                        Log.i("oh yes", "Item: " + currentText.getValue());
                        Log.i("oh yes", "Value: " + otherMatcher.group(1));
                        itemList.add(currentText.getValue());
                        priceList.add(Float.valueOf(otherMatcher.group(1)));
                    }                      
                    Toast toast = Toast.makeText(this,  " Text Captured!" , Toast.LENGTH_SHORT);
                    toast.show();
                }
            }

        }
        return true;
    }
    return false;
}
Run Code Online (Sandbox Code Playgroud)

这应该在 OcrCaptureActivity.java 中,它将 TextBlock 分解为行,并找到与该行位于同一行中的块,并检查组件是否都是价格,并相应地打印所有值。

almostEqual 中的 eps 值是检查行中图形高度的容差。