在视觉中将 TextBlock 从上到下排序 API
Sort TextBlock as top to bottom in vision API
当我使用视觉 API 扫描文本时,覆盖 return 多个文本框作为未排序的列表。因此,当我通过循环阅读文本时,有时我会以错误的顺序获取文本,即页面底部的文本首先出现。
OcrDetectorProcessor.java
中receiveDetections的示例代码
@Override
public void receiveDetections(Detector.Detections<TextBlock> detections) {
mGraphicOverlay.clear();
SparseArray<TextBlock> items = detections.getDetectedItems();
for (int i = 0; i < items.size(); ++i) {
TextBlock item = items.valueAt(i);
OcrGraphic graphic = new OcrGraphic(mGraphicOverlay, item);
mGraphicOverlay.add(graphic);
}
}
在此代码中,我想根据 TextBlock 的位置对 mGraphicOverlay
列表进行排序。
如果有 solution/suggestion 可用的话,那将对我很有帮助。
您需要按照OCR示例代码所示对输出进行排序。我在排序前将文本块分成几行。
这是我的代码:
List<Text> textLines = new ArrayList<>();
for (int i = 0; i < origTextBlocks.size(); i++) {
TextBlock textBlock = origTextBlocks.valueAt(i);
List<? extends Text> textComponents = textBlock.getComponents();
for (Text currentText : textComponents) {
textLines.add(currentText);
}
}
Collections.sort(textLines, new Comparator<Text>() {
@Override
public int compare(Text t1, Text t2) {
int diffOfTops = t1.getBoundingBox().top - t2.getBoundingBox().top;
int diffOfLefts = t1.getBoundingBox().left - t2.getBoundingBox().left;
if (diffOfTops != 0) {
return diffOfTops;
}
return diffOfLefts;
}
});
StringBuilder textBuilder = new StringBuilder();
for (Text text : textLines) {
if (text != null && text.getValue() != null) {
textBuilder.append(text.getValue() + "\n");
}
}
字符串 ocrString = textBuilder.toString();
我创建了这样的文本块比较器。
public static Comparator<TextBlock> TextBlockComparator
= new Comparator<TextBlock>() {
public int compare(TextBlock textBlock1, TextBlock textBlock2) {
return textBlock1.getBoundingBox().top - textBlock2.getBoundingBox().top;
}
};
并使用 Arrays.sort(myTextBlocks, Utils.TextBlockComparator);
排序
更新
今天我有时间测试@rajesh 的。似乎文本块排序比文本行排序更准确。
我试图从下图中提取文本。
结果来自 TextBlockComparator
结果来自 TextLineComparator
好吧,如果你有时间,测试我的代码。它做得很仔细,并且已经过很多时间的测试。它的设计采用 sparseArray(如 api 给出的)和 return 相同但已排序。希望对你有帮助。
/**
* Taking all the textblock in the frame, sort them to be at the same
* location as it is in real life (not as the original output)
* it return the sparsearray with the same textblock but sorted
*/
private SparseArray<TextBlock> sortTB(SparseArray<TextBlock> items) {
if (items == null) {
return null;
}
int size = items.size();
if (size == 0) {
return null;
}
//SparseArray to store the result, the same that the one in parameters but sorted
SparseArray<TextBlock> sortedSparseArray = new SparseArray<>(size);
//Moving from SparseArray to List, to use Lambda expression
List<TextBlock> listTest = new ArrayList<>();
for (int i = 0; i < size; i++) {
listTest.add(items.valueAt(i));
}
//sorting via a stream and lambda expression, then collecting the result
listTest = listTest.stream().sorted((textBlock1, textBlock2) -> {
RectF rect1 = new RectF(textBlock1.getComponents().get(0).getBoundingBox());
RectF rect2 = new RectF(textBlock2.getComponents().get(0).getBoundingBox());
//Test if textBlock are on the same line
if (rect2.centerY() < rect1.centerY() + SAME_LINE_DELTA
&& rect2.centerY() > rect1.centerY() - SAME_LINE_DELTA) {
//sort on the same line (X value)
return Float.compare(rect1.left, rect2.left);
}
//else sort them by their Y value
return Float.compare(rect1.centerY(), rect2.centerY());
}).collect(Collectors.toList());
//Store the result to the empty sparseArray
for (int i = 0; i < listTest.size(); i++) {
sortedSparseArray.append(i, listTest.get(i));
}
//return the sorted result
return sortedSparseArray;
}
当我使用视觉 API 扫描文本时,覆盖 return 多个文本框作为未排序的列表。因此,当我通过循环阅读文本时,有时我会以错误的顺序获取文本,即页面底部的文本首先出现。
OcrDetectorProcessor.java
中receiveDetections的示例代码@Override
public void receiveDetections(Detector.Detections<TextBlock> detections) {
mGraphicOverlay.clear();
SparseArray<TextBlock> items = detections.getDetectedItems();
for (int i = 0; i < items.size(); ++i) {
TextBlock item = items.valueAt(i);
OcrGraphic graphic = new OcrGraphic(mGraphicOverlay, item);
mGraphicOverlay.add(graphic);
}
}
在此代码中,我想根据 TextBlock 的位置对 mGraphicOverlay
列表进行排序。
如果有 solution/suggestion 可用的话,那将对我很有帮助。
您需要按照OCR示例代码所示对输出进行排序。我在排序前将文本块分成几行。
这是我的代码:
List<Text> textLines = new ArrayList<>();
for (int i = 0; i < origTextBlocks.size(); i++) {
TextBlock textBlock = origTextBlocks.valueAt(i);
List<? extends Text> textComponents = textBlock.getComponents();
for (Text currentText : textComponents) {
textLines.add(currentText);
}
}
Collections.sort(textLines, new Comparator<Text>() {
@Override
public int compare(Text t1, Text t2) {
int diffOfTops = t1.getBoundingBox().top - t2.getBoundingBox().top;
int diffOfLefts = t1.getBoundingBox().left - t2.getBoundingBox().left;
if (diffOfTops != 0) {
return diffOfTops;
}
return diffOfLefts;
}
});
StringBuilder textBuilder = new StringBuilder();
for (Text text : textLines) {
if (text != null && text.getValue() != null) {
textBuilder.append(text.getValue() + "\n");
}
}
字符串 ocrString = textBuilder.toString();
我创建了这样的文本块比较器。
public static Comparator<TextBlock> TextBlockComparator
= new Comparator<TextBlock>() {
public int compare(TextBlock textBlock1, TextBlock textBlock2) {
return textBlock1.getBoundingBox().top - textBlock2.getBoundingBox().top;
}
};
并使用 Arrays.sort(myTextBlocks, Utils.TextBlockComparator);
更新
今天我有时间测试@rajesh 的
我试图从下图中提取文本。
结果来自 TextBlockComparator
结果来自 TextLineComparator
好吧,如果你有时间,测试我的代码。它做得很仔细,并且已经过很多时间的测试。它的设计采用 sparseArray(如 api 给出的)和 return 相同但已排序。希望对你有帮助。
/**
* Taking all the textblock in the frame, sort them to be at the same
* location as it is in real life (not as the original output)
* it return the sparsearray with the same textblock but sorted
*/
private SparseArray<TextBlock> sortTB(SparseArray<TextBlock> items) {
if (items == null) {
return null;
}
int size = items.size();
if (size == 0) {
return null;
}
//SparseArray to store the result, the same that the one in parameters but sorted
SparseArray<TextBlock> sortedSparseArray = new SparseArray<>(size);
//Moving from SparseArray to List, to use Lambda expression
List<TextBlock> listTest = new ArrayList<>();
for (int i = 0; i < size; i++) {
listTest.add(items.valueAt(i));
}
//sorting via a stream and lambda expression, then collecting the result
listTest = listTest.stream().sorted((textBlock1, textBlock2) -> {
RectF rect1 = new RectF(textBlock1.getComponents().get(0).getBoundingBox());
RectF rect2 = new RectF(textBlock2.getComponents().get(0).getBoundingBox());
//Test if textBlock are on the same line
if (rect2.centerY() < rect1.centerY() + SAME_LINE_DELTA
&& rect2.centerY() > rect1.centerY() - SAME_LINE_DELTA) {
//sort on the same line (X value)
return Float.compare(rect1.left, rect2.left);
}
//else sort them by their Y value
return Float.compare(rect1.centerY(), rect2.centerY());
}).collect(Collectors.toList());
//Store the result to the empty sparseArray
for (int i = 0; i < listTest.size(); i++) {
sortedSparseArray.append(i, listTest.get(i));
}
//return the sorted result
return sortedSparseArray;
}