需求
公司需求需要识别工单图片,后续再对识别到的内容入库。
网上查了下开源的,java 使用主要发现两个
- test4j
- RapidOcr-java:https://github.com/MyMonsterCat/RapidOcr-Java
两者使用都很简单,但是前者识别率很低,本文主要介绍后者
引入仓库
maven 配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
<dependency> <groupId>io.github.mymonstercat</groupId> <artifactId>rapidocr</artifactId> <version>${rapidocr.version}</version> </dependency>
<dependency> <groupId>io.github.mymonstercat</groupId> <artifactId>rapidocr-onnx-platform</artifactId> <version>${rapidocr-onnx-platform.version}</version> </dependency>
|
基本使用
使用起来很简单,代码如下
1 2 3 4 5 6 7
| ParamConfig paramConfig = ParamConfig.getDefaultConfig(); paramConfig.setDoAngle(true); paramConfig.setMostAngle(true); InferenceEngine engine = InferenceEngine.getInstance(Model.ONNX_PPOCR_V3);
OcrResult ocrResult = engine.runOcr(path, paramConfig);
|

进阶
- 图片上所有汉字均会识别出来,如果定位到需要的地方?
可根据坐标来识别相同行,y 轴误差在一定范围内,视为同一行,然后再按 x 轴排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
|
private List<List<String>> filterGroupRowData(List<TextBlock> textBlocks) { List<List<TextBlock>> groupedPoints = new ArrayList<>(); List<TextBlock> currentGroup = new ArrayList<>();
int yDiff = getYDiff(textBlocks); for (TextBlock textBlock : textBlocks) { Point point = textBlock.getBoxPoint().get(0); if (currentGroup.isEmpty()) { currentGroup.add(textBlock); } else { TextBlock lastTextBlock = currentGroup.get(currentGroup.size() - 1); Point lastPoint = lastTextBlock.getBoxPoint().get(0); if (Math.abs(point.getY() - lastPoint.getY()) <= yDiff) { currentGroup.add(textBlock); } else { groupedPoints.add(new ArrayList<>(currentGroup)); currentGroup.clear(); currentGroup.add(textBlock); } } } if (!currentGroup.isEmpty()) { groupedPoints.add(currentGroup); }
return groupedPoints.stream() .peek(group -> group.sort(Comparator.comparingInt(t -> t.getBoxPoint().get(0).getX()))) .map(group -> group.stream().map(t -> t.getText().trim()).collect(Collectors.toList())) .collect(Collectors.toList()); }
private int getYDiff(List<TextBlock> textBlocks) { if (CollUtil.isEmpty(textBlocks) || textBlocks.size() <=1) { return 0; } Point fristPoint = textBlocks.get(0).getBoxPoint().get(0); Point secondPoint = textBlocks.get(1).getBoxPoint().get(0); return NumberUtil.round(secondPoint.getY()-fristPoint.getY(),0).intValue(); }
|
- 绘制图片,补充矩形框底下文字
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
|
@Slf4j public class ImageUtil extends ImgUtil {
public static ByteArrayOutputStream drawImg(InputStream stream, List<TextBlock> blockList) { BufferedImage image = read(stream);
Graphics2D g2d = image.createGraphics(); for (final TextBlock textBlock : blockList) { final List<Point> boxPoint = textBlock.getBoxPoint(); final String text = textBlock.getText(); final Rectangle box = calcRectangle(boxPoint); final int x = box.x; final int y = box.y; final int width = box.width; final int height = box.height; g2d.setColor(Color.RED); g2d.drawRect(x, y, width, height); g2d.setColor(Color.BLACK); g2d.drawString(text, x, y + height + 15); } g2d.dispose();
ByteArrayOutputStream os = new ByteArrayOutputStream(); write(image, IMAGE_TYPE_PNG, os); return os; }
public static ByteArrayOutputStream drawImg(File imageFile, List<TextBlock> blockList) { ByteArrayOutputStream os = null; try (InputStream is = new FileInputStream(imageFile)) { os = drawImg(is, blockList); } catch (Exception e) { log.error("图片绘制异常", e); } return os; }
private static Rectangle calcRectangle(List<Point> pointList) { Assert.isFalse(CollUtil.isEmpty(pointList) || pointList.size() != 4, "需要4个点来构成矩形"); int minX = Integer.MAX_VALUE; int minY = Integer.MAX_VALUE; int maxX = Integer.MIN_VALUE; int maxY = Integer.MIN_VALUE; for (Point point : pointList) { final int x = point.getX(); final int y = point.getY(); if (x < minX) { minX = x; } if (y < minY) { minY = y; } if (x > maxX) { maxX = x; } if (y > maxY) { maxY = y; } } final int width = maxX - minX; final int height = maxY - minY; return new Rectangle(minX, minY, width, height); }
}
|