update site link and renew iocr.

This commit is contained in:
Calvin 2023-03-09 21:24:04 +08:00
parent 4f1ae402a6
commit b2ac9bc744
154 changed files with 10846 additions and 92 deletions

View File

@ -1,5 +1,5 @@
### 官网:
[官网链接](http://www.aias.top/)
[官网链接](https://www.aias.top/)
### 动物分类识别SDK
动物识别sdk支持7978种动物的分类识别。
@ -39,7 +39,7 @@
### 其它帮助信息
http://aias.top/guides.html
https://aias.top/guides.html
### Git地址
[Github链接](https://github.com/mymagicpower/AIAS)
@ -48,12 +48,12 @@ http://aias.top/guides.html
#### 帮助文档:
- http://aias.top/guides.html
- https://aias.top/guides.html
- 1.性能优化常见问题:
- http://aias.top/AIAS/guides/performance.html
- https://aias.top/AIAS/guides/performance.html
- 2.引擎配置包括CPUGPU在线自动加载及本地配置:
- http://aias.top/AIAS/guides/engine_config.html
- https://aias.top/AIAS/guides/engine_config.html
- 3.模型加载方式(在线自动加载,及本地配置):
- http://aias.top/AIAS/guides/load_model.html
- https://aias.top/AIAS/guides/load_model.html
- 4.Windows环境常见问题:
- http://aias.top/AIAS/guides/windows.html
- https://aias.top/AIAS/guides/windows.html

View File

@ -1,5 +1,5 @@
### 官网:
[官网链接](http://www.aias.top/)
[官网链接](https://www.aias.top/)
### 菜品分类识别SDK
@ -39,7 +39,7 @@
### 其它帮助信息
http://aias.top/guides.html
https://aias.top/guides.html
### Git地址
[Github链接](https://github.com/mymagicpower/AIAS)
@ -47,12 +47,12 @@ http://aias.top/guides.html
#### 帮助文档:
- http://aias.top/guides.html
- https://aias.top/guides.html
- 1.性能优化常见问题:
- http://aias.top/AIAS/guides/performance.html
- https://aias.top/AIAS/guides/performance.html
- 2.引擎配置包括CPUGPU在线自动加载及本地配置:
- http://aias.top/AIAS/guides/engine_config.html
- https://aias.top/AIAS/guides/engine_config.html
- 3.模型加载方式(在线自动加载,及本地配置):
- http://aias.top/AIAS/guides/load_model.html
- https://aias.top/AIAS/guides/load_model.html
- 4.Windows环境常见问题:
- http://aias.top/AIAS/guides/windows.html
- https://aias.top/AIAS/guides/windows.html

View File

@ -1,5 +1,5 @@
### 官网:
[官网链接](http://www.aias.top/)
[官网链接](https://www.aias.top/)
### 特征提取(512维)SDK
@ -93,7 +93,7 @@ sm.save("models/clip-ViT-B-32/clip-ViT-B-32.pt")
```
### 其它帮助信息
http://aias.top/guides.html
https://aias.top/guides.html
### Git地址
@ -103,12 +103,12 @@ http://aias.top/guides.html
#### 帮助文档:
- http://aias.top/guides.html
- https://aias.top/guides.html
- 1.性能优化常见问题:
- http://aias.top/AIAS/guides/performance.html
- https://aias.top/AIAS/guides/performance.html
- 2.引擎配置包括CPUGPU在线自动加载及本地配置:
- http://aias.top/AIAS/guides/engine_config.html
- https://aias.top/AIAS/guides/engine_config.html
- 3.模型加载方式(在线自动加载,及本地配置):
- http://aias.top/AIAS/guides/load_model.html
- https://aias.top/AIAS/guides/load_model.html
- 4.Windows环境常见问题:
- http://aias.top/AIAS/guides/windows.html
- https://aias.top/AIAS/guides/windows.html

View File

@ -1,5 +1,5 @@
### 官网:
[官网链接](http://www.aias.top/)
[官网链接](https://www.aias.top/)
### BIGGAN 图像自动生成SDK
@ -118,7 +118,7 @@ if __name__ == '__main__':
### 其它帮助信息
http://aias.top/guides.html
https://aias.top/guides.html
### Git地址
[Github链接](https://github.com/mymagicpower/AIAS)
@ -126,12 +126,12 @@ http://aias.top/guides.html
#### 帮助文档:
- http://aias.top/guides.html
- https://aias.top/guides.html
- 1.性能优化常见问题:
- http://aias.top/AIAS/guides/performance.html
- https://aias.top/AIAS/guides/performance.html
- 2.引擎配置包括CPUGPU在线自动加载及本地配置:
- http://aias.top/AIAS/guides/engine_config.html
- https://aias.top/AIAS/guides/engine_config.html
- 3.模型加载方式(在线自动加载,及本地配置):
- http://aias.top/AIAS/guides/load_model.html
- https://aias.top/AIAS/guides/load_model.html
- 4.Windows环境常见问题:
- http://aias.top/AIAS/guides/windows.html
- https://aias.top/AIAS/guides/windows.html

View File

@ -1,5 +1,5 @@
### 官网:
[官网链接](http://www.aias.top/)
[官网链接](https://www.aias.top/)
### 动作驱动 SDK
### 不得用于非法用途!
@ -43,7 +43,7 @@ build/output/result.gif
### 其它帮助信息
http://aias.top/guides.html
https://aias.top/guides.html
### Git地址
@ -55,12 +55,12 @@ https://gitee.com/endlesshh/first-order-model-java
#### 帮助文档:
- http://aias.top/guides.html
- https://aias.top/guides.html
- 1.性能优化常见问题:
- http://aias.top/AIAS/guides/performance.html
- https://aias.top/AIAS/guides/performance.html
- 2.引擎配置包括CPUGPU在线自动加载及本地配置:
- http://aias.top/AIAS/guides/engine_config.html
- https://aias.top/AIAS/guides/engine_config.html
- 3.模型加载方式(在线自动加载,及本地配置):
- http://aias.top/AIAS/guides/load_model.html
- https://aias.top/AIAS/guides/load_model.html
- 4.Windows环境常见问题:
- http://aias.top/AIAS/guides/windows.html
- https://aias.top/AIAS/guides/windows.html

View File

@ -1,5 +1,5 @@
### 官网:
[官网链接](http://www.aias.top/)
[官网链接](https://www.aias.top/)
### 风格迁移(预定义4种)SDK
风格迁移可以把一张图片转换成另一种风格。本sdk预定义了4种画风
@ -38,7 +38,7 @@
#### 找不到了,后面会有更好的替换
### 其它帮助信息
http://aias.top/guides.html
https://aias.top/guides.html
### Git地址
@ -47,12 +47,12 @@ http://aias.top/guides.html
#### 帮助文档:
- http://aias.top/guides.html
- https://aias.top/guides.html
- 1.性能优化常见问题:
- http://aias.top/AIAS/guides/performance.html
- https://aias.top/AIAS/guides/performance.html
- 2.引擎配置包括CPUGPU在线自动加载及本地配置:
- http://aias.top/AIAS/guides/engine_config.html
- https://aias.top/AIAS/guides/engine_config.html
- 3.模型加载方式(在线自动加载,及本地配置):
- http://aias.top/AIAS/guides/load_model.html
- https://aias.top/AIAS/guides/load_model.html
- 4.Windows环境常见问题:
- http://aias.top/AIAS/guides/windows.html
- https://aias.top/AIAS/guides/windows.html

View File

@ -1,5 +1,5 @@
### 官网:
[官网链接](http://www.aias.top/)
[官网链接](https://www.aias.top/)
### 超分辨(4倍)SDK
提升图片4倍分辨率。
@ -32,12 +32,12 @@
#### 帮助文档:
- http://aias.top/guides.html
- https://aias.top/guides.html
- 1.性能优化常见问题:
- http://aias.top/AIAS/guides/performance.html
- https://aias.top/AIAS/guides/performance.html
- 2.引擎配置包括CPUGPU在线自动加载及本地配置:
- http://aias.top/AIAS/guides/engine_config.html
- https://aias.top/AIAS/guides/engine_config.html
- 3.模型加载方式(在线自动加载,及本地配置):
- http://aias.top/AIAS/guides/load_model.html
- https://aias.top/AIAS/guides/load_model.html
- 4.Windows环境常见问题:
- http://aias.top/AIAS/guides/windows.html
- https://aias.top/AIAS/guides/windows.html

View File

@ -1,5 +1,5 @@
## 目录:
http://aias.top/
https://aias.top/
# 图像预处理SDK
在OCR文字识别的时候我们得到的图像一般情况下都不是正的多少都会有一定的倾斜。
@ -31,10 +31,10 @@ height = 753
### 帮助
引擎定制化配置,可以提升首次运行的引擎下载速度,解决外网无法访问或者带宽过低的问题。
[引擎定制化配置](http://aias.top/engine_cpu.html)
[引擎定制化配置](https://aias.top/engine_cpu.html)
### 官网:
[官网链接](http://www.aias.top/)
[官网链接](https://www.aias.top/)
### Git地址
[Github链接](https://github.com/mymagicpower/AIAS)

View File

@ -1,5 +1,5 @@
### 官网:
[官网链接](http://www.aias.top/)
[官网链接](https://www.aias.top/)
### 人脸对齐 SDK
@ -46,7 +46,7 @@
### 其它帮助信息
http://aias.top/guides.html
https://aias.top/guides.html
### Git地址
@ -56,12 +56,12 @@ http://aias.top/guides.html
#### 帮助文档:
- http://aias.top/guides.html
- https://aias.top/guides.html
- 1.性能优化常见问题:
- http://aias.top/AIAS/guides/performance.html
- https://aias.top/AIAS/guides/performance.html
- 2.引擎配置包括CPUGPU在线自动加载及本地配置:
- http://aias.top/AIAS/guides/engine_config.html
- https://aias.top/AIAS/guides/engine_config.html
- 3.模型加载方式(在线自动加载,及本地配置):
- http://aias.top/AIAS/guides/load_model.html
- https://aias.top/AIAS/guides/load_model.html
- 4.Windows环境常见问题:
- http://aias.top/AIAS/guides/windows.html
- https://aias.top/AIAS/guides/windows.html

View File

@ -1,5 +1,5 @@
### 官网:
[官网链接](http://www.aias.top/)
[官网链接](https://www.aias.top/)
### 人脸检测SDK
@ -54,7 +54,7 @@
### 其它帮助信息
http://aias.top/guides.html
https://aias.top/guides.html
### Git地址
@ -63,12 +63,12 @@ http://aias.top/guides.html
#### 帮助文档:
- http://aias.top/guides.html
- https://aias.top/guides.html
- 1.性能优化常见问题:
- http://aias.top/AIAS/guides/performance.html
- https://aias.top/AIAS/guides/performance.html
- 2.引擎配置包括CPUGPU在线自动加载及本地配置:
- http://aias.top/AIAS/guides/engine_config.html
- https://aias.top/AIAS/guides/engine_config.html
- 3.模型加载方式(在线自动加载,及本地配置):
- http://aias.top/AIAS/guides/load_model.html
- https://aias.top/AIAS/guides/load_model.html
- 4.Windows环境常见问题:
- http://aias.top/AIAS/guides/windows.html
- https://aias.top/AIAS/guides/windows.html

View File

@ -1,5 +1,5 @@
### 官网:
[官网链接](http://www.aias.top/)
[官网链接](https://www.aias.top/)
### 行人检测SDK
@ -36,7 +36,7 @@
### 其它帮助信息
http://aias.top/guides.html
https://aias.top/guides.html
### Git地址
[Github链接](https://github.com/mymagicpower/AIAS)
@ -44,12 +44,12 @@ http://aias.top/guides.html
#### 帮助文档:
- http://aias.top/guides.html
- https://aias.top/guides.html
- 1.性能优化常见问题:
- http://aias.top/AIAS/guides/performance.html
- https://aias.top/AIAS/guides/performance.html
- 2.引擎配置包括CPUGPU在线自动加载及本地配置:
- http://aias.top/AIAS/guides/engine_config.html
- https://aias.top/AIAS/guides/engine_config.html
- 3.模型加载方式(在线自动加载,及本地配置):
- http://aias.top/AIAS/guides/load_model.html
- https://aias.top/AIAS/guides/load_model.html
- 4.Windows环境常见问题:
- http://aias.top/AIAS/guides/windows.html
- https://aias.top/AIAS/guides/windows.html

View File

@ -20,7 +20,7 @@ import java.nio.file.Paths;
/**
* 行人检测例子
* http://aias.top/
* https://aias.top/
* @author Calvin
*/

View File

@ -1,5 +1,5 @@
### 官网:
[官网链接](http://www.aias.top/)
[官网链接](https://www.aias.top/)
## 文字识别OCR工具箱
文字识别OCR目前在多个行业中得到了广泛应用比如金融行业的单据识别输入餐饮行业中的发票识别
@ -156,12 +156,12 @@ https://blog.csdn.net/wsp_1138886114/article/details/83374333
#### 帮助文档:
- http://aias.top/guides.html
- https://aias.top/guides.html
- 1.性能优化常见问题:
- http://aias.top/AIAS/guides/performance.html
- https://aias.top/AIAS/guides/performance.html
- 2.引擎配置包括CPUGPU在线自动加载及本地配置:
- http://aias.top/AIAS/guides/engine_config.html
- https://aias.top/AIAS/guides/engine_config.html
- 3.模型加载方式(在线自动加载,及本地配置):
- http://aias.top/AIAS/guides/load_model.html
- https://aias.top/AIAS/guides/load_model.html
- 4.Windows环境常见问题:
- http://aias.top/AIAS/guides/windows.html
- https://aias.top/AIAS/guides/windows.html

View File

@ -1,5 +1,5 @@
### 官网:
[官网链接](http://www.aias.top/)
[官网链接](https://www.aias.top/)
### 声纹识别
@ -118,12 +118,12 @@ if __name__ == '__main__':
#### 帮助文档:
- http://aias.top/guides.html
- https://aias.top/guides.html
- 1.性能优化常见问题:
- http://aias.top/AIAS/guides/performance.html
- https://aias.top/AIAS/guides/performance.html
- 2.引擎配置包括CPUGPU在线自动加载及本地配置:
- http://aias.top/AIAS/guides/engine_config.html
- https://aias.top/AIAS/guides/engine_config.html
- 3.模型加载方式(在线自动加载,及本地配置):
- http://aias.top/AIAS/guides/load_model.html
- https://aias.top/AIAS/guides/load_model.html
- 4.Windows环境常见问题:
- http://aias.top/AIAS/guides/windows.html
- https://aias.top/AIAS/guides/windows.html

View File

@ -1,5 +1,5 @@
### 目录:
http://aias.top/
https://aias.top/
### 人脸大数据搜索介绍
@ -130,7 +130,7 @@ me.calvin.modules.search.tools.MilvusInit.java
```
### 官网:
[官网链接](http://www.aias.top/)
[官网链接](https://www.aias.top/)
### Git地址
[Github链接](https://github.com/mymagicpower/AIAS)
@ -138,12 +138,12 @@ me.calvin.modules.search.tools.MilvusInit.java
#### 帮助文档:
- http://aias.top/guides.html
- https://aias.top/guides.html
- 1.性能优化常见问题:
- http://aias.top/AIAS/guides/performance.html
- https://aias.top/AIAS/guides/performance.html
- 2.引擎配置包括CPUGPU在线自动加载及本地配置:
- http://aias.top/AIAS/guides/engine_config.html
- https://aias.top/AIAS/guides/engine_config.html
- 3.模型加载方式(在线自动加载,及本地配置):
- http://aias.top/AIAS/guides/load_model.html
- https://aias.top/AIAS/guides/load_model.html
- 4.Windows环境常见问题:
- http://aias.top/AIAS/guides/windows.html
- https://aias.top/AIAS/guides/windows.html

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 856 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 980 KiB

View File

@ -0,0 +1 @@
<table><thead><tr><td>Methods</td><td>R</td><td>P</td><td>F</td><td>FPS</td></tr></thead><tbody><tr><td>SegLink[26]</td><td>70.0</td><td>86.0</td><td>770</td><td>89</td></tr><tr><td>PixelLink[4j</td><td>73.2</td><td>83.0</td><td>77.8</td><td></td></tr><tr><td>TextSnake18]</td><td>73.9</td><td>83.2</td><td>78.3</td><td>1.1</td></tr><tr><td>TextField[37]</td><td>75.9</td><td>87.4</td><td>81.3</td><td>36</td></tr><tr><td>MSR38]</td><td>76.7</td><td>87.4</td><td>81.7</td><td></td></tr><tr><td>FTSN3]</td><td>77.1</td><td>87.6</td><td>82.0</td><td></td></tr><tr><td>LSE[30]</td><td>81.7</td><td>84.2</td><td>82.9</td><td></td></tr><tr><td>CRAFT[2]</td><td>78.2</td><td>88.2</td><td>82.9</td><td>8.6</td></tr><tr><td>MCNJ161</td><td>79</td><td>88</td><td>83</td><td></td></tr><tr><td>ATRR[35]</td><td>82.1</td><td>85.2</td><td>83.6</td><td></td></tr><tr><td>PAN[34]</td><td>83.8</td><td>84.4</td><td>84.1</td><td>30.2</td></tr><tr><td>DB[12]</td><td>79.2</td><td>91.5</td><td>84.9</td><td>32.0</td></tr><tr><td>DRRG141]</td><td>82.30</td><td>88.05</td><td>85.08</td><td></td></tr><tr><td>Ours(SynText</td><td>80.68</td><td>85.40</td><td>82.97</td><td>12.68</td></tr><tr><td>OursMLT-17</td><td>84.54</td><td>86.62</td><td>85.57</td><td>12.31</td></tr></tbody></table>

View File

@ -0,0 +1,7 @@
[
{
"uid": "39e6200133bb4755a737fc97cbe188e6",
"name": "test",
"imageName": "7442ff603d1042d995a64bbcfeb1b1fc.png"
}
]

View File

@ -0,0 +1,130 @@
{
"uid": "39e6200133bb4755a737fc97cbe188e6",
"name": "test",
"imageName": "7442ff603d1042d995a64bbcfeb1b1fc.png",
"labelData": [
{
"index": 0,
"active": 0,
"type": "anchor",
"value": "限乘当日当次车",
"points": [
{
"x": 308,
"y": 558
},
{
"x": 688,
"y": 558
},
{
"x": 688,
"y": 638
},
{
"x": 308,
"y": 638
}
]
},
{
"index": 1,
"active": 0,
"type": "anchor",
"value": "中国铁路祝您旅途愉快",
"points": [
{
"x": 515,
"y": 825
},
{
"x": 998,
"y": 825
},
{
"x": 998,
"y": 883
},
{
"x": 515,
"y": 883
}
]
},
{
"index": 2,
"active": 0,
"type": "rectangle",
"value": "南昌站",
"field": "start",
"points": [
{
"x": 340,
"y": 283
},
{
"x": 695,
"y": 283
},
{
"x": 695,
"y": 378
},
{
"x": 340,
"y": 378
}
]
},
{
"index": 3,
"active": 0,
"type": "rectangle",
"value": "D6262",
"field": "ticket",
"points": [
{
"x": 773,
"y": 285
},
{
"x": 1013,
"y": 285
},
{
"x": 1013,
"y": 375
},
{
"x": 773,
"y": 375
}
]
},
{
"index": 4,
"active": 0,
"type": "rectangle",
"value": "九江站",
"field": "end",
"points": [
{
"x": 1073,
"y": 280
},
{
"x": 1423,
"y": 280
},
{
"x": 1423,
"y": 373
},
{
"x": 1073,
"y": 373
}
]
}
]
}

View File

@ -0,0 +1,293 @@
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="CheckStyle-IDEA-Module">
<option name="configuration">
<map />
</option>
</component>
<component name="FacetManager">
<facet type="Spring" name="Spring">
<configuration />
</facet>
<facet type="web" name="Web">
<configuration>
<webroots />
<sourceRoots>
<root url="file://$MODULE_DIR$/src/main/java" />
<root url="file://$MODULE_DIR$/src/main/resources" />
</sourceRoots>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter:2.1.9.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot:2.1.9.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-context:5.1.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-autoconfigure:2.1.9.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-logging:2.1.9.RELEASE" level="project" />
<orderEntry type="library" name="Maven: ch.qos.logback:logback-classic:1.2.3" level="project" />
<orderEntry type="library" name="Maven: ch.qos.logback:logback-core:1.2.3" level="project" />
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-to-slf4j:2.11.2" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:jul-to-slf4j:1.7.28" level="project" />
<orderEntry type="library" name="Maven: javax.annotation:javax.annotation-api:1.3.2" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-core:5.1.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-jcl:5.1.10.RELEASE" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: org.yaml:snakeyaml:1.23" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-web:2.1.9.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-json:2.1.9.RELEASE" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.9.9.3" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.9.9" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.9.9" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.9" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.module:jackson-module-parameter-names:2.9.9" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-tomcat:2.1.9.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-core:9.0.26" level="project" />
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-el:9.0.26" level="project" />
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-websocket:9.0.26" level="project" />
<orderEntry type="library" name="Maven: org.hibernate.validator:hibernate-validator:6.0.17.Final" level="project" />
<orderEntry type="library" name="Maven: javax.validation:validation-api:2.0.1.Final" level="project" />
<orderEntry type="library" name="Maven: org.jboss.logging:jboss-logging:3.3.3.Final" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-web:5.1.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-webmvc:5.1.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-expression:5.1.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-aop:2.1.9.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-aop:5.1.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.aspectj:aspectjweaver:1.9.4" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-starter-test:2.1.9.RELEASE" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-test:2.1.9.RELEASE" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-test-autoconfigure:2.1.9.RELEASE" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: com.jayway.jsonpath:json-path:2.4.0" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: net.minidev:json-smart:2.3" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: net.minidev:accessors-smart:1.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.ow2.asm:asm:5.0.4" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: junit:junit:4.12" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.assertj:assertj-core:3.11.1" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.mockito:mockito-core:2.23.4" level="project" />
<orderEntry type="library" name="Maven: net.bytebuddy:byte-buddy:1.9.16" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: net.bytebuddy:byte-buddy-agent:1.9.16" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.objenesis:objenesis:2.6" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-core:1.3" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-library:1.3" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.skyscreamer:jsonassert:1.5.0" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: com.vaadin.external.google:android-json:0.0.20131108.vaadin1" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework:spring-test:5.1.10.RELEASE" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.xmlunit:xmlunit-core:2.6.3" level="project" />
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-commons:2.1.2.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-beans:5.1.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.28" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.12.0" level="project" />
<orderEntry type="library" name="Maven: com.google.code.gson:gson:2.8.5" level="project" />
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-slf4j-impl:2.15.0" level="project" />
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-api:2.11.2" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: org.apache.logging.log4j:log4j-core:2.11.2" level="project" />
<orderEntry type="library" name="Maven: ai.djl:api:0.14.0" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-compress:1.21" level="project" />
<orderEntry type="library" name="Maven: ai.djl:basicdataset:0.14.0" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-csv:1.8" level="project" />
<orderEntry type="library" name="Maven: ai.djl:model-zoo:0.14.0" level="project" />
<orderEntry type="library" name="Maven: ai.djl.mxnet:mxnet-engine:0.14.0" level="project" />
<orderEntry type="library" name="Maven: ai.djl.mxnet:mxnet-native-auto:1.8.0" level="project" />
<orderEntry type="library" name="Maven: net.java.dev.jna:jna:5.6.0" level="project" />
<orderEntry type="library" name="Maven: ai.djl.paddlepaddle:paddlepaddle-engine:0.14.0" level="project" />
<orderEntry type="library" name="Maven: ai.djl.paddlepaddle:paddlepaddle-native-auto:2.0.2" level="project" />
<orderEntry type="library" name="Maven: ai.djl.paddlepaddle:paddlepaddle-model-zoo:0.14.0" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:javacv-platform:1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:javacv:1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:javacpp:1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:openblas:0.3.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:opencv:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:4.1.3-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flycapture:2.13.3.31-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libdc1394:2.2.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libfreenect:0.5.7-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libfreenect2:0.2.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:librealsense:1.12.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:videoinput:0.200-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:artoolkitplus:2.3.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flandmark:1.07-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:leptonica:1.78.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:tesseract:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:openblas-platform:0.3.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:openblas:android-arm:0.3.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:openblas:android-arm64:0.3.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:openblas:android-x86:0.3.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:openblas:android-x86_64:0.3.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:openblas:ios-arm64:0.3.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:openblas:ios-x86_64:0.3.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:openblas:linux-x86:0.3.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:openblas:linux-x86_64:0.3.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:openblas:linux-armhf:0.3.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:openblas:linux-arm64:0.3.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:openblas:linux-ppc64le:0.3.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:openblas:macosx-x86_64:0.3.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:openblas:windows-x86:0.3.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:openblas:windows-x86_64:0.3.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:opencv-platform:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:opencv:android-arm:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:opencv:android-arm64:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:opencv:android-x86:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:opencv:android-x86_64:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:opencv:ios-arm64:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:opencv:ios-x86_64:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:opencv:linux-x86:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:opencv:linux-x86_64:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:opencv:linux-armhf:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:opencv:linux-arm64:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:opencv:linux-ppc64le:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:opencv:macosx-x86_64:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:opencv:windows-x86:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:opencv:windows-x86_64:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:ffmpeg-platform:4.1.3-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:android-arm:4.1.3-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:android-arm64:4.1.3-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:android-x86:4.1.3-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:android-x86_64:4.1.3-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:linux-x86:4.1.3-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:linux-x86_64:4.1.3-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:linux-armhf:4.1.3-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:linux-arm64:4.1.3-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:linux-ppc64le:4.1.3-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:macosx-x86_64:4.1.3-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:windows-x86:4.1.3-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:windows-x86_64:4.1.3-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flycapture-platform:2.13.3.31-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flycapture:linux-x86:2.13.3.31-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flycapture:linux-x86_64:2.13.3.31-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flycapture:linux-armhf:2.13.3.31-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flycapture:linux-arm64:2.13.3.31-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flycapture:windows-x86:2.13.3.31-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flycapture:windows-x86_64:2.13.3.31-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libdc1394-platform:2.2.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libdc1394:linux-x86:2.2.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libdc1394:linux-x86_64:2.2.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libdc1394:linux-armhf:2.2.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libdc1394:linux-arm64:2.2.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libdc1394:linux-ppc64le:2.2.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libdc1394:macosx-x86_64:2.2.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libdc1394:windows-x86:2.2.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libdc1394:windows-x86_64:2.2.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libfreenect-platform:0.5.7-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libfreenect:linux-x86:0.5.7-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libfreenect:linux-x86_64:0.5.7-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libfreenect:linux-armhf:0.5.7-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libfreenect:linux-arm64:0.5.7-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libfreenect:linux-ppc64le:0.5.7-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libfreenect:macosx-x86_64:0.5.7-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libfreenect:windows-x86:0.5.7-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libfreenect:windows-x86_64:0.5.7-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libfreenect2-platform:0.2.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libfreenect2:linux-x86:0.2.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libfreenect2:linux-x86_64:0.2.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libfreenect2:macosx-x86_64:0.2.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libfreenect2:windows-x86_64:0.2.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:librealsense-platform:1.12.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:librealsense:linux-x86:1.12.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:librealsense:linux-x86_64:1.12.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:librealsense:macosx-x86_64:1.12.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:librealsense:windows-x86:1.12.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:librealsense:windows-x86_64:1.12.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:videoinput-platform:0.200-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:videoinput:windows-x86:0.200-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:videoinput:windows-x86_64:0.200-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:artoolkitplus-platform:2.3.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:artoolkitplus:android-arm:2.3.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:artoolkitplus:android-arm64:2.3.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:artoolkitplus:android-x86:2.3.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:artoolkitplus:android-x86_64:2.3.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:artoolkitplus:linux-x86:2.3.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:artoolkitplus:linux-x86_64:2.3.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:artoolkitplus:linux-armhf:2.3.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:artoolkitplus:linux-arm64:2.3.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:artoolkitplus:linux-ppc64le:2.3.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:artoolkitplus:macosx-x86_64:2.3.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:artoolkitplus:windows-x86:2.3.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:artoolkitplus:windows-x86_64:2.3.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flandmark-platform:1.07-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flandmark:android-arm:1.07-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flandmark:android-arm64:1.07-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flandmark:android-x86:1.07-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flandmark:android-x86_64:1.07-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flandmark:linux-x86:1.07-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flandmark:linux-x86_64:1.07-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flandmark:linux-armhf:1.07-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flandmark:linux-arm64:1.07-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flandmark:linux-ppc64le:1.07-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flandmark:macosx-x86_64:1.07-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flandmark:windows-x86:1.07-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flandmark:windows-x86_64:1.07-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:leptonica-platform:1.78.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:leptonica:android-arm:1.78.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:leptonica:android-arm64:1.78.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:leptonica:android-x86:1.78.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:leptonica:android-x86_64:1.78.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:leptonica:linux-x86:1.78.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:leptonica:linux-x86_64:1.78.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:leptonica:linux-armhf:1.78.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:leptonica:linux-arm64:1.78.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:leptonica:linux-ppc64le:1.78.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:leptonica:macosx-x86_64:1.78.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:leptonica:windows-x86:1.78.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:leptonica:windows-x86_64:1.78.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:tesseract-platform:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:tesseract:android-arm:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:tesseract:android-arm64:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:tesseract:android-x86:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:tesseract:android-x86_64:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:tesseract:linux-x86:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:tesseract:linux-x86_64:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:tesseract:linux-armhf:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:tesseract:linux-arm64:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:tesseract:linux-ppc64le:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:tesseract:macosx-x86_64:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:tesseract:windows-x86:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:tesseract:windows-x86_64:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: gov.nist.math:jama:1.0.3" level="project" />
<orderEntry type="library" name="Maven: org.projectlombok:lombok:1.18.10" level="project" />
<orderEntry type="library" name="Maven: com.google.http-client:google-http-client:1.19.0" level="project" />
<orderEntry type="library" name="Maven: com.google.code.findbugs:jsr305:1.3.9" level="project" />
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpclient:4.5.10" level="project" />
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpcore:4.4.12" level="project" />
<orderEntry type="library" name="Maven: commons-cli:commons-cli:1.4" level="project" />
<orderEntry type="library" name="Maven: com.alibaba:fastjson:1.2.70" level="project" />
<orderEntry type="library" name="Maven: com.github.xiaoymin:knife4j-spring-boot-starter:2.0.2" level="project" />
<orderEntry type="library" name="Maven: com.github.xiaoymin:knife4j-spring-boot-autoconfigure:2.0.2" level="project" />
<orderEntry type="library" name="Maven: com.github.xiaoymin:knife4j-spring:2.0.2" level="project" />
<orderEntry type="library" name="Maven: com.github.xiaoymin:knife4j-annotations:2.0.2" level="project" />
<orderEntry type="library" name="Maven: com.github.xiaoymin:knife4j-core:2.0.2" level="project" />
<orderEntry type="library" name="Maven: org.javassist:javassist:3.25.0-GA" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-bean-validators:2.9.2" level="project" />
<orderEntry type="library" name="Maven: com.github.xiaoymin:knife4j-spring-ui:2.0.2" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-swagger2:2.9.2" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-spi:2.9.2" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-core:2.9.2" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-schema:2.9.2" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-swagger-common:2.9.2" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-spring-web:2.9.2" level="project" />
<orderEntry type="library" name="Maven: com.google.guava:guava:20.0" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml:classmate:1.4.0" level="project" />
<orderEntry type="library" name="Maven: org.springframework.plugin:spring-plugin-core:1.2.0.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.plugin:spring-plugin-metadata:1.2.0.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.mapstruct:mapstruct:1.2.0.Final" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-swagger-ui:2.9.2" level="project" />
<orderEntry type="library" name="Maven: io.swagger:swagger-annotations:1.5.21" level="project" />
<orderEntry type="library" name="Maven: io.swagger:swagger-models:1.5.21" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.9.0" level="project" />
<orderEntry type="library" name="Maven: commons-collections:commons-collections:3.2.2" level="project" />
<orderEntry type="library" name="Maven: org.apache.poi:poi:4.0.0" level="project" />
<orderEntry type="library" name="Maven: commons-codec:commons-codec:1.11" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-collections4:4.2" level="project" />
<orderEntry type="library" name="Maven: dom4j:dom4j:1.6.1" level="project" />
<orderEntry type="library" name="Maven: xml-apis:xml-apis:1.4.01" level="project" />
</component>
</module>

286
8_suite_hub/iocr/ocr-demo/mvnw vendored Normal file
View File

@ -0,0 +1,286 @@
#!/bin/sh
# ----------------------------------------------------------------------------
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Maven2 Start Up Batch script
#
# Required ENV vars:
# ------------------
# JAVA_HOME - location of a JDK home dir
#
# Optional ENV vars
# -----------------
# M2_HOME - location of maven2's installed home dir
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
# e.g. to debug Maven itself, use
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
# ----------------------------------------------------------------------------
if [ -z "$MAVEN_SKIP_RC" ] ; then
if [ -f /etc/mavenrc ] ; then
. /etc/mavenrc
fi
if [ -f "$HOME/.mavenrc" ] ; then
. "$HOME/.mavenrc"
fi
fi
# OS specific support. $var _must_ be set to either true or false.
cygwin=false;
darwin=false;
mingw=false
case "`uname`" in
CYGWIN*) cygwin=true ;;
MINGW*) mingw=true;;
Darwin*) darwin=true
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
if [ -z "$JAVA_HOME" ]; then
if [ -x "/usr/libexec/java_home" ]; then
export JAVA_HOME="`/usr/libexec/java_home`"
else
export JAVA_HOME="/Library/Java/Home"
fi
fi
;;
esac
if [ -z "$JAVA_HOME" ] ; then
if [ -r /etc/gentoo-release ] ; then
JAVA_HOME=`java-config --jre-home`
fi
fi
if [ -z "$M2_HOME" ] ; then
## resolve links - $0 may be a link to maven's home
PRG="$0"
# need this for relative symlinks
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG="`dirname "$PRG"`/$link"
fi
done
saveddir=`pwd`
M2_HOME=`dirname "$PRG"`/..
# make it fully qualified
M2_HOME=`cd "$M2_HOME" && pwd`
cd "$saveddir"
# echo Using m2 at $M2_HOME
fi
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin ; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --unix "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
fi
# For Mingw, ensure paths are in UNIX format before anything is touched
if $mingw ; then
[ -n "$M2_HOME" ] &&
M2_HOME="`(cd "$M2_HOME"; pwd)`"
[ -n "$JAVA_HOME" ] &&
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
# TODO classpath?
fi
if [ -z "$JAVA_HOME" ]; then
javaExecutable="`which javac`"
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
# readlink(1) is not available as standard on Solaris 10.
readLink=`which readlink`
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
if $darwin ; then
javaHome="`dirname \"$javaExecutable\"`"
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
else
javaExecutable="`readlink -f \"$javaExecutable\"`"
fi
javaHome="`dirname \"$javaExecutable\"`"
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
JAVA_HOME="$javaHome"
export JAVA_HOME
fi
fi
fi
if [ -z "$JAVACMD" ] ; then
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
else
JAVACMD="`which java`"
fi
fi
if [ ! -x "$JAVACMD" ] ; then
echo "Error: JAVA_HOME is not defined correctly." >&2
echo " We cannot execute $JAVACMD" >&2
exit 1
fi
if [ -z "$JAVA_HOME" ] ; then
echo "Warning: JAVA_HOME environment variable is not set."
fi
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
# traverses directory structure from process work directory to filesystem root
# first directory with .mvn subdirectory is considered project base directory
find_maven_basedir() {
if [ -z "$1" ]
then
echo "Path not specified to find_maven_basedir"
return 1
fi
basedir="$1"
wdir="$1"
while [ "$wdir" != '/' ] ; do
if [ -d "$wdir"/.mvn ] ; then
basedir=$wdir
break
fi
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
if [ -d "${wdir}" ]; then
wdir=`cd "$wdir/.."; pwd`
fi
# end of workaround
done
echo "${basedir}"
}
# concatenates all lines of a file
concat_lines() {
if [ -f "$1" ]; then
echo "$(tr -s '\n' ' ' < "$1")"
fi
}
BASE_DIR=`find_maven_basedir "$(pwd)"`
if [ -z "$BASE_DIR" ]; then
exit 1;
fi
##########################################################################################
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
# This allows using the maven wrapper in projects that prohibit checking in binary data.
##########################################################################################
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found .mvn/wrapper/maven-wrapper.jar"
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
fi
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
while IFS="=" read key value; do
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
esac
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
if [ "$MVNW_VERBOSE" = true ]; then
echo "Downloading from: $jarUrl"
fi
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
if command -v wget > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found wget ... using wget"
fi
wget "$jarUrl" -O "$wrapperJarPath"
elif command -v curl > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found curl ... using curl"
fi
curl -o "$wrapperJarPath" "$jarUrl"
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Falling back to using Java to download"
fi
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
if [ -e "$javaClass" ]; then
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Compiling MavenWrapperDownloader.java ..."
fi
# Compiling the Java class
("$JAVA_HOME/bin/javac" "$javaClass")
fi
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
# Running the downloader
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Running MavenWrapperDownloader.java ..."
fi
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
fi
fi
fi
fi
##########################################################################################
# End of extension
##########################################################################################
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
if [ "$MVNW_VERBOSE" = true ]; then
echo $MAVEN_PROJECTBASEDIR
fi
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
# For Cygwin, switch paths to Windows format before running java
if $cygwin; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --path --windows "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
fi
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
exec "$JAVACMD" \
$MAVEN_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"

161
8_suite_hub/iocr/ocr-demo/mvnw.cmd vendored Normal file
View File

@ -0,0 +1,161 @@
@REM ----------------------------------------------------------------------------
@REM Licensed to the Apache Software Foundation (ASF) under one
@REM or more contributor license agreements. See the NOTICE file
@REM distributed with this work for additional information
@REM regarding copyright ownership. The ASF licenses this file
@REM to you under the Apache License, Version 2.0 (the
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM http://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@REM KIND, either express or implied. See the License for the
@REM specific language governing permissions and limitations
@REM under the License.
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Maven2 Start Up Batch script
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@REM
@REM Optional ENV vars
@REM M2_HOME - location of maven2's installed home dir
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@REM e.g. to debug Maven itself, use
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
@REM ----------------------------------------------------------------------------
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
@echo off
@REM set title of command window
title %0
@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
@REM set %HOME% to equivalent of $HOME
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
@REM Execute a user defined script before this one
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
:skipRcPre
@setlocal
set ERROR_CODE=0
@REM To isolate internal variables from possible post scripts, we use another setlocal
@setlocal
@REM ==== START VALIDATION ====
if not "%JAVA_HOME%" == "" goto OkJHome
echo.
echo Error: JAVA_HOME not found in your environment. >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
:OkJHome
if exist "%JAVA_HOME%\bin\java.exe" goto init
echo.
echo Error: JAVA_HOME is set to an invalid directory. >&2
echo JAVA_HOME = "%JAVA_HOME%" >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
@REM ==== END VALIDATION ====
:init
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
@REM Fallback to current working directory if not found.
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
set EXEC_DIR=%CD%
set WDIR=%EXEC_DIR%
:findBaseDir
IF EXIST "%WDIR%"\.mvn goto baseDirFound
cd ..
IF "%WDIR%"=="%CD%" goto baseDirNotFound
set WDIR=%CD%
goto findBaseDir
:baseDirFound
set MAVEN_PROJECTBASEDIR=%WDIR%
cd "%EXEC_DIR%"
goto endDetectBaseDir
:baseDirNotFound
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
cd "%EXEC_DIR%"
:endDetectBaseDir
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
@setlocal EnableExtensions EnableDelayedExpansion
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
:endReadAdditionalConfig
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO (
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
)
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
if exist %WRAPPER_JAR% (
echo Found %WRAPPER_JAR%
) else (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %DOWNLOAD_URL%
powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"
echo Finished downloading %WRAPPER_JAR%
)
@REM End of extension
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
if ERRORLEVEL 1 goto error
goto end
:error
set ERROR_CODE=1
:end
@endlocal & set ERROR_CODE=%ERROR_CODE%
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
@REM check for post script, once with legacy .bat ending and once with .cmd ending
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
:skipRcPost
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
if "%MAVEN_BATCH_PAUSE%" == "on" pause
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
exit /B %ERROR_CODE%

View File

@ -0,0 +1,288 @@
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="CheckStyle-IDEA-Module">
<option name="configuration">
<map />
</option>
</component>
<component name="FacetManager">
<facet type="Spring" name="Spring">
<configuration />
</facet>
<facet type="web" name="Web">
<configuration>
<webroots />
<sourceRoots>
<root url="file://$MODULE_DIR$/src/main/java" />
<root url="file://$MODULE_DIR$/src/main/resources" />
</sourceRoots>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter:2.1.9.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot:2.1.9.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-context:5.1.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-autoconfigure:2.1.9.RELEASE" level="project" />
<orderEntry type="library" name="Maven: javax.annotation:javax.annotation-api:1.3.2" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-core:5.1.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-jcl:5.1.10.RELEASE" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: org.yaml:snakeyaml:1.23" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-web:2.1.9.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-json:2.1.9.RELEASE" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.9.9.3" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.9.9" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.9.9" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.9" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.module:jackson-module-parameter-names:2.9.9" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-tomcat:2.1.9.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-core:9.0.26" level="project" />
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-el:9.0.26" level="project" />
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-websocket:9.0.26" level="project" />
<orderEntry type="library" name="Maven: org.hibernate.validator:hibernate-validator:6.0.17.Final" level="project" />
<orderEntry type="library" name="Maven: javax.validation:validation-api:2.0.1.Final" level="project" />
<orderEntry type="library" name="Maven: org.jboss.logging:jboss-logging:3.3.3.Final" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-web:5.1.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-webmvc:5.1.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-expression:5.1.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-aop:2.1.9.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-aop:5.1.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.aspectj:aspectjweaver:1.9.4" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-starter-test:2.1.9.RELEASE" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-test:2.1.9.RELEASE" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-test-autoconfigure:2.1.9.RELEASE" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: com.jayway.jsonpath:json-path:2.4.0" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: net.minidev:json-smart:2.3" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: net.minidev:accessors-smart:1.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.ow2.asm:asm:5.0.4" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: junit:junit:4.12" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.assertj:assertj-core:3.11.1" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.mockito:mockito-core:2.23.4" level="project" />
<orderEntry type="library" name="Maven: net.bytebuddy:byte-buddy:1.9.16" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: net.bytebuddy:byte-buddy-agent:1.9.16" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.objenesis:objenesis:2.6" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-core:1.3" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-library:1.3" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.skyscreamer:jsonassert:1.5.0" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: com.vaadin.external.google:android-json:0.0.20131108.vaadin1" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework:spring-test:5.1.10.RELEASE" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.xmlunit:xmlunit-core:2.6.3" level="project" />
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-commons:2.1.2.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-beans:5.1.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.12.0" level="project" />
<orderEntry type="library" name="Maven: com.google.code.gson:gson:2.8.5" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.30" level="project" />
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-slf4j-impl:2.12.1" level="project" />
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-api:2.11.2" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: org.apache.logging.log4j:log4j-core:2.11.2" level="project" />
<orderEntry type="library" name="Maven: ai.djl:api:0.14.0" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-compress:1.21" level="project" />
<orderEntry type="library" name="Maven: ai.djl:basicdataset:0.14.0" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-csv:1.8" level="project" />
<orderEntry type="library" name="Maven: ai.djl:model-zoo:0.14.0" level="project" />
<orderEntry type="library" name="Maven: ai.djl.mxnet:mxnet-engine:0.14.0" level="project" />
<orderEntry type="library" name="Maven: ai.djl.mxnet:mxnet-native-auto:1.8.0" level="project" />
<orderEntry type="library" name="Maven: net.java.dev.jna:jna:5.6.0" level="project" />
<orderEntry type="library" name="Maven: ai.djl.paddlepaddle:paddlepaddle-engine:0.14.0" level="project" />
<orderEntry type="library" name="Maven: ai.djl.paddlepaddle:paddlepaddle-native-auto:2.0.2" level="project" />
<orderEntry type="library" name="Maven: ai.djl.paddlepaddle:paddlepaddle-model-zoo:0.14.0" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:javacv-platform:1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:javacv:1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:javacpp:1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:openblas:0.3.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:opencv:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:4.1.3-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flycapture:2.13.3.31-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libdc1394:2.2.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libfreenect:0.5.7-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libfreenect2:0.2.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:librealsense:1.12.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:videoinput:0.200-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:artoolkitplus:2.3.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flandmark:1.07-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:leptonica:1.78.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:tesseract:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:openblas-platform:0.3.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:openblas:android-arm:0.3.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:openblas:android-arm64:0.3.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:openblas:android-x86:0.3.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:openblas:android-x86_64:0.3.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:openblas:ios-arm64:0.3.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:openblas:ios-x86_64:0.3.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:openblas:linux-x86:0.3.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:openblas:linux-x86_64:0.3.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:openblas:linux-armhf:0.3.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:openblas:linux-arm64:0.3.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:openblas:linux-ppc64le:0.3.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:openblas:macosx-x86_64:0.3.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:openblas:windows-x86:0.3.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:openblas:windows-x86_64:0.3.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:opencv-platform:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:opencv:android-arm:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:opencv:android-arm64:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:opencv:android-x86:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:opencv:android-x86_64:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:opencv:ios-arm64:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:opencv:ios-x86_64:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:opencv:linux-x86:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:opencv:linux-x86_64:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:opencv:linux-armhf:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:opencv:linux-arm64:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:opencv:linux-ppc64le:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:opencv:macosx-x86_64:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:opencv:windows-x86:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:opencv:windows-x86_64:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:ffmpeg-platform:4.1.3-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:android-arm:4.1.3-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:android-arm64:4.1.3-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:android-x86:4.1.3-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:android-x86_64:4.1.3-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:linux-x86:4.1.3-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:linux-x86_64:4.1.3-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:linux-armhf:4.1.3-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:linux-arm64:4.1.3-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:linux-ppc64le:4.1.3-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:macosx-x86_64:4.1.3-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:windows-x86:4.1.3-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:windows-x86_64:4.1.3-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flycapture-platform:2.13.3.31-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flycapture:linux-x86:2.13.3.31-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flycapture:linux-x86_64:2.13.3.31-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flycapture:linux-armhf:2.13.3.31-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flycapture:linux-arm64:2.13.3.31-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flycapture:windows-x86:2.13.3.31-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flycapture:windows-x86_64:2.13.3.31-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libdc1394-platform:2.2.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libdc1394:linux-x86:2.2.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libdc1394:linux-x86_64:2.2.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libdc1394:linux-armhf:2.2.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libdc1394:linux-arm64:2.2.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libdc1394:linux-ppc64le:2.2.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libdc1394:macosx-x86_64:2.2.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libdc1394:windows-x86:2.2.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libdc1394:windows-x86_64:2.2.6-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libfreenect-platform:0.5.7-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libfreenect:linux-x86:0.5.7-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libfreenect:linux-x86_64:0.5.7-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libfreenect:linux-armhf:0.5.7-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libfreenect:linux-arm64:0.5.7-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libfreenect:linux-ppc64le:0.5.7-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libfreenect:macosx-x86_64:0.5.7-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libfreenect:windows-x86:0.5.7-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libfreenect:windows-x86_64:0.5.7-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libfreenect2-platform:0.2.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libfreenect2:linux-x86:0.2.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libfreenect2:linux-x86_64:0.2.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libfreenect2:macosx-x86_64:0.2.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:libfreenect2:windows-x86_64:0.2.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:librealsense-platform:1.12.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:librealsense:linux-x86:1.12.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:librealsense:linux-x86_64:1.12.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:librealsense:macosx-x86_64:1.12.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:librealsense:windows-x86:1.12.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:librealsense:windows-x86_64:1.12.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:videoinput-platform:0.200-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:videoinput:windows-x86:0.200-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:videoinput:windows-x86_64:0.200-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:artoolkitplus-platform:2.3.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:artoolkitplus:android-arm:2.3.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:artoolkitplus:android-arm64:2.3.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:artoolkitplus:android-x86:2.3.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:artoolkitplus:android-x86_64:2.3.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:artoolkitplus:linux-x86:2.3.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:artoolkitplus:linux-x86_64:2.3.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:artoolkitplus:linux-armhf:2.3.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:artoolkitplus:linux-arm64:2.3.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:artoolkitplus:linux-ppc64le:2.3.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:artoolkitplus:macosx-x86_64:2.3.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:artoolkitplus:windows-x86:2.3.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:artoolkitplus:windows-x86_64:2.3.1-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flandmark-platform:1.07-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flandmark:android-arm:1.07-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flandmark:android-arm64:1.07-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flandmark:android-x86:1.07-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flandmark:android-x86_64:1.07-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flandmark:linux-x86:1.07-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flandmark:linux-x86_64:1.07-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flandmark:linux-armhf:1.07-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flandmark:linux-arm64:1.07-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flandmark:linux-ppc64le:1.07-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flandmark:macosx-x86_64:1.07-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flandmark:windows-x86:1.07-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:flandmark:windows-x86_64:1.07-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:leptonica-platform:1.78.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:leptonica:android-arm:1.78.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:leptonica:android-arm64:1.78.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:leptonica:android-x86:1.78.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:leptonica:android-x86_64:1.78.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:leptonica:linux-x86:1.78.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:leptonica:linux-x86_64:1.78.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:leptonica:linux-armhf:1.78.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:leptonica:linux-arm64:1.78.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:leptonica:linux-ppc64le:1.78.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:leptonica:macosx-x86_64:1.78.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:leptonica:windows-x86:1.78.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:leptonica:windows-x86_64:1.78.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:tesseract-platform:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:tesseract:android-arm:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:tesseract:android-arm64:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:tesseract:android-x86:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:tesseract:android-x86_64:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:tesseract:linux-x86:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:tesseract:linux-x86_64:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:tesseract:linux-armhf:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:tesseract:linux-arm64:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:tesseract:linux-ppc64le:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:tesseract:macosx-x86_64:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:tesseract:windows-x86:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.bytedeco:tesseract:windows-x86_64:4.1.0-1.5.1" level="project" />
<orderEntry type="library" name="Maven: gov.nist.math:jama:1.0.3" level="project" />
<orderEntry type="library" name="Maven: org.projectlombok:lombok:1.18.10" level="project" />
<orderEntry type="library" name="Maven: com.google.http-client:google-http-client:1.19.0" level="project" />
<orderEntry type="library" name="Maven: com.google.code.findbugs:jsr305:1.3.9" level="project" />
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpclient:4.5.10" level="project" />
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpcore:4.4.12" level="project" />
<orderEntry type="library" name="Maven: commons-cli:commons-cli:1.4" level="project" />
<orderEntry type="library" name="Maven: com.alibaba:fastjson:1.2.70" level="project" />
<orderEntry type="library" name="Maven: com.github.xiaoymin:knife4j-spring-boot-starter:2.0.2" level="project" />
<orderEntry type="library" name="Maven: com.github.xiaoymin:knife4j-spring-boot-autoconfigure:2.0.2" level="project" />
<orderEntry type="library" name="Maven: com.github.xiaoymin:knife4j-spring:2.0.2" level="project" />
<orderEntry type="library" name="Maven: com.github.xiaoymin:knife4j-annotations:2.0.2" level="project" />
<orderEntry type="library" name="Maven: com.github.xiaoymin:knife4j-core:2.0.2" level="project" />
<orderEntry type="library" name="Maven: org.javassist:javassist:3.25.0-GA" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-bean-validators:2.9.2" level="project" />
<orderEntry type="library" name="Maven: com.github.xiaoymin:knife4j-spring-ui:2.0.2" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-swagger2:2.9.2" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-spi:2.9.2" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-core:2.9.2" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-schema:2.9.2" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-swagger-common:2.9.2" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-spring-web:2.9.2" level="project" />
<orderEntry type="library" name="Maven: com.google.guava:guava:20.0" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml:classmate:1.4.0" level="project" />
<orderEntry type="library" name="Maven: org.springframework.plugin:spring-plugin-core:1.2.0.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.plugin:spring-plugin-metadata:1.2.0.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.mapstruct:mapstruct:1.2.0.Final" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-swagger-ui:2.9.2" level="project" />
<orderEntry type="library" name="Maven: io.swagger:swagger-annotations:1.5.21" level="project" />
<orderEntry type="library" name="Maven: io.swagger:swagger-models:1.5.21" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.9.0" level="project" />
<orderEntry type="library" name="Maven: commons-collections:commons-collections:3.2.2" level="project" />
<orderEntry type="library" name="Maven: org.apache.poi:poi:4.0.0" level="project" />
<orderEntry type="library" name="Maven: commons-codec:commons-codec:1.11" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-collections4:4.2" level="project" />
<orderEntry type="library" name="Maven: dom4j:dom4j:1.6.1" level="project" />
<orderEntry type="library" name="Maven: xml-apis:xml-apis:1.4.01" level="project" />
</component>
</module>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

View File

@ -0,0 +1,248 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.9.RELEASE</version>
</parent>
<groupId>aias</groupId>
<artifactId>iocr-demo</artifactId>
<version>0.1.0</version>
<name>aias-ocr-demo</name>
<description>AIAS IOCR Demo Project</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<jna.version>5.6.0</jna.version>
<fastjson.version>1.2.70</fastjson.version>
<swagger.version>2.9.2</swagger.version>
<djl.version>0.14.0</djl.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
<version>2.1.2.RELEASE</version>
</dependency>
<!-- apache commons -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8.1</version>
</dependency>
<!-- Gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.15.0</version>
</dependency>
<!-- DJL -->
<dependency>
<groupId>ai.djl</groupId>
<artifactId>api</artifactId>
<version>${djl.version}</version>
</dependency>
<dependency>
<groupId>ai.djl</groupId>
<artifactId>basicdataset</artifactId>
<version>${djl.version}</version>
</dependency>
<dependency>
<groupId>ai.djl</groupId>
<artifactId>model-zoo</artifactId>
<version>${djl.version}</version>
</dependency>
<dependency>
<groupId>ai.djl.mxnet</groupId>
<artifactId>mxnet-engine</artifactId>
<version>${djl.version}</version>
</dependency>
<dependency>
<groupId>ai.djl.mxnet</groupId>
<artifactId>mxnet-native-auto</artifactId>
<version>1.8.0</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>ai.djl.mxnet</groupId>-->
<!-- <artifactId>mxnet-native-mkl</artifactId>-->
<!-- <classifier>linux-x86_64</classifier>-->
<!-- <scope>runtime</scope>-->
<!-- <version>1.8.0</version>-->
<!-- </dependency>-->
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>${jna.version}</version> <!-- overrides default spring boot version to comply with DJL -->
</dependency>
<!-- PaddlePaddle -->
<dependency>
<groupId>ai.djl.paddlepaddle</groupId>
<artifactId>paddlepaddle-engine</artifactId>
<version>${djl.version}</version>
</dependency>
<dependency>
<groupId>ai.djl.paddlepaddle</groupId>
<artifactId>paddlepaddle-native-auto</artifactId>
<version>2.0.2</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>ai.djl.paddlepaddle</groupId>-->
<!-- <artifactId>paddlepaddle-native-cpu</artifactId>-->
<!-- <classifier>linux-x86_64</classifier>-->
<!-- <version>2.0.2</version>-->
<!-- </dependency>-->
<dependency>
<groupId>ai.djl.paddlepaddle</groupId>
<artifactId>paddlepaddle-model-zoo</artifactId>
<version>${djl.version}</version>
</dependency>
<dependency>
<groupId>ai.djl.paddlepaddle</groupId>
<artifactId>paddlepaddle-model-zoo</artifactId>
<version>${djl.version}</version>
</dependency>
<!-- java cv -->
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv-platform</artifactId>
<version>1.5.1</version>
</dependency>
<dependency>
<groupId>gov.nist.math</groupId>
<artifactId>jama</artifactId>
<version>1.0.3</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.google.http-client</groupId>
<artifactId>google-http-client</artifactId>
<version>1.19.0</version>
</dependency>
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.4</version>
</dependency>
<!-- fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>2.0.2</version>
</dependency>
<!-- Swagger UI 相关 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger.version}</version>
<exclusions>
<exclusion>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
</exclusion>
<exclusion>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.version}</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.5.21</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
<version>1.5.21</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>me.aias.ocr.MainApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,3 @@
Manifest-Version: 1.0
Main-Class: me.aias.ocr.MainApplication

View File

@ -0,0 +1,16 @@
package me.aias.ocr;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}
}

View File

@ -0,0 +1,76 @@
package me.aias.ocr.configuration;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
/**
* @author Calvin
* @date Oct 19, 2021
*/
@Configuration
@EnableWebMvc
public class ConfigAdapter implements WebMvcConfigurer {
// file configuration
private final FileProperties properties;
public ConfigAdapter(FileProperties properties) {
this.properties = properties;
}
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
FileProperties.ElPath path = properties.getPath();
String pathUtl = "file:" + path.getPath().replace("\\", "/");
registry.addResourceHandler("/file/**").addResourceLocations(pathUtl).setCachePeriod(0);
registry.addResourceHandler("/file/tables/**").addResourceLocations(pathUtl + "tables/").setCachePeriod(0);
registry.addResourceHandler("/file/images/**").addResourceLocations(pathUtl + "images/").setCachePeriod(0);
registry.addResourceHandler("/**").addResourceLocations("classpath:/META-INF/resources/").setCachePeriod(0);
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
// 使用 fastjson 序列化会导致 @JsonIgnore 失效可以使用 @JSONField(serialize = false) 替换
FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
List<MediaType> supportMediaTypeList = new ArrayList<>();
supportMediaTypeList.add(MediaType.APPLICATION_JSON_UTF8);
supportMediaTypeList.add(MediaType.TEXT_HTML);
FastJsonConfig config = new FastJsonConfig();
config.setDateFormat("yyyy-MM-dd HH:mm:ss");
config.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect);
fastJsonHttpMessageConverter.setFastJsonConfig(config);
fastJsonHttpMessageConverter.setSupportedMediaTypes(supportMediaTypeList);
fastJsonHttpMessageConverter.setDefaultCharset(StandardCharsets.UTF_8);
converters.add(fastJsonHttpMessageConverter);
}
}

View File

@ -0,0 +1,43 @@
package me.aias.ocr.configuration;
import lombok.Data;
import me.aias.ocr.utils.Constants;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* @author Calvin
* @date Oct 19, 2021
*/
@Data
@Configuration
@ConfigurationProperties(prefix = "file")
public class FileProperties {
/**
* File size limitation
*/
private Long maxSize;
private ElPath mac;
private ElPath linux;
private ElPath windows;
public ElPath getPath() {
String os = System.getProperty("os.name");
if (os.toLowerCase().startsWith(Constants.WIN)) {
return windows;
} else if (os.toLowerCase().startsWith(Constants.MAC)) {
return mac;
}
return linux;
}
@Data
public static class ElPath {
private String path;
}
}

View File

@ -0,0 +1,73 @@
package me.aias.ocr.configuration;
import ai.djl.MalformedModelException;
import ai.djl.repository.zoo.ModelNotFoundException;
import me.aias.ocr.inference.LayoutDetectionModel;
import me.aias.ocr.inference.RecognitionModel;
import me.aias.ocr.inference.TableDetectionModel;
import me.aias.ocr.utils.Constants;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.io.IOException;
/**
* @author Calvin
* @date Oct 19, 2021
*/
@Configuration
public class ModelConfiguration {
@Value("${model.type}")
private String type;
@Value("${model.table.layout}")
private String tableLayout;
@Value("${model.table.table-en}")
private String table;
// mobile model
@Value("${model.mobile.det}")
private String mobileDet;
@Value("${model.mobile.rec}")
private String mobileRec;
// light model
@Value("${model.light.det}")
private String lightDet;
@Value("${model.light.rec}")
private String lightRec;
// server model
@Value("${model.server.det}")
private String serverDet;
@Value("${model.server.rec}")
private String serverRec;
@Bean
public RecognitionModel recognitionModel() throws IOException, ModelNotFoundException, MalformedModelException {
RecognitionModel recognitionModel = new RecognitionModel();
if (StringUtils.isEmpty(type) || type.toLowerCase().equals("mobile")) {
recognitionModel.init(mobileDet, mobileRec);
} else if (type.toLowerCase().equals("light")) {
recognitionModel.init(lightDet, lightRec);
} else if (type.toLowerCase().equals("server")) {
recognitionModel.init(serverDet, serverRec);
} else {
recognitionModel.init(mobileDet, mobileRec);
}
return recognitionModel;
}
@Bean
public TableDetectionModel tableDetectionModel() throws IOException, ModelNotFoundException, MalformedModelException {
TableDetectionModel tableDetectionModel = new TableDetectionModel();
tableDetectionModel.init(table);
return tableDetectionModel;
}
@Bean
public LayoutDetectionModel layoutDetectionModel() throws IOException, ModelNotFoundException, MalformedModelException {
LayoutDetectionModel layoutDetectionModel = new LayoutDetectionModel();
layoutDetectionModel.init(tableLayout);
return layoutDetectionModel;
}
}

View File

@ -0,0 +1,111 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package me.aias.ocr.configuration;
import com.fasterxml.classmate.TypeResolver;
import com.google.common.base.Predicates;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.data.domain.Pageable;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.schema.AlternateTypeRule;
import springfox.documentation.schema.AlternateTypeRuleConvention;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.List;
import static com.google.common.collect.Lists.newArrayList;
import static springfox.documentation.schema.AlternateTypeRules.newRule;
/**
* api doc.html
* @author Calvin
* @date Oct 19, 2021
*/
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Value("${swagger.enabled}")
private Boolean enabled;
@Bean
@SuppressWarnings("all")
public Docket createRestApi() {
ParameterBuilder ticketPar = new ParameterBuilder();
return new Docket(DocumentationType.SWAGGER_2)
.enable(enabled)
.apiInfo(apiInfo())
.select()
.paths(Predicates.not(PathSelectors.regex("/error.*")))
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.description("")
.title("接口文档")
.version("1.0")
.build();
}
}
/**
* 将Pageable转换展示在swagger中
*/
@Configuration
class SwaggerDataConfig {
@Bean
public AlternateTypeRuleConvention pageableConvention(final TypeResolver resolver) {
return new AlternateTypeRuleConvention() {
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
@Override
public List<AlternateTypeRule> rules() {
return newArrayList(newRule(resolver.resolve(Pageable.class), resolver.resolve(Page.class)));
}
};
}
@ApiModel
@Data
private static class Page {
@ApiModelProperty("页码 (0..N)")
private Integer page;
@ApiModelProperty("每页显示的数目")
private Integer size;
@ApiModelProperty("以下列格式排序标准property[,asc | desc]。 默认排序顺序为升序。 支持多种排序条件id,asc")
private List<String> sort;
}
}

View File

@ -0,0 +1,75 @@
package me.aias.ocr.controller;
import ai.djl.modality.cv.Image;
import ai.djl.modality.cv.ImageFactory;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import me.aias.ocr.configuration.FileProperties;
import me.aias.ocr.model.DataBean;
import me.aias.ocr.model.ResultBean;
import me.aias.ocr.service.InferService;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
/**
* @author Calvin
* @date Oct 19, 2021
*/
@Api(tags = "通用文字识别")
@RestController
@RequestMapping("/inference")
public class InferController {
private Logger logger = LoggerFactory.getLogger(InferController.class);
@Autowired
private InferService inferService;
@Value("${server.baseUri}")
private String baseUri;
/**
* file configuration
*/
@Autowired
private FileProperties properties;
@ApiOperation(value = "通用文字识别-URL")
@GetMapping(value = "/generalInfoForImageUrl", produces = "application/json;charset=utf-8")
public ResultBean generalInfoForImageUrl(@RequestParam(value = "url") String url) throws IOException {
try {
Image image = ImageFactory.getInstance().fromUrl(url);
List<DataBean> dataList = inferService.getGeneralInfo(image);
return ResultBean.success().add("result", dataList);
} catch (Exception e) {
logger.error(e.getMessage());
e.printStackTrace();
return ResultBean.failure().add("errors", e.getMessage());
}
}
@ApiOperation(value = "通用文字识别-图片")
@PostMapping(value = "/generalInfoForImageFile", produces = "application/json;charset=utf-8")
public ResultBean generalInfoForImageFile(@RequestParam(value = "imageFile") MultipartFile imageFile) {
try (InputStream inputStream = imageFile.getInputStream()) {
String base64Img = Base64.encodeBase64String(imageFile.getBytes());
Image image = ImageFactory.getInstance().fromInputStream(inputStream);
List<DataBean> dataList = inferService.getGeneralInfo(image);
return ResultBean.success().add("result", dataList)
.add("base64Img", "data:imageName/jpeg;base64," + base64Img);
} catch (Exception e) {
logger.error(e.getMessage());
e.printStackTrace();
return ResultBean.failure().add("errors", e.getMessage());
}
}
}

View File

@ -0,0 +1,248 @@
package me.aias.ocr.controller;
import ai.djl.modality.cv.Image;
import ai.djl.modality.cv.ImageFactory;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import me.aias.ocr.configuration.FileProperties;
import me.aias.ocr.model.DataBean;
import me.aias.ocr.model.ResultBean;
import me.aias.ocr.service.InferService;
import me.aias.ocr.service.TableInferService;
import me.aias.ocr.utils.ConvertHtml2Excel;
import me.aias.ocr.utils.UUIDUtils;
import org.apache.commons.codec.binary.Base64;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author Calvin
* @date Oct 19, 2021
*/
@Api(tags = "表格文字识别")
@RestController
@RequestMapping("/table")
public class TableController {
private Logger logger = LoggerFactory.getLogger(TableController.class);
@Autowired
private TableInferService tableInferService;
@Value("${server.baseUri}")
private String baseUri;
/**
* file configuration
*/
@Autowired
private FileProperties properties;
@ApiOperation(value = "单表格文字识别-URL")
@GetMapping(value = "/tableInfoForImageUrl")
public ResultBean tableInfoForImageUrl(@RequestParam(value = "url") String url) {
try {
Image image = ImageFactory.getInstance().fromUrl(url);
String tableHtml = tableInferService.getTableHtml(image);
// 创建一个Excel文件
tableHtml = tableHtml.replace("<html><body>", "");
tableHtml = tableHtml.replace("</body></html>", "");
HSSFWorkbook workbook = ConvertHtml2Excel.table2Excel(tableHtml);
FileProperties.ElPath path = properties.getPath();
String fileRelativePath = path.getPath().replace("\\", "/") + "tables/";
//Check & create file path
Path filePath = Paths.get(fileRelativePath);
File file = filePath.toFile();
if (!file.exists() && !file.isDirectory()) {
file.mkdir();
}
String fileId = UUIDUtils.getUUID();
workbook.write(new File(fileRelativePath + fileId + ".xls"));
try (OutputStreamWriter out = new OutputStreamWriter(
new FileOutputStream(fileRelativePath + fileId + ".html"), "UTF-8")) {
out.write(tableHtml);
}
String excelUri = baseUri + File.separator + fileRelativePath + fileId + ".xls";
String htmlUri = baseUri + File.separator + fileRelativePath + fileId + ".html";
Map<String, String> map = new ConcurrentHashMap<>();
map.put("excelUri", excelUri);
map.put("htmlUri", htmlUri);
map.put("html", tableHtml);
return ResultBean.success().add("result", map);
} catch (Exception e) {
logger.error(e.getMessage());
e.printStackTrace();
return ResultBean.failure().add("errors", e.getMessage());
}
}
@ApiOperation(value = "单表格文字识别-图片")
@PostMapping("/tableInfoForImageFile")
public ResultBean tableInfoForImageFile(@RequestParam(value = "imageFile") MultipartFile imageFile) {
try (InputStream inputStream = imageFile.getInputStream()) {
String base64Img = Base64.encodeBase64String(imageFile.getBytes());
Image image = ImageFactory.getInstance().fromInputStream(inputStream);
String tableHtml = tableInferService.getTableHtml(image);
// 创建一个Excel文件
tableHtml = tableHtml.replace("<html><body>", "");
tableHtml = tableHtml.replace("</body></html>", "");
HSSFWorkbook workbook = ConvertHtml2Excel.table2Excel(tableHtml);
FileProperties.ElPath path = properties.getPath();
String fileRelativePath = path.getPath().replace("\\", "/") + "tables/";
//Check & create file path
Path filePath = Paths.get(fileRelativePath);
File file = filePath.toFile();
if (!file.exists() && !file.isDirectory()) {
file.mkdir();
}
String fileId = UUIDUtils.getUUID();
workbook.write(new File(fileRelativePath + fileId + ".xls"));
try (OutputStreamWriter out = new OutputStreamWriter(
new FileOutputStream(fileRelativePath + fileId + ".html"), "UTF-8")) {
out.write(tableHtml);
}
String excelUri = baseUri + File.separator + fileRelativePath + fileId + ".xls";
String htmlUri = baseUri + File.separator + fileRelativePath + fileId + ".html";
Map<String, String> map = new ConcurrentHashMap<>();
map.put("excelUri", excelUri);
map.put("htmlUri", htmlUri);
map.put("html", tableHtml);
return ResultBean.success().add("result", map)
.add("base64Img", "data:imageName/jpeg;base64," + base64Img);
} catch (Exception e) {
logger.error(e.getMessage());
e.printStackTrace();
return ResultBean.failure().add("errors", e.getMessage());
}
}
@ApiOperation(value = "表单表格自动检测文字识别-URL")
@GetMapping(value = "/autoTableInfoForImageUrl")
public ResultBean autoTableInfoForImageUrl(@RequestParam(value = "url") String url) {
try {
Image image = ImageFactory.getInstance().fromUrl(url);
List<String> tableHtmlList = tableInferService.getTableHtmlList(image);
List<HSSFWorkbook> workbookList = new ArrayList<>();
for (String tableHtml : tableHtmlList) {
tableHtml = tableHtml.replace("<html><body>", "");
tableHtml = tableHtml.replace("</body></html>", "");
// Create workbook for each table
HSSFWorkbook workbook = ConvertHtml2Excel.table2Excel(tableHtml);
workbookList.add(workbook);
}
FileProperties.ElPath path = properties.getPath();
String fileRelativePath = path.getPath().replace("\\", "/") + "tables/";
//Check & create file path
Path filePath = Paths.get(fileRelativePath);
File file = filePath.toFile();
if (!file.exists() && !file.isDirectory()) {
file.mkdir();
}
List<Map<String, String>> uriList = new ArrayList<>();
for (int i = 0; i < tableHtmlList.size(); i++) {
String fileId = UUIDUtils.getUUID();
HSSFWorkbook workbook = workbookList.get(i);
workbook.write(new File(fileRelativePath + fileId + ".xls"));
String tableHtml = tableHtmlList.get(i);
try (OutputStreamWriter out = new OutputStreamWriter(
new FileOutputStream(fileRelativePath + fileId + ".html"), "UTF-8")) {
out.write(tableHtml);
}
String excelUri = baseUri + File.separator + fileRelativePath + fileId + ".xls";
String htmlUri = baseUri + File.separator + fileRelativePath + fileId + ".html";
Map<String, String> map = new ConcurrentHashMap<>();
map.put("excelUri", excelUri);
map.put("htmlUri", htmlUri);
map.put("html", tableHtml);
uriList.add(map);
}
return ResultBean.success().add("result", uriList);
} catch (Exception e) {
logger.error(e.getMessage());
e.printStackTrace();
return ResultBean.failure().add("errors", e.getMessage());
}
}
@ApiOperation(value = "表单表格自动检测文字识别-URL")
@PostMapping("/autoTableInfoForImageFile")
public ResultBean autoTableInfoForImageFile(@RequestParam(value = "imageFile") MultipartFile imageFile) {
try (InputStream inputStream = imageFile.getInputStream()) {
String base64Img = Base64.encodeBase64String(imageFile.getBytes());
Image image = ImageFactory.getInstance().fromInputStream(inputStream);
List<String> tableHtmlList = tableInferService.getTableHtmlList(image);
List<HSSFWorkbook> workbookList = new ArrayList<>();
for (String tableHtml : tableHtmlList) {
tableHtml = tableHtml.replace("<html><body>", "");
tableHtml = tableHtml.replace("</body></html>", "");
// Create workbook for each table
HSSFWorkbook workbook = ConvertHtml2Excel.table2Excel(tableHtml);
workbookList.add(workbook);
}
FileProperties.ElPath path = properties.getPath();
String fileRelativePath = path.getPath().replace("\\", "/") + "tables/";
//Check & create file path
Path filePath = Paths.get(fileRelativePath);
File file = filePath.toFile();
if (!file.exists() && !file.isDirectory()) {
file.mkdir();
}
List<Map<String, String>> uriList = new ArrayList<>();
for (int i = 0; i < tableHtmlList.size(); i++) {
String fileId = UUIDUtils.getUUID();
HSSFWorkbook workbook = workbookList.get(i);
workbook.write(new File(fileRelativePath + fileId + ".xls"));
String tableHtml = tableHtmlList.get(i);
try (OutputStreamWriter out = new OutputStreamWriter(
new FileOutputStream(fileRelativePath + fileId + ".html"), "UTF-8")) {
out.write(tableHtml);
}
String excelUri = baseUri + File.separator + fileRelativePath + fileId + ".xls";
String htmlUri = baseUri + File.separator + fileRelativePath + fileId + ".html";
Map<String, String> map = new ConcurrentHashMap<>();
map.put("excelUri", excelUri);
map.put("htmlUri", htmlUri);
map.put("html", tableHtml);
uriList.add(map);
}
return ResultBean.success().add("result", uriList).add("base64Img", "data:imageName/jpeg;base64," + base64Img);
} catch (Exception e) {
logger.error(e.getMessage());
e.printStackTrace();
return ResultBean.failure().add("errors", e.getMessage());
}
}
}

View File

@ -0,0 +1,181 @@
package me.aias.ocr.controller;
import ai.djl.modality.cv.Image;
import ai.djl.modality.cv.ImageFactory;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import me.aias.ocr.configuration.FileProperties;
import me.aias.ocr.model.LabelDTO;
import me.aias.ocr.model.ResultBean;
import me.aias.ocr.model.TemplateBean;
import me.aias.ocr.service.TemplateService;
import me.aias.ocr.utils.FileUtils;
import me.aias.ocr.utils.UUIDUtils;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
import java.util.Map;
/**
* @author Calvin
* @date Oct 19, 2021
*/
@Api(tags = "自定义模版文字识别")
@RestController
@Configuration
@RequestMapping("/template")
public class TemplateController {
private Logger logger = LoggerFactory.getLogger(TemplateController.class);
@Autowired
private TemplateService ocrTemplateService;
@Value("${server.baseUri}")
private String baseUri;
/**
* 文件配置
*/
@Autowired
private FileProperties properties;
@ApiOperation(value = "获取模版")
@GetMapping(value = "/getTemplate", produces = "application/json;charset=utf-8")
public ResultBean getTemplate(@RequestParam(value = "uid") String uid) {
try {
TemplateBean templateBean = ocrTemplateService.getTemplate(uid);
return ResultBean.success().add("result", templateBean);
} catch (Exception e) {
logger.error(e.getMessage());
return ResultBean.failure().add("errors", e.getMessage());
}
}
@ApiOperation(value = "获取模版列表")
@GetMapping(value = "/getTemplates", produces = "application/json;charset=utf-8")
public ResultBean getTemplatesList() {
try {
return ResultBean.success().add("result", ocrTemplateService.getTemplateList());
} catch (Exception e) {
logger.error(e.getMessage());
return ResultBean.failure().add("errors", e.getMessage());
}
}
@ApiOperation(value = "更新模板信息")
@PostMapping(value = "/updateTemplate", consumes = "application/json;charset=utf-8")
public ResultBean updateTemplate(@RequestBody TemplateBean templateBean) {
try {
ocrTemplateService.updateTemplate(templateBean);
return ResultBean.success();
} catch (Exception e) {
logger.error(e.getMessage());
return ResultBean.failure().add("errors", e.getMessage());
}
}
@ApiOperation(value = "删除模板")
@PostMapping(value = "/removeTemplate", produces = "application/json;charset=utf-8")
public ResultBean removeTemplate(@RequestParam(value = "uid") String uid) {
try {
ocrTemplateService.removeTemplate(uid);
return ResultBean.success();
} catch (Exception e) {
logger.error(e.getMessage());
return ResultBean.failure().add("errors", e.getMessage());
}
}
@ApiOperation(value = "识别标注字段")
@PostMapping(value = "/getLabelData", produces = "application/json;charset=utf-8")
public ResultBean getLabelData(@RequestBody LabelDTO labelDTO) {
try {
String result = ocrTemplateService.getLabelData(labelDTO.getUid(), labelDTO.getLabelData());
logger.info("LabelData: " + result);
return ResultBean.success().add("result", result);
} catch (Exception e) {
logger.error(e.getMessage());
e.printStackTrace();
return ResultBean.failure().add("errors", e.getMessage());
}
}
@ApiOperation(value = "创建模板")
@PostMapping(value = "/addTemplate")
public ResultBean addTemplate(@RequestParam(value = "name") String name, @RequestParam(value = "imageFile") MultipartFile imageFile) {
try {
// 要上传的目标文件存放路径
FileProperties.ElPath path = properties.getPath();
String imagePath = path.getPath().replace("\\", "/") + "images/";
FileUtils.checkAndCreatePath(imagePath);
String templatePath = path.getPath().replace("\\", "/") + "templates/";
FileUtils.checkAndCreatePath(templatePath);
TemplateBean templateBean = new TemplateBean();
String uid = UUIDUtils.getUUID();
templateBean.setUid(uid);
//image/jpg' || 'image/jpeg' || 'image/png'
String suffix = FileUtils.getSuffix(imageFile.getOriginalFilename());
if (!suffix.equalsIgnoreCase(".jpg") && !suffix.equalsIgnoreCase(".jpeg") && !suffix.equalsIgnoreCase(".png")) {
return ResultBean.failure().add("errors", "Image format should be JPG(JPEG) or PNG!");
}
String imageName = FileUtils.getFileName(imageFile.getOriginalFilename());
templateBean.setImageName(imageName);
templateBean.setName(name);
logger.info("Template name:" + name);
// String imageUri = baseUri + File.separator + fileRelativePath + fileName;
if (FileUtils.upload(imageFile, imagePath, imageName)) {
ocrTemplateService.addTemplate(templateBean);
return ResultBean.success().add("result", templateBean);
} else {
return ResultBean.failure();
}
} catch (Exception e) {
logger.error(e.getMessage());
e.printStackTrace();
return ResultBean.failure().add("errors", e.getMessage());
}
}
@ApiOperation(value = "模版文字识别-URL")
@GetMapping(value = "/infoForImageUrl", produces = "application/json;charset=utf-8")
public ResultBean infoForImageUrl(@RequestParam(value = "uid") String uid, @RequestParam(value = "url") String url) {
try {
Image image = ImageFactory.getInstance().fromUrl(url);
TemplateBean templateBean = ocrTemplateService.getTemplate(uid);
Map<String, String> hashMap = ocrTemplateService.getImageInfo(templateBean, image);
return ResultBean.success().add("result", hashMap);
} catch (Exception e) {
logger.error(e.getMessage());
e.printStackTrace();
return ResultBean.failure().add("errors", e.getMessage());
}
}
@ApiOperation(value = "模版文字识别-图片")
@PostMapping(value = "/infoForImageFile", produces = "application/json;charset=utf-8")
public ResultBean infoForImageFile(@RequestParam(value = "uid") String uid, @RequestParam(value = "imageFile") MultipartFile imageFile) {
try (InputStream inputStream = imageFile.getInputStream()) {
String base64Img = Base64.encodeBase64String(imageFile.getBytes());
TemplateBean templateBean = ocrTemplateService.getTemplate(uid);
Image image = ImageFactory.getInstance().fromInputStream(inputStream);
Map<String, String> hashMap = ocrTemplateService.getImageInfo(templateBean, image);
return ResultBean.success().add("result", hashMap)
.add("base64Img", "data:imageName/jpeg;base64," + base64Img);
} catch (Exception e) {
logger.error(e.getMessage());
e.printStackTrace();
return ResultBean.failure().add("errors", e.getMessage());
}
}
}

View File

@ -0,0 +1,57 @@
package me.aias.ocr.inference;
import ai.djl.Device;
import ai.djl.MalformedModelException;
import ai.djl.inference.Predictor;
import ai.djl.modality.cv.Image;
import ai.djl.modality.cv.output.DetectedObjects;
import ai.djl.repository.zoo.Criteria;
import ai.djl.repository.zoo.ModelNotFoundException;
import ai.djl.repository.zoo.ModelZoo;
import ai.djl.repository.zoo.ZooModel;
import ai.djl.training.util.ProgressBar;
import ai.djl.translate.TranslateException;
import me.aias.ocr.model.TableResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author Calvin
* @date Oct 20, 2021
*/
public final class LayoutDetectionModel {
private ZooModel<Image, DetectedObjects> model;
private Predictor<Image, DetectedObjects> predictor;
public void init(String layoutUri) throws MalformedModelException, ModelNotFoundException, IOException {
this.model = ModelZoo.loadModel(detectCriteria(layoutUri));
this.predictor = model.newPredictor();
}
public void close() {
this.model.close();
this.predictor.close();
}
public DetectedObjects predict(Image image) throws TranslateException {
return predictor.predict(image);
}
private Criteria<Image, DetectedObjects> detectCriteria(String layoutUri) {
Criteria<Image, DetectedObjects> criteria =
Criteria.builder()
.optEngine("PaddlePaddle")
.setTypes(Image.class, DetectedObjects.class)
.optModelUrls(layoutUri)
// .optDevice(Device.cpu())
.optTranslator(new LayoutDetectionTranslator())
.optProgress(new ProgressBar())
.build();
return criteria;
}
}

View File

@ -0,0 +1,104 @@
package me.aias.ocr.inference;
import ai.djl.modality.cv.Image;
import ai.djl.modality.cv.output.BoundingBox;
import ai.djl.modality.cv.output.DetectedObjects;
import ai.djl.modality.cv.output.Rectangle;
import ai.djl.modality.cv.util.NDImageUtils;
import ai.djl.ndarray.NDArray;
import ai.djl.ndarray.NDList;
import ai.djl.ndarray.types.DataType;
import ai.djl.translate.Batchifier;
import ai.djl.translate.Translator;
import ai.djl.translate.TranslatorContext;
import java.util.ArrayList;
import java.util.List;
public class LayoutDetectionTranslator implements Translator<Image, DetectedObjects> {
private int width;
private int height;
public LayoutDetectionTranslator() {}
@Override
public DetectedObjects processOutput(TranslatorContext ctx, NDList list) {
NDArray result = list.get(0); // np_boxes
long rows = result.size(0);
List<BoundingBox> boxes = new ArrayList<>();
List<String> names = new ArrayList<>();
List<Double> probs = new ArrayList<>();
for (long i = 0; i < rows; i++) {
NDArray row = result.get(i);
float[] array = row.toFloatArray();
if (array[1] <= 0.5 || array[0] <= -1) continue;
int clsid = (int) array[0];
double score = array[1];
String name = "";
switch (clsid) {
case 0:
name = "Text";
break;
case 1:
name = "Title";
break;
case 2:
name = "List";
break;
case 3:
name = "Table";
break;
case 4:
name = "Figure";
break;
default:
name = "Unknown";
}
float x = array[2] / width;
float y = array[3] / height;
float w = (array[4] - array[2]) / width;
float h = (array[5] - array[3]) / height;
Rectangle rect = new Rectangle(x, y, w, h);
boxes.add(rect);
names.add(name);
probs.add(score);
}
return new DetectedObjects(names, probs, boxes);
}
@Override
public NDList processInput(TranslatorContext ctx, Image input) {
NDArray img = input.toNDArray(ctx.getNDManager());
width = input.getWidth();
height = input.getHeight();
img = NDImageUtils.resize(img, 640, 640);
img = img.transpose(2, 0, 1).div(255);
img =
NDImageUtils.normalize(
img, new float[] {0.485f, 0.456f, 0.406f}, new float[] {0.229f, 0.224f, 0.225f});
img = img.expandDims(0);
NDArray scale_factor = ctx.getNDManager().create(new float[] {640f / height, 640f / width});
scale_factor = scale_factor.toType(DataType.FLOAT32, false);
scale_factor = scale_factor.expandDims(0);
NDArray im_shape = ctx.getNDManager().create(new float[] {640f, 640f});
im_shape = im_shape.toType(DataType.FLOAT32, false);
im_shape = im_shape.expandDims(0);
// im_shape, imageName, scale_factor
return new NDList(im_shape, img, scale_factor);
}
@Override
public Batchifier getBatchifier() {
return null;
}
}

View File

@ -0,0 +1,170 @@
package me.aias.ocr.inference;
import ai.djl.modality.cv.Image;
import ai.djl.modality.cv.output.DetectedObjects;
import ai.djl.modality.cv.output.Rectangle;
import ai.djl.ndarray.NDManager;
import ai.djl.translate.TranslateException;
import me.aias.ocr.model.LabelBean;
import me.aias.ocr.utils.*;
import org.bytedeco.javacv.Java2DFrameUtils;
import org.bytedeco.opencv.global.opencv_imgproc;
import org.bytedeco.opencv.opencv_core.Mat;
import org.bytedeco.opencv.opencv_core.Point2f;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author Calvin
* @date Oct 19, 2021
*/
public class PerspectiveRecogition {
public static Map<String, String> recognize(NDManager manager, BufferedImage templateImg, RecognitionModel recognitionModel, Image image, List<LabelBean> anchorlabels, List<LabelBean> contentLabels, String fileRelativePath, String distance, boolean save) throws TranslateException {
// 锚点识别区 - 计算中心点坐标用于透视变换
for (int i = 0; i < anchorlabels.size(); i++) {
List<me.aias.ocr.model.Point> points = anchorlabels.get(i).getPoints();
anchorlabels.get(i).setCenterPoint(PointUtils.getCenterPoint(points));
}
// 文本检测区
List<LabelBean> detectedTexts = new ArrayList<>();
DetectedObjects textDetections = recognitionModel.predict(image);
List<DetectedObjects.DetectedObject> dt_boxes = textDetections.items();
for (DetectedObjects.DetectedObject item : dt_boxes) {
LabelBean labelBean = new LabelBean();
List<me.aias.ocr.model.Point> points = new ArrayList<>();
labelBean.setValue(item.getClassName());
Rectangle rectangle = item.getBoundingBox().getBounds();
Iterable<ai.djl.modality.cv.output.Point> pathIterator = rectangle.getPath();
for (Iterator iter = pathIterator.iterator(); iter.hasNext(); ) {
me.aias.ocr.model.Point point = new me.aias.ocr.model.Point();
ai.djl.modality.cv.output.Point djlPoint = (ai.djl.modality.cv.output.Point) iter.next();
point.setX((int) (djlPoint.getX() * image.getWidth()));
point.setY((int) (djlPoint.getY() * image.getHeight()));
points.add(point);
}
labelBean.setPoints(points);
labelBean.setCenterPoint(PointUtils.getCenterPoint(points));
detectedTexts.add(labelBean);
}
List<ai.djl.modality.cv.output.Point> srcPoints = new ArrayList<>();
List<ai.djl.modality.cv.output.Point> dstPoints = new ArrayList<>();
for (int i = 0; i < anchorlabels.size(); i++) {
String anchorText = anchorlabels.get(i).getValue();
for (int j = 0; j < detectedTexts.size(); j++) {
String detectedText = detectedTexts.get(j).getValue();
if (detectedText.equals(anchorText)) {
double x = anchorlabels.get(i).getCenterPoint().getX();
double y = anchorlabels.get(i).getCenterPoint().getY();
ai.djl.modality.cv.output.Point point = new ai.djl.modality.cv.output.Point(x, y);
srcPoints.add(point);
x = detectedTexts.get(j).getCenterPoint().getX();
y = detectedTexts.get(j).getCenterPoint().getY();
point = new ai.djl.modality.cv.output.Point(x, y);
dstPoints.add(point);
}
}
}
Point2f srcPoint2f = null;
Point2f dstPoint2f = null;
Mat warp_mat = null;
if (dstPoints.size() == 3) {
srcPoint2f = NDArrayUtils.toOpenCVPoint2f(srcPoints, 3);
dstPoint2f = NDArrayUtils.toOpenCVPoint2f(dstPoints, 3);
//3点仿射变换
warp_mat = opencv_imgproc.getAffineTransform(srcPoint2f.position(0), dstPoint2f.position(0));
} else if (dstPoints.size() >= 4) {
srcPoint2f = NDArrayUtils.toOpenCVPoint2f(srcPoints, 4);
dstPoint2f = NDArrayUtils.toOpenCVPoint2f(dstPoints, 4);
//4点透视变换
warp_mat = opencv_imgproc.getPerspectiveTransform(srcPoint2f.position(0), dstPoint2f.position(0));
}
if (dstPoints.size() >= 3 && save) {
// 模板图片透视变换跟上传图片对齐
Mat mat = Java2DFrameUtils.toMat(templateImg);
if (dstPoints.size() == 3) { //3点仿射变换
mat = OpenCVUtils.affineTransform(mat, srcPoint2f, dstPoint2f);
templateImg = Java2DFrameUtils.toBufferedImage(mat);
DJLImageUtils.saveImage(templateImg, "affineTransform.png", fileRelativePath);
} else if (dstPoints.size() >= 4) { //4点透视变换
mat = OpenCVUtils.perspectiveTransform(mat, srcPoint2f, dstPoint2f);
templateImg = Java2DFrameUtils.toBufferedImage(mat);
DJLImageUtils.saveImage(templateImg, "perspectiveTransform.png", fileRelativePath);
}
}
// 内容识别区 - 计算中心点坐标用于距离计算
for (int i = 0; i < contentLabels.size(); i++) {
List<me.aias.ocr.model.Point> points = contentLabels.get(i).getPoints();
//根据变换矩阵对所有点坐标进行坐标变换
if (dstPoints.size() >= 3) {
points = PointUtils.transformPoints(manager, warp_mat, points);
}
ai.djl.modality.cv.output.Point point = PointUtils.getCenterPoint(points);
if (dstPoints.size() < 3) { //无坐标变换则将坐标归一化坐标变为占整张图片的百分比
double x = point.getX() / templateImg.getHeight();
double y = point.getY() / templateImg.getWidth();
ai.djl.modality.cv.output.Point djlPoint = new ai.djl.modality.cv.output.Point(x, y);
contentLabels.get(i).setCenterPoint(djlPoint);
} else {
contentLabels.get(i).setCenterPoint(point);
}
if (save) {
Color c = new Color(0, 255, 0);
DJLImageUtils.drawImageRect((BufferedImage) image.getWrappedImage(), (int) point.getX(), (int) point.getY(), 4, 4, c);
}
}
// 文本检测区 - 中心点坐标根据透视变换矩阵进行坐标变换
for (int i = 0; i < detectedTexts.size(); i++) {
List<me.aias.ocr.model.Point> points = detectedTexts.get(i).getPoints();
ai.djl.modality.cv.output.Point point = PointUtils.getCenterPoint(points);
if (dstPoints.size() < 3) { //无坐标变换则将坐标归一化坐标变为占整张图片的百分比
double x = point.getX() / image.getHeight();
double y = point.getY() / image.getWidth();
ai.djl.modality.cv.output.Point djlPoint = new ai.djl.modality.cv.output.Point(x, y);
detectedTexts.get(i).setCenterPoint(djlPoint);
} else {
detectedTexts.get(i).setCenterPoint(point);
}
if (save) {
DJLImageUtils.drawImageRect((BufferedImage) image.getWrappedImage(), (int) point.getX(), (int) point.getY(), 4, 4);
}
}
Map<String, String> hashMap = new ConcurrentHashMap<>();
if (distance.equalsIgnoreCase("IOU")) {
hashMap = DistanceUtils.iou(contentLabels, detectedTexts);
} else {
hashMap = DistanceUtils.l2Distance(contentLabels, detectedTexts);
}
if (save) {
// 保存图
DJLImageUtils.saveImage((BufferedImage) image.getWrappedImage(), "points_result.png", fileRelativePath);
}
return hashMap;
}
}

View File

@ -0,0 +1,80 @@
package me.aias.ocr.inference;
import ai.djl.Model;
import ai.djl.modality.cv.Image;
import ai.djl.modality.cv.util.NDImageUtils;
import ai.djl.ndarray.NDArray;
import ai.djl.ndarray.NDList;
import ai.djl.translate.Batchifier;
import ai.djl.translate.Translator;
import ai.djl.translate.TranslatorContext;
import ai.djl.util.Utils;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
/**
* @author Calvin
* @date Oct 19, 2021
*/
public class PpWordRecognitionTranslator implements Translator<Image, String> {
private List<String> table;
@Override
public void prepare(TranslatorContext ctx) throws IOException {
Model model = ctx.getModel();
// ppocr_keys_v1.txt
try (InputStream is = model.getArtifact("ppocr_keys_v1.txt").openStream()) {
table = Utils.readLines(is, true);
table.add(0, "blank");
table.add("");
}
}
@Override
public String processOutput(TranslatorContext ctx, NDList list) throws IOException {
StringBuilder sb = new StringBuilder();
NDArray tokens = list.singletonOrThrow();
long[] indices = tokens.get(0).argMax(1).toLongArray();
int lastIdx = 0;
for (int i = 0; i < indices.length; i++) {
if (indices[i] > 0 && !(i > 0 && indices[i] == lastIdx)) {
sb.append(table.get((int) indices[i]));
}
}
return sb.toString();
}
@Override
public NDList processInput(TranslatorContext ctx, Image input) {
NDArray img = input.toNDArray(ctx.getNDManager(), Image.Flag.COLOR);
// int[] hw = resize32(input.getHeight(), input.getWidth());
int h = input.getHeight();
int w = input.getWidth();
float ratio = (float) w / (float) h;
int resized_w = (int) (Math.ceil(32 * ratio));
// img = NDImageUtils.resize(img, hw[1], hw[0]);
img = NDImageUtils.resize(img, resized_w, 32);
img = NDImageUtils.toTensor(img).sub(0.5f).div(0.5f);
img = img.expandDims(0);
return new NDList(img);
}
@Override
public Batchifier getBatchifier() {
return null;
}
private int[] resize32(double h, double w) {
double h32Ratio = h / 32d;
double w32 = w / h32Ratio;
int w32Ratio = (int) Math.round(w32 / 32d);
return new int[]{32, w32Ratio * 32}; // height: 32 (fixed), width: 32 * N
}
}

View File

@ -0,0 +1,147 @@
package me.aias.ocr.inference;
import ai.djl.Device;
import ai.djl.MalformedModelException;
import ai.djl.ModelException;
import ai.djl.inference.Predictor;
import ai.djl.modality.cv.Image;
import ai.djl.modality.cv.ImageFactory;
import ai.djl.modality.cv.output.BoundingBox;
import ai.djl.modality.cv.output.DetectedObjects;
import ai.djl.modality.cv.output.Rectangle;
import ai.djl.modality.cv.util.NDImageUtils;
import ai.djl.ndarray.NDArray;
import ai.djl.ndarray.NDManager;
import ai.djl.paddlepaddle.zoo.cv.objectdetection.PpWordDetectionTranslator;
import ai.djl.repository.zoo.Criteria;
import ai.djl.repository.zoo.ModelNotFoundException;
import ai.djl.repository.zoo.ModelZoo;
import ai.djl.repository.zoo.ZooModel;
import ai.djl.training.util.ProgressBar;
import ai.djl.translate.TranslateException;
import me.aias.ocr.model.TableResult;
import org.springframework.beans.factory.annotation.Value;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author Calvin
* @date Oct 19, 2021
*/
public final class RecognitionModel {
private ZooModel<Image, DetectedObjects> detectionModel;
private ZooModel<Image, String> recognitionModel;
private Predictor<Image, String> recognizer;
private Predictor<Image, DetectedObjects> detector;
public void init(String detUri, String recUri) throws MalformedModelException, ModelNotFoundException, IOException {
this.detectionModel = ModelZoo.loadModel(detectCriteria(detUri));
this.recognitionModel = ModelZoo.loadModel(recognizeCriteria(recUri));
this.recognizer = recognitionModel.newPredictor();
this.detector = detectionModel.newPredictor();
}
public void close() {
this.detectionModel.close();
this.recognitionModel.close();
this.recognizer.close();
this.detector.close();
}
public String predictSingleLineText(Image image)
throws TranslateException {
String text = recognizer.predict(image);
return text;
}
public DetectedObjects predict(Image image)
throws TranslateException {
DetectedObjects detections = detector.predict(image);
List<DetectedObjects.DetectedObject> boxes = detections.items();
List<String> names = new ArrayList<>();
List<Double> prob = new ArrayList<>();
List<BoundingBox> rect = new ArrayList<>();
for (int i = 0; i < boxes.size(); i++) {
Image subImg = getSubImage(image, boxes.get(i).getBoundingBox());
if (subImg.getHeight() * 1.0 / subImg.getWidth() > 1.5) {
subImg = rotateImg(subImg);
}
String name = recognizer.predict(subImg);
System.out.println(name);
names.add(name);
prob.add(-1.0);
rect.add(boxes.get(i).getBoundingBox());
}
DetectedObjects detectedObjects = new DetectedObjects(names, prob, rect);
return detectedObjects;
}
private Criteria<Image, DetectedObjects> detectCriteria(String detUri) {
Criteria<Image, DetectedObjects> criteria =
Criteria.builder()
.optEngine("PaddlePaddle")
.setTypes(Image.class, DetectedObjects.class)
.optModelUrls(detUri)
// .optDevice(Device.cpu())
.optTranslator(new PpWordDetectionTranslator(new ConcurrentHashMap<String, String>()))
.optProgress(new ProgressBar())
.build();
return criteria;
}
private Criteria<Image, String> recognizeCriteria(String recUri) {
Criteria<Image, String> criteria =
Criteria.builder()
.optEngine("PaddlePaddle")
.setTypes(Image.class, String.class)
.optModelUrls(recUri)
// .optDevice(Device.cpu())
.optProgress(new ProgressBar())
.optTranslator(new PpWordRecognitionTranslator())
.build();
return criteria;
}
private Image getSubImage(Image img, BoundingBox box) {
Rectangle rect = box.getBounds();
double[] extended = extendRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
int width = img.getWidth();
int height = img.getHeight();
int[] recovered = {
(int) (extended[0] * width),
(int) (extended[1] * height),
(int) (extended[2] * width),
(int) (extended[3] * height)
};
return img.getSubImage(recovered[0], recovered[1], recovered[2], recovered[3]);
}
private double[] extendRect(double xmin, double ymin, double width, double height) {
double centerx = xmin + width / 2;
double centery = ymin + height / 2;
if (width > height) {
width += height * 2.0;
height *= 3.0;
} else {
height += width * 2.0;
width *= 3.0;
}
double newX = centerx - width / 2 < 0 ? 0 : centerx - width / 2;
double newY = centery - height / 2 < 0 ? 0 : centery - height / 2;
double newWidth = newX + width > 1 ? 1 - newX : width;
double newHeight = newY + height > 1 ? 1 - newY : height;
return new double[]{newX, newY, newWidth, newHeight};
}
private Image rotateImg(Image image) {
try (NDManager manager = NDManager.newBaseManager()) {
NDArray rotated = NDImageUtils.rotate90(image.toNDArray(manager), 1);
return ImageFactory.getInstance().fromNDArray(rotated);
}
}
}

View File

@ -0,0 +1,249 @@
package me.aias.ocr.inference;
import ai.djl.Device;
import ai.djl.MalformedModelException;
import ai.djl.inference.Predictor;
import ai.djl.modality.cv.Image;
import ai.djl.modality.cv.output.BoundingBox;
import ai.djl.modality.cv.output.DetectedObjects;
import ai.djl.modality.cv.output.Rectangle;
import ai.djl.repository.zoo.Criteria;
import ai.djl.repository.zoo.ModelNotFoundException;
import ai.djl.repository.zoo.ModelZoo;
import ai.djl.repository.zoo.ZooModel;
import ai.djl.training.util.ProgressBar;
import ai.djl.translate.TranslateException;
import me.aias.ocr.model.TableResult;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author Calvin
* @date Oct 19, 2021
*/
public final class TableDetectionModel {
private ZooModel<Image, TableResult> model;
private Predictor<Image, TableResult> predictor;
public void init(String tableUri) throws MalformedModelException, ModelNotFoundException, IOException {
this.model = ModelZoo.loadModel(detectCriteria(tableUri));
this.predictor = model.newPredictor();
}
public void close() {
this.model.close();
this.predictor.close();
}
public String getTableHtml(Image image, DetectedObjects textDetections) throws TranslateException {
// Table cell detection
TableResult tableResult = predictor.predict(image);
List<BoundingBox> cells = tableResult.getBoxes();
List<DetectedObjects.DetectedObject> dt_boxes = textDetections.items();
// 获取 Cell 文本检测框 的对应关系(1:N)
Map<Integer, List<Integer>> matched = new ConcurrentHashMap<>();
for (int i = 0; i < dt_boxes.size(); i++) {
DetectedObjects.DetectedObject item = dt_boxes.get(i);
Rectangle textBounds = item.getBoundingBox().getBounds();
int[] box_1 = rectXYXY(textBounds, image.getWidth(), image.getHeight());
// 获取两两cell之间的L1距离和 1- IOU
List<Pair<Float, Float>> distances = new ArrayList<>();
for (BoundingBox cell : cells) {
Rectangle cellBounds = cell.getBounds();
int[] box_2 = rectXYXY(cellBounds, image.getWidth(), image.getHeight());
float distance = distance(box_1, box_2);
float iou = 1 - compute_iou(box_1, box_2);
distances.add(Pair.of(distance, iou));
}
// 根据距离和IOU挑选最""的cell
Pair<Float, Float> nearest = sorted(distances);
// 获取最小距离对应的下标id也等价于cell的下标id distances列表是根据遍历cells生成的
int id = 0;
for (int idx = 0; idx < distances.size(); idx++) {
Pair<Float, Float> current = distances.get(idx);
if (current.getLeft().floatValue() == nearest.getLeft().floatValue()
&& current.getRight().floatValue() == nearest.getRight().floatValue()) {
id = idx;
break;
}
}
if (!matched.containsKey(id)) {
List<Integer> textIds = new ArrayList<>();
textIds.add(i);
// cell id, text id list (dt_boxes index list)
matched.put(id, textIds);
} else {
matched.get(id).add(i);
}
}
List<String> cell_contents = new ArrayList<>();
List<Double> probs = new ArrayList<>();
for (int i = 0; i < cells.size(); i++) {
List<Integer> textIds = matched.get(i);
List<String> contents = new ArrayList<>();
String content = "";
if (textIds != null) {
for (Integer id : textIds) {
DetectedObjects.DetectedObject item = dt_boxes.get(id);
contents.add(item.getClassName());
}
content = StringUtils.join(contents, " ");
}
cell_contents.add(content);
probs.add(-1.0);
}
List<String> pred_structures = tableResult.getStructure_str_list();
return getPredHtml(pred_structures, cell_contents);
}
/**
* Generate table html
*
* @param pred_structures
* @param cell_contents
* @return
*/
private String getPredHtml(List<String> pred_structures, List<String> cell_contents) {
StringBuffer html = new StringBuffer();
int td_index = 0;
for (String tag : pred_structures) {
if (tag.contains("</td>")) {
String content = cell_contents.get(td_index);
html.append(content);
td_index++;
}
html.append(tag);
}
return html.toString();
}
private Criteria<Image, TableResult> detectCriteria(String tableUri) {
Criteria<Image, TableResult> criteria =
Criteria.builder()
.optEngine("PaddlePaddle")
.setTypes(Image.class, TableResult.class)
.optModelUrls(tableUri)
// .optDevice(Device.cpu())
.optOption("removePass", "repeated_fc_relu_fuse_pass")
.optTranslator(new TableStructTranslator(new ConcurrentHashMap<String, String>()))
.optProgress(new ProgressBar())
.build();
return criteria;
}
/**
* Calculate L1 distance
*
* @param box_1
* @param box_2
* @return
*/
private int distance(int[] box_1, int[] box_2) {
int x1 = box_1[0];
int y1 = box_1[1];
int x2 = box_1[2];
int y2 = box_1[3];
int x3 = box_2[0];
int y3 = box_2[1];
int x4 = box_2[2];
int y4 = box_2[3];
int dis = Math.abs(x3 - x1) + Math.abs(y3 - y1) + Math.abs(x4 - x2) + Math.abs(y4 - y2);
int dis_2 = Math.abs(x3 - x1) + Math.abs(y3 - y1);
int dis_3 = Math.abs(x4 - x2) + Math.abs(y4 - y2);
return dis + Math.min(dis_2, dis_3);
}
/**
* Get absolute coordinations
*
* @param rect
* @param width
* @param height
* @return
*/
private int[] rectXYXY(Rectangle rect, int width, int height) {
int left = Math.max((int) (width * rect.getX()), 0);
int top = Math.max((int) (height * rect.getY()), 0);
int right = Math.min((int) (width * (rect.getX() + rect.getWidth())), width - 1);
int bottom = Math.min((int) (height * (rect.getY() + rect.getHeight())), height - 1);
return new int[]{left, top, right, bottom};
}
/**
* computing IoU
*
* @param rec1: (y0, x0, y1, x1), which reflects (top, left, bottom, right)
* @param rec2: (y0, x0, y1, x1)
* @return scala value of IoU
*/
private float compute_iou(int[] rec1, int[] rec2) {
// computing area of each rectangles
int S_rec1 = (rec1[2] - rec1[0]) * (rec1[3] - rec1[1]);
int S_rec2 = (rec2[2] - rec2[0]) * (rec2[3] - rec2[1]);
// computing the sum_area
int sum_area = S_rec1 + S_rec2;
// find the each edge of intersect rectangle
int left_line = Math.max(rec1[1], rec2[1]);
int right_line = Math.min(rec1[3], rec2[3]);
int top_line = Math.max(rec1[0], rec2[0]);
int bottom_line = Math.min(rec1[2], rec2[2]);
// judge if there is an intersect
if (left_line >= right_line || top_line >= bottom_line) {
return 0.0f;
} else {
float intersect = (right_line - left_line) * (bottom_line - top_line);
return (intersect / (sum_area - intersect)) * 1.0f;
}
}
/**
* Distance sorted
*
* @param distances
* @return
*/
private Pair<Float, Float> sorted(List<Pair<Float, Float>> distances) {
Comparator<Pair<Float, Float>> comparator =
new Comparator<Pair<Float, Float>>() {
@Override
public int compare(Pair<Float, Float> a1, Pair<Float, Float> a2) {
// order by IoU first
if (a1.getRight().floatValue() > a2.getRight().floatValue()) {
return 1;
} else if (a1.getRight().floatValue() == a2.getRight().floatValue()) {
// Then order by L1 distance
if (a1.getLeft().floatValue() > a2.getLeft().floatValue()) {
return 1;
}
return -1;
}
return -1;
}
};
// Sort distances
List<Pair<Float, Float>> newDistances = new ArrayList<>();
CollectionUtils.addAll(newDistances, new Object[distances.size()]);
Collections.copy(newDistances, distances);
Collections.sort(newDistances, comparator);
return newDistances.get(0);
}
}

View File

@ -0,0 +1,247 @@
package me.aias.ocr.inference;
import ai.djl.Model;
import ai.djl.modality.cv.Image;
import ai.djl.modality.cv.ImageFactory;
import ai.djl.modality.cv.output.BoundingBox;
import ai.djl.modality.cv.output.Rectangle;
import ai.djl.modality.cv.util.NDImageUtils;
import ai.djl.ndarray.NDArray;
import ai.djl.ndarray.NDArrays;
import ai.djl.ndarray.NDList;
import ai.djl.ndarray.index.NDIndex;
import ai.djl.ndarray.types.DataType;
import ai.djl.ndarray.types.Shape;
import ai.djl.translate.Batchifier;
import ai.djl.translate.Translator;
import ai.djl.translate.TranslatorContext;
import ai.djl.util.Utils;
import me.aias.ocr.model.TableResult;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class TableStructTranslator implements Translator<Image, TableResult> {
private final int maxLength;
private int height;
private int width;
private float xScale = 1.0f;
private float yScale = 1.0f;
public TableStructTranslator(Map<String, ?> arguments) {
maxLength =
arguments.containsKey("maxLength")
? Integer.parseInt(arguments.get("maxLength").toString())
: 488;
}
private Map<String, String> dict_idx_character = new ConcurrentHashMap<>();
private Map<String, String> dict_character_idx = new ConcurrentHashMap<>();
private Map<String, String> dict_idx_elem = new ConcurrentHashMap<>();
private Map<String, String> dict_elem_idx = new ConcurrentHashMap<>();
private String beg_str = "sos";
private String end_str = "eos";
@Override
public void prepare(TranslatorContext ctx) throws IOException {
Model model = ctx.getModel();
// ppocr_keys_v1.txt
try (InputStream is = model.getArtifact("table_structure_dict.txt").openStream()) {
List<String> lines = Utils.readLines(is, false);
String[] substr = lines.get(0).trim().split("\\t");
int characterNum = Integer.parseInt(substr[0]);
int elemNum = Integer.parseInt(substr[1]);
List<String> listCharacter = new ArrayList<>();
List<String> listElem = new ArrayList<>();
for (int i = 1; i < 1 + characterNum; i++) {
listCharacter.add(lines.get(i).trim());
}
for (int i = 1 + characterNum; i < 1 + characterNum + elemNum; i++) {
listElem.add(lines.get(i).trim());
}
listCharacter.add(0, beg_str);
listCharacter.add(end_str);
listElem.add(0, beg_str);
listElem.add(end_str);
for (int i = 0; i < listCharacter.size(); i++) {
dict_idx_character.put("" + i, listCharacter.get(i));
dict_character_idx.put(listCharacter.get(i), "" + i);
}
for (int i = 0; i < listElem.size(); i++) {
dict_idx_elem.put("" + i, listElem.get(i));
dict_elem_idx.put(listElem.get(i), "" + i);
}
}
}
@Override
public NDList processInput(TranslatorContext ctx, Image input) {
NDArray img = input.toNDArray(ctx.getNDManager(), Image.Flag.COLOR);
height = input.getHeight();
width = input.getWidth();
// img = ResizeTableImage(img, height, width, maxLength);
// img = PaddingTableImage(ctx, img, maxLength);
img = NDImageUtils.resize(img, 488, 488);
// img = NDImageUtils.toTensor(img);
img = img.transpose(2, 0, 1).div(255).flip(0);
img =
NDImageUtils.normalize(
img, new float[] {0.485f, 0.456f, 0.406f}, new float[] {0.229f, 0.224f, 0.225f});
img = img.expandDims(0);
return new NDList(img);
}
@Override
public TableResult processOutput(TranslatorContext ctx, NDList list) {
NDArray locPreds = list.get(0);
NDArray structureProbs = list.get(1);
NDArray structure_idx = structureProbs.argMax(2);
NDArray structure_probs = structureProbs.max(new int[] {2});
List<List<String>> result_list = new ArrayList<>();
List<List<String>> result_pos_list = new ArrayList<>();
List<List<String>> result_score_list = new ArrayList<>();
List<List<String>> result_elem_idx_list = new ArrayList<>();
List<String> res_html_code_list = new ArrayList<>();
List<NDArray> res_loc_list = new ArrayList<>();
// get ignored tokens
int beg_idx = Integer.parseInt(dict_elem_idx.get(beg_str));
int end_idx = Integer.parseInt(dict_elem_idx.get(end_str));
long batch_size = structure_idx.size(0); // len(text_index)
for (int batch_idx = 0; batch_idx < batch_size; batch_idx++) {
List<String> char_list = new ArrayList<>();
List<String> elem_pos_list = new ArrayList<>();
List<String> elem_idx_list = new ArrayList<>();
List<String> score_list = new ArrayList<>();
long len = structure_idx.get(batch_idx).size();
for (int idx = 0; idx < len; idx++) {
int tmp_elem_idx = (int) structure_idx.get(batch_idx).get(idx).toLongArray()[0];
if (idx > 0 && tmp_elem_idx == end_idx) {
break;
}
if (tmp_elem_idx == beg_idx || tmp_elem_idx == end_idx) {
continue;
}
char_list.add(dict_idx_elem.get("" + tmp_elem_idx));
elem_pos_list.add("" + idx);
score_list.add("" + structure_probs.get(batch_idx, idx).toFloatArray()[0]);
elem_idx_list.add("" + tmp_elem_idx);
}
result_list.add(char_list); // structure_str
result_pos_list.add(elem_pos_list);
result_score_list.add(score_list);
result_elem_idx_list.add(elem_idx_list);
}
int batch_num = result_list.size();
for (int bno = 0; bno < batch_num; bno++) {
NDList res_loc = new NDList();
int len = result_list.get(bno).size();
for (int sno = 0; sno < len; sno++) {
String text = result_list.get(bno).get(sno);
if (text.equals("<td>") || text.equals("<td")) {
int pos = Integer.parseInt(result_pos_list.get(bno).get(sno));
res_loc.add(locPreds.get(bno, pos));
}
}
String res_html_code = StringUtils.join(result_list.get(bno), "");
res_html_code_list.add(res_html_code);
NDArray array = NDArrays.stack(res_loc);
res_loc_list.add(array);
}
// structure_str_list result_list
// res_loc res_loc_list
List<BoundingBox> boxes = new ArrayList<>();
long rows = res_loc_list.get(0).size(0);
for (int rno = 0; rno < rows; rno++) {
float[] arr = res_loc_list.get(0).get(rno).toFloatArray();
Rectangle rect = new Rectangle(arr[0], arr[1], (arr[2] - arr[0]), (arr[3] - arr[1]));
boxes.add(rect);
}
List<String> structure_str_list = result_list.get(0);
structure_str_list.add(0, "<table>");
structure_str_list.add(0, "<body>");
structure_str_list.add(0, "<html>");
structure_str_list.add("</table>");
structure_str_list.add("</body>");
structure_str_list.add("</html>");
TableResult result = new TableResult(structure_str_list, boxes);
return result;
}
@Override
public Batchifier getBatchifier() {
return null;
}
private NDArray ResizeTableImage(NDArray img, int height, int width, int maxLen) {
int localMax = Math.max(height, width);
float ratio = maxLen * 1.0f / localMax;
int resize_h = (int) (height * ratio);
int resize_w = (int) (width * ratio);
if(width > height){
xScale = 1.0f;
yScale = ratio;
} else{
xScale = ratio;
yScale = 1.0f;
}
img = NDImageUtils.resize(img, resize_w, resize_h);
return img;
}
private NDArray PaddingTableImage(TranslatorContext ctx, NDArray img, int maxLen) {
Image srcImg = ImageFactory.getInstance().fromNDArray(img.duplicate());
saveImage(srcImg, "img.png", "build/output");
NDArray paddingImg = ctx.getNDManager().zeros(new Shape(maxLen, maxLen, 3), DataType.UINT8);
// NDManager manager = NDManager.newBaseManager();
// NDArray paddingImg = manager.zeros(new Shape(maxLen, maxLen, 3), DataType.UINT8);
paddingImg.set(
new NDIndex("0:" + img.getShape().get(0) + ",0:" + img.getShape().get(1) + ",:"), img);
Image image = ImageFactory.getInstance().fromNDArray(paddingImg);
saveImage(image, "paddingImg.png", "build/output");
return paddingImg;
}
public void saveImage(Image img, String name, String path) {
Path outputDir = Paths.get(path);
Path imagePath = outputDir.resolve(name);
// OpenJDK 不能保存 jpg 图片的 alpha channel
try {
img.save(Files.newOutputStream(imagePath), "png");
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,37 @@
package me.aias.ocr.model;
public class CrossRangeCellMeta {
public CrossRangeCellMeta(int firstRowIndex, int firstColIndex, int rowSpan, int colSpan) {
super();
this.firstRowIndex = firstRowIndex;
this.firstColIndex = firstColIndex;
this.rowSpan = rowSpan;
this.colSpan = colSpan;
}
private int firstRowIndex;
private int firstColIndex;
private int rowSpan;// 跨越行数
private int colSpan;// 跨越列数
public int getFirstRow() {
return firstRowIndex;
}
public int getLastRow() {
return firstRowIndex + rowSpan - 1;
}
public int getFirstCol() {
return firstColIndex;
}
public int getLastCol() {
return firstColIndex + colSpan - 1;
}
public int getColSpan(){
return colSpan;
}
}

View File

@ -0,0 +1,10 @@
package me.aias.ocr.model;
import lombok.Data;
import java.util.List;
@Data
public class DataBean {
private String value;
private List<Point> points;
}

View File

@ -0,0 +1,16 @@
package me.aias.ocr.model;
import lombok.Data;
import java.util.List;
@Data
public class LabelBean {
private int index;
private int active;
private String type;
private String value;
private String field;
private List<Point> points;
private ai.djl.modality.cv.output.Point centerPoint;
}

View File

@ -0,0 +1,11 @@
package me.aias.ocr.model;
import lombok.Data;
import java.util.List;
@Data
public class LabelDTO {
private String uid;
private LabelBean labelData;
}

View File

@ -0,0 +1,9 @@
package me.aias.ocr.model;
import lombok.Data;
@Data
public class Point {
private int x;
private int y;
}

View File

@ -0,0 +1,38 @@
package me.aias.ocr.model;
import lombok.Data;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
@Data
public class ResultBean<T> implements Serializable {
private static final long serialVersionUID = 1L;
private int code;
private String value;
private Map<String, Object> data = new HashMap<String, Object>();
public static ResultBean success() {
ResultBean rb = new ResultBean();
rb.setCode(0);
rb.setValue("Success");
return rb;
}
public static ResultBean failure() {
ResultBean msg = new ResultBean();
msg.setCode(-1);
msg.setValue("Failure");
return msg;
}
public ResultBean() {
}
public ResultBean add(String key, Object value) {
this.getData().put(key, value);
return this;
}
}

View File

@ -0,0 +1,17 @@
package me.aias.ocr.model;
import ai.djl.modality.cv.output.BoundingBox;
import lombok.Data;
import java.util.List;
@Data
public class TableResult {
private List<String> structure_str_list;
private List<BoundingBox> boxes;
public TableResult(List<String> structure_str_list, List<BoundingBox> boxes) {
this.structure_str_list = structure_str_list;
this.boxes = boxes;
}
}

View File

@ -0,0 +1,13 @@
package me.aias.ocr.model;
import lombok.Data;
import java.util.List;
@Data
public class TemplateBean {
private String uid;
private String name;
private String imageName;
List<LabelBean> labelData;
}

View File

@ -0,0 +1,17 @@
package me.aias.ocr.service;
import ai.djl.modality.cv.Image;
import ai.djl.translate.TranslateException;
import me.aias.ocr.model.DataBean;
import me.aias.ocr.model.TemplateBean;
import java.util.List;
import java.util.Map;
/**
* @author Calvin
* @date Oct 19, 2021
*/
public interface InferService {
List<DataBean> getGeneralInfo(Image image) throws TranslateException;
}

View File

@ -0,0 +1,16 @@
package me.aias.ocr.service;
import ai.djl.modality.cv.Image;
import ai.djl.translate.TranslateException;
import me.aias.ocr.model.DataBean;
import java.util.List;
/**
* @author Calvin
* @date Oct 19, 2021
*/
public interface TableInferService {
String getTableHtml(Image image) throws TranslateException;
List<String> getTableHtmlList(Image image) throws TranslateException;
}

View File

@ -0,0 +1,31 @@
package me.aias.ocr.service;
import ai.djl.modality.cv.Image;
import ai.djl.translate.TranslateException;
import me.aias.ocr.model.LabelBean;
import me.aias.ocr.model.TemplateBean;
import java.io.IOException;
import java.util.List;
import java.util.Map;
/**
* @author Calvin
* @date Oct 19, 2021
*/
public interface TemplateService {
Map<String, String> getImageInfo(TemplateBean templateBean, Image image) throws TranslateException, IOException;
List<TemplateBean> getTemplateList();
TemplateBean getTemplate(String uid) throws IOException;
void addTemplate(TemplateBean templateBean) throws IOException;
void updateTemplate(TemplateBean templateBean) throws IOException;
void removeTemplate(String uid) throws IOException;
String getLabelData(String uid, LabelBean labelData) throws IOException, TranslateException;
}

View File

@ -0,0 +1,66 @@
package me.aias.ocr.service.impl;
import ai.djl.modality.cv.Image;
import ai.djl.modality.cv.output.BoundingBox;
import ai.djl.modality.cv.output.DetectedObjects;
import ai.djl.modality.cv.output.Rectangle;
import ai.djl.ndarray.NDManager;
import ai.djl.translate.TranslateException;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import me.aias.ocr.inference.LayoutDetectionModel;
import me.aias.ocr.inference.PerspectiveRecogition;
import me.aias.ocr.inference.RecognitionModel;
import me.aias.ocr.inference.TableDetectionModel;
import me.aias.ocr.model.*;
import me.aias.ocr.service.InferService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;
/**
* @author Calvin
* @date Oct 19, 2021
*/
@Service
public class InferServiceImpl implements InferService {
private Logger logger = LoggerFactory.getLogger(InferServiceImpl.class);
@Autowired
private RecognitionModel recognitionModel;
public List<DataBean> getGeneralInfo(Image image) throws TranslateException {
List<DataBean> dataList = new ArrayList<>();
DetectedObjects detectedObjects = recognitionModel.predict(image);
List<DetectedObjects.DetectedObject> list = detectedObjects.items();
for (DetectedObjects.DetectedObject result : list) {
DataBean dataBean = new DataBean();
List<Point> points = new ArrayList<>();
String className = result.getClassName();
dataBean.setValue(className);
BoundingBox box = result.getBoundingBox();
Rectangle rectangle = box.getBounds();
Iterable<ai.djl.modality.cv.output.Point> pathIterator = rectangle.getPath();
for (Iterator iter = pathIterator.iterator(); iter.hasNext(); ) {
Point point = new Point();
ai.djl.modality.cv.output.Point djlPoint = (ai.djl.modality.cv.output.Point) iter.next();
point.setX((int) (djlPoint.getX() * image.getWidth()));
point.setY((int) (djlPoint.getY() * image.getHeight()));
points.add(point);
}
dataBean.setPoints(points);
dataList.add(dataBean);
}
return dataList;
}
}

View File

@ -0,0 +1,77 @@
package me.aias.ocr.service.impl;
import ai.djl.modality.cv.Image;
import ai.djl.modality.cv.output.BoundingBox;
import ai.djl.modality.cv.output.DetectedObjects;
import ai.djl.modality.cv.output.Rectangle;
import ai.djl.translate.TranslateException;
import me.aias.ocr.inference.LayoutDetectionModel;
import me.aias.ocr.inference.RecognitionModel;
import me.aias.ocr.inference.TableDetectionModel;
import me.aias.ocr.model.DataBean;
import me.aias.ocr.model.Point;
import me.aias.ocr.service.InferService;
import me.aias.ocr.service.TableInferService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* @author Calvin
* @date Oct 19, 2021
*/
@Service
public class TableInferServiceImpl implements TableInferService {
private Logger logger = LoggerFactory.getLogger(TableInferServiceImpl.class);
@Autowired
private RecognitionModel recognitionModel;
@Autowired
private TableDetectionModel tableDetectionModel;
@Autowired
private LayoutDetectionModel layoutDetectionModel;
public String getTableHtml(Image image) throws TranslateException {
DetectedObjects textDetections = recognitionModel.predict(image);
String tableHtml = tableDetectionModel.getTableHtml(image, textDetections);
return tableHtml;
}
public List<String> getTableHtmlList(Image image) throws TranslateException {
List<String> tableHtmlList = new ArrayList<>();
DetectedObjects layoutDetections = layoutDetectionModel.predict(image);
List<DetectedObjects.DetectedObject> boxes = layoutDetections.items();
for (int i = 0; i < boxes.size(); i++) {
// TODO 模型需优化, 页面出现多个表不准但是当前可以用于表单中一个表格自动检测识别
if (boxes.get(i).getClassName().equals("Table")) {
Image subImage = getSubImage(image, boxes.get(i).getBoundingBox());
// 表格单元检测
DetectedObjects textDetections = recognitionModel.predict(subImage);
String tableHtml = tableDetectionModel.getTableHtml(subImage, textDetections);
tableHtmlList.add(tableHtml);
}
}
return tableHtmlList;
}
private Image getSubImage(Image img, BoundingBox box) {
Rectangle rect = box.getBounds();
int width = img.getWidth();
int height = img.getHeight();
int[] recovered = {
(int) (rect.getX() * width),
(int) (rect.getY() * height),
(int) (rect.getWidth() * width),
(int) (rect.getHeight() * height)
};
return img.getSubImage(recovered[0], recovered[1], recovered[2], recovered[3]);
}
}

View File

@ -0,0 +1,209 @@
package me.aias.ocr.service.impl;
import ai.djl.modality.cv.Image;
import ai.djl.modality.cv.ImageFactory;
import ai.djl.ndarray.NDManager;
import ai.djl.translate.TranslateException;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import me.aias.ocr.configuration.FileProperties;
import me.aias.ocr.inference.PerspectiveRecogition;
import me.aias.ocr.inference.RecognitionModel;
import me.aias.ocr.model.LabelBean;
import me.aias.ocr.model.TemplateBean;
import me.aias.ocr.service.TemplateService;
import me.aias.ocr.utils.FileUtils;
import me.aias.ocr.utils.PointUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @author Calvin
* @date Oct 19, 2021
*/
@Service
public class TemplateServiceImpl implements TemplateService {
private static final String TEMPLATE_LIST_FILE = "templates.json";
private Logger logger = LoggerFactory.getLogger(TemplateServiceImpl.class);
/**
* file configuration
*/
@Autowired
private FileProperties properties;
/**
* ocr recognition model
*/
@Autowired
private RecognitionModel recognitionModel;
@Value("${model.type}")
private String type;
@Value("${image.debug}")
private boolean debug;
@Value("${distance.type}")
private String distance;
public Map<String, String> getImageInfo(TemplateBean templateBean, Image image) throws TranslateException, IOException {
List<LabelBean> anchorlabels = getLabelDataByType(templateBean.getLabelData(), "anchor");
List<LabelBean> contentLabels = getLabelDataByType(templateBean.getLabelData(), "rectangle");
FileProperties.ElPath path = properties.getPath();
String fileRelativePath = path.getPath().replace("\\", "/");
BufferedImage templateImg = ImageIO.read(new File(fileRelativePath + "images/" + templateBean.getImageName()));
try (NDManager manager = NDManager.newBaseManager()) {
Map<String, String> hashMap = PerspectiveRecogition.recognize(manager, templateImg, recognitionModel, image, anchorlabels, contentLabels, fileRelativePath, distance, debug);
return hashMap;
}
}
public List<TemplateBean> getTemplateList() {
List<TemplateBean> templateList = null;
FileProperties.ElPath path = properties.getPath();
String fileRelativePath = path.getPath().replace("\\", "/");
String json = null;
try {
json = FileUtils.readFile(fileRelativePath, TEMPLATE_LIST_FILE);
} catch (IOException e) {
e.printStackTrace();
}
if (!StringUtils.isBlank(json)) {
templateList = new Gson().fromJson(json, new TypeToken<List<TemplateBean>>() {
}.getType());
} else {
templateList = new ArrayList<>();
}
return templateList;
}
/**
* 获取模板
*
* @param uid
*/
public TemplateBean getTemplate(String uid) throws IOException {
TemplateBean template = null;
FileProperties.ElPath path = properties.getPath();
String fileRelativePath = path.getPath().replace("\\", "/") + "templates/";
String json = FileUtils.readFile(fileRelativePath, uid + ".json");
if (!StringUtils.isBlank(json)) {
template = new Gson().fromJson(json, new TypeToken<TemplateBean>() {
}.getType());
}
return template;
}
/**
* 新增模板
*
* @param templateBean
*/
public synchronized void addTemplate(TemplateBean templateBean) throws IOException {
List<TemplateBean> templateList = getTemplateList();
templateBean.setLabelData(null);
templateList.add(templateBean);
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String json = gson.toJson(templateList);
FileProperties.ElPath path = properties.getPath();
// 保存模版列表数据
String fileRelativePath = path.getPath().replace("\\", "/");
FileUtils.saveFile(fileRelativePath, TEMPLATE_LIST_FILE, json);
// 保存模版数据
json = gson.toJson(templateBean);
FileUtils.saveFile(fileRelativePath + "templates/", templateBean.getUid() + ".json", json);
}
/**
* 更新模板
*
* @param templateBean
*/
public synchronized void updateTemplate(TemplateBean templateBean) throws IOException {
List<TemplateBean> templateList = getTemplateList();
for (TemplateBean item : templateList) {
if (item.getUid().equals(templateBean.getUid())) {
BeanUtils.copyProperties(templateBean, item);
item.setLabelData(null);
break;
}
}
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String json = gson.toJson(templateList);
FileProperties.ElPath path = properties.getPath();
// 保存模版列表数据
String fileRelativePath = path.getPath().replace("\\", "/");
FileUtils.saveFile(fileRelativePath, TEMPLATE_LIST_FILE, json);
// 保存模版数据
json = gson.toJson(templateBean);
FileUtils.saveFile(fileRelativePath + "templates/", templateBean.getUid() + ".json", json);
}
/**
* 删除模板
*
* @param uid
*/
public synchronized void removeTemplate(String uid) throws IOException {
List<TemplateBean> templateList = getTemplateList();
for (int i = 0; i < templateList.size(); i++) {
if (templateList.get(i).getUid().equals(uid)) {
templateList.remove(i);
break;
}
}
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String json = gson.toJson(templateList);
FileProperties.ElPath path = properties.getPath();
// 保存模版列表数据
String fileRelativePath = path.getPath().replace("\\", "/");
FileUtils.saveFile(fileRelativePath, TEMPLATE_LIST_FILE, json);
// 删除模版数据
FileUtils.removeFile(fileRelativePath + "templates/", uid + ".json");
}
public String getLabelData(String uid, LabelBean labelData) throws IOException, TranslateException {
TemplateBean template = getTemplate(uid);
FileProperties.ElPath path = properties.getPath();
String fileRelativePath = path.getPath().replace("\\", "/");
BufferedImage img = ImageIO.read(new File(fileRelativePath + "images/" + template.getImageName()));
Image image = ImageFactory.getInstance().fromImage(img);
// int x = labelData.getPoints().get(0).getX();
// int y = labelData.getPoints().get(0).getY();
// int w = labelData.getPoints().get(1).getX() - labelData.getPoints().get(0).getX();
// int h = labelData.getPoints().get(3).getY() - labelData.getPoints().get(0).getY();
int[] rect = PointUtils.rectXYWH(labelData.getPoints());
Image subImage = image.getSubImage(rect[0], rect[1], rect[2], rect[3]);
String result = recognitionModel.predictSingleLineText(subImage);
return result;
}
private List<LabelBean> getLabelDataByType(List<LabelBean> labelData, String type) {
List<LabelBean> labels = new ArrayList<>();
for (int i = 0; i < labelData.size(); i++) {
if (labelData.get(i).getType().equals(type)) {
labels.add(labelData.get(i));
}
}
return labels;
}
}

View File

@ -0,0 +1,22 @@
package me.aias.ocr.utils;
/**
* @author Calvin
* @date Oct 19, 2021
*/
public class Constants {
/**
* win systems
*/
public static final String WIN = "win";
/**
* mac system
*/
public static final String MAC = "mac";
/**
* mac system
*/
public static final String LINUX = "linux";
}

View File

@ -0,0 +1,236 @@
package me.aias.ocr.utils;
import me.aias.ocr.model.CrossRangeCellMeta;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.util.CellRangeAddress;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import java.util.ArrayList;
import java.util.List;
/**
* @Auther: xiaoqiang
* @Date: 2020/12/9 9:16
* @Description:
*/
public class ConvertHtml2Excel {
/**
* html表格转excel
*
* @param tableHtml
* <table>
* ..
* </table>
* @return
*/
public static HSSFWorkbook table2Excel(String tableHtml) {
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet();
List<CrossRangeCellMeta> crossRowEleMetaLs = new ArrayList<>();
int rowIndex = 0;
try {
Document data = DocumentHelper.parseText(tableHtml);
// 生成表头
Element thead = data.getRootElement().element("thead");
HSSFCellStyle titleStyle = getTitleStyle(wb);
int ls=0;//列数
if (thead != null) {
List<Element> trLs = thead.elements("tr");
for (Element trEle : trLs) {
HSSFRow row = sheet.createRow(rowIndex);
List<Element> thLs = trEle.elements("td");
ls=thLs.size();
makeRowCell(thLs, rowIndex, row, 0, titleStyle, crossRowEleMetaLs);
rowIndex++;
}
}
// 生成表体
Element tbody = data.getRootElement().element("tbody");
HSSFCellStyle contentStyle = getContentStyle(wb);
if (tbody != null) {
List<Element> trLs = tbody.elements("tr");
for (Element trEle : trLs) {
HSSFRow row = sheet.createRow(rowIndex);
List<Element> thLs = trEle.elements("th");
int cellIndex = makeRowCell(thLs, rowIndex, row, 0, titleStyle, crossRowEleMetaLs);
List<Element> tdLs = trEle.elements("td");
makeRowCell(tdLs, rowIndex, row, cellIndex, contentStyle, crossRowEleMetaLs);
rowIndex++;
}
}
// 合并表头
for (CrossRangeCellMeta crcm : crossRowEleMetaLs) {
sheet.addMergedRegion(new CellRangeAddress(crcm.getFirstRow(), crcm.getLastRow(), crcm.getFirstCol(), crcm.getLastCol()));
setRegionStyle(sheet, new CellRangeAddress(crcm.getFirstRow(), crcm.getLastRow(), crcm.getFirstCol(), crcm.getLastCol()),titleStyle);
}
for(int i=0;i<sheet.getRow(0).getPhysicalNumberOfCells();i++){
sheet.autoSizeColumn(i, true);//设置列宽
if(sheet.getColumnWidth(i)<255*256){
sheet.setColumnWidth(i, sheet.getColumnWidth(i) < 9000 ? 9000 : sheet.getColumnWidth(i));
}else{
sheet.setColumnWidth(i, 15000);
}
}
} catch (DocumentException e) {
e.printStackTrace();
}
return wb;
}
/**
* 生产行内容
*
* @return 最后一列的cell index
*/
/**
* @param tdLs th或者td集合
* @param rowIndex 行号
* @param row POI行对象
* @param startCellIndex
* @param cellStyle 样式
* @param crossRowEleMetaLs 跨行元数据集合
* @return
*/
private static int makeRowCell(List<Element> tdLs, int rowIndex, HSSFRow row, int startCellIndex, HSSFCellStyle cellStyle,
List<CrossRangeCellMeta> crossRowEleMetaLs) {
int i = startCellIndex;
for (int eleIndex = 0; eleIndex < tdLs.size(); i++, eleIndex++) {
int captureCellSize = getCaptureCellSize(rowIndex, i, crossRowEleMetaLs);
while (captureCellSize > 0) {
for (int j = 0; j < captureCellSize; j++) {// 当前行跨列处理补单元格
row.createCell(i);
i++;
}
captureCellSize = getCaptureCellSize(rowIndex, i, crossRowEleMetaLs);
}
Element thEle = tdLs.get(eleIndex);
String val = thEle.getTextTrim();
if (StringUtils.isBlank(val)) {
Element e = thEle.element("a");
if (e != null) {
val = e.getTextTrim();
}
}
HSSFCell c = row.createCell(i);
if (NumberUtils.isNumber(val)) {
c.setCellValue(Double.parseDouble(val));
c.setCellType(CellType.NUMERIC);
} else {
c.setCellValue(val);
}
int rowSpan = NumberUtils.toInt(thEle.attributeValue("rowspan"), 1);
int colSpan = NumberUtils.toInt(thEle.attributeValue("colspan"), 1);
c.setCellStyle(cellStyle);
if (rowSpan > 1 || colSpan > 1) { // 存在跨行或跨列
crossRowEleMetaLs.add(new CrossRangeCellMeta(rowIndex, i, rowSpan, colSpan));
}
if (colSpan > 1) {// 当前行跨列处理补单元格
for (int j = 1; j < colSpan; j++) {
i++;
row.createCell(i);
}
}
}
return i;
}
/**
* 设置合并单元格的边框样式
*
* @param sheet
* @param region
* @param cs
*/
public static void setRegionStyle(HSSFSheet sheet, CellRangeAddress region, HSSFCellStyle cs) {
for (int i = region.getFirstRow(); i <= region.getLastRow(); i++) {
HSSFRow row = sheet.getRow(i);
for (int j = region.getFirstColumn(); j <= region.getLastColumn(); j++) {
HSSFCell cell = row.getCell(j);
cell.setCellStyle(cs);
}
}
}
/**
* 获得因rowSpan占据的单元格
*
* @param rowIndex 行号
* @param colIndex 列号
* @param crossRowEleMetaLs 跨行列元数据
* @return 当前行在某列需要占据单元格
*/
private static int getCaptureCellSize(int rowIndex, int colIndex, List<CrossRangeCellMeta> crossRowEleMetaLs) {
int captureCellSize = 0;
for (CrossRangeCellMeta crossRangeCellMeta : crossRowEleMetaLs) {
if (crossRangeCellMeta.getFirstRow() < rowIndex && crossRangeCellMeta.getLastRow() >= rowIndex) {
if (crossRangeCellMeta.getFirstCol() <= colIndex && crossRangeCellMeta.getLastCol() >= colIndex) {
captureCellSize = crossRangeCellMeta.getLastCol() - colIndex + 1;
}
}
}
return captureCellSize;
}
/**
* 获得标题样式
*
* @param workbook
* @return
*/
private static HSSFCellStyle getTitleStyle(HSSFWorkbook workbook) {
//short titlebackgroundcolor = IndexedColors.GREY_25_PERCENT.index;
short fontSize = 12;
String fontName = "宋体";
HSSFCellStyle style = workbook.createCellStyle();
style.setVerticalAlignment(VerticalAlignment.CENTER);
style.setAlignment(HorizontalAlignment.CENTER);
style.setBorderBottom(BorderStyle.THIN); //下边框
style.setBorderLeft(BorderStyle.THIN);//左边框
style.setBorderTop(BorderStyle.THIN);//上边框
style.setBorderRight(BorderStyle.THIN);//右边框
//style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
//style.setFillForegroundColor(titlebackgroundcolor);// 背景色
HSSFFont font = workbook.createFont();
font.setFontName(fontName);
font.setFontHeightInPoints(fontSize);
font.setBold(true);
style.setFont(font);
return style;
}
/**
* 获得内容样式
*
* @param wb
* @return
*/
private static HSSFCellStyle getContentStyle(HSSFWorkbook wb) {
short fontSize = 12;
String fontName = "宋体";
HSSFCellStyle style = wb.createCellStyle();
style.setBorderBottom(BorderStyle.THIN); //下边框
style.setBorderLeft(BorderStyle.THIN);//左边框
style.setBorderTop(BorderStyle.THIN);//上边框
style.setBorderRight(BorderStyle.THIN);//右边框
HSSFFont font = wb.createFont();
font.setFontName(fontName);
font.setFontHeightInPoints(fontSize);
style.setFont(font);
style.setAlignment(HorizontalAlignment.CENTER);//水平居中
style.setVerticalAlignment(VerticalAlignment.CENTER);//垂直居中
style.setWrapText(true);
return style;
}
}

View File

@ -0,0 +1,98 @@
package me.aias.ocr.utils;
import ai.djl.modality.cv.Image;
import ai.djl.modality.cv.ImageFactory;
import ai.djl.modality.cv.output.DetectedObjects;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class DJLImageUtils {
public static Image bufferedImage2DJLImage(BufferedImage img) {
return ImageFactory.getInstance().fromImage(img);
}
public static void saveImage(BufferedImage img, String name, String path) {
Image djlImg = ImageFactory.getInstance().fromImage(img); // 支持多种图片格式自动适配
Path outputDir = Paths.get(path);
Path imagePath = outputDir.resolve(name);
// OpenJDK 不能保存 jpg 图片的 alpha channel
try {
djlImg.save(Files.newOutputStream(imagePath), "png");
} catch (IOException e) {
e.printStackTrace();
}
}
public static void saveDJLImage(Image img, String name, String path) {
Path outputDir = Paths.get(path);
Path imagePath = outputDir.resolve(name);
// OpenJDK 不能保存 jpg 图片的 alpha channel
try {
img.save(Files.newOutputStream(imagePath), "png");
} catch (IOException e) {
e.printStackTrace();
}
}
public static void saveBoundingBoxImage(
Image img, DetectedObjects detection, String name, String path) throws IOException {
// Make imageName copy with alpha channel because original imageName was jpg
img.drawBoundingBoxes(detection);
Path outputDir = Paths.get(path);
Files.createDirectories(outputDir);
Path imagePath = outputDir.resolve(name);
// OpenJDK can't save jpg with alpha channel
img.save(Files.newOutputStream(imagePath), "png");
}
public static void drawImageRect(BufferedImage image, int x, int y, int width, int height) {
// 将绘制图像转换为Graphics2D
Graphics2D g = (Graphics2D) image.getGraphics();
try {
g.setColor(new Color(246, 96, 0));
// 声明画笔属性 单位像素末端无修饰 折线处呈尖角
BasicStroke bStroke = new BasicStroke(4, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER);
g.setStroke(bStroke);
g.drawRect(x, y, width, height);
} finally {
g.dispose();
}
}
public static void drawImageRect(
BufferedImage image, int x, int y, int width, int height, Color c) {
// 将绘制图像转换为Graphics2D
Graphics2D g = (Graphics2D) image.getGraphics();
try {
g.setColor(c);
// 声明画笔属性 单位像素末端无修饰 折线处呈尖角
BasicStroke bStroke = new BasicStroke(4, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER);
g.setStroke(bStroke);
g.drawRect(x, y, width, height);
} finally {
g.dispose();
}
}
public static void drawImageText(BufferedImage image, String text) {
Graphics graphics = image.getGraphics();
int fontSize = 100;
Font font = new Font("楷体", Font.PLAIN, fontSize);
try {
graphics.setFont(font);
graphics.setColor(new Color(246, 96, 0));
int strWidth = graphics.getFontMetrics().stringWidth(text);
graphics.drawString(text, fontSize - (strWidth / 2), fontSize + 30);
} finally {
graphics.dispose();
}
}
}

View File

@ -0,0 +1,110 @@
package me.aias.ocr.utils;
import me.aias.ocr.model.LabelBean;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author Calvin
* @date Oct 19, 2021
*/
public class DistanceUtils {
/**
* Calculate L2 distance
*
* @param contentLabels 内容识别区
* @param detectedTexts 文本检测区
* @return
*/
public static Map<String, String> l2Distance(List<LabelBean> contentLabels, List<LabelBean> detectedTexts) {
Map<String, String> hashMap = new ConcurrentHashMap<>();
for (int i = 0; i < contentLabels.size(); i++) {
String field = contentLabels.get(i).getField();
double minDistance = Double.MAX_VALUE;
String value = "";
for (int j = 0; j < detectedTexts.size(); j++) {
double dis = l2Distance(contentLabels.get(i).getCenterPoint(), detectedTexts.get(j).getCenterPoint());
if (dis < minDistance) {
minDistance = dis;
value = detectedTexts.get(j).getValue();
}
}
System.out.println(field + " : " + value);
hashMap.put(field, value);
}
return hashMap;
}
/**
* Calculate iou
*
* @param contentLabels 内容识别区
* @param detectedTexts 文本检测区
* @return
*/
public static Map<String, String> iou(List<LabelBean> contentLabels, List<LabelBean> detectedTexts) {
Map<String, String> hashMap = new ConcurrentHashMap<>();
for (int i = 0; i < contentLabels.size(); i++) {
String field = contentLabels.get(i).getField();
double maxIOU = 0d;
String value = "";
int[] box_1 = PointUtils.rectXYXY(contentLabels.get(i).getPoints());
for (int j = 0; j < detectedTexts.size(); j++) {
int[] box_2 = PointUtils.rectXYXY(detectedTexts.get(j).getPoints());
double iou = compute_iou(box_1, box_2);
if (iou > maxIOU) {
maxIOU = iou;
value = detectedTexts.get(j).getValue();
}
}
System.out.println(field + " : " + value);
hashMap.put(field, value);
}
return hashMap;
}
/**
* Calculate L2 distance
*
* @param point1
* @param point2
* @return
*/
public static double l2Distance(ai.djl.modality.cv.output.Point point1, ai.djl.modality.cv.output.Point point2) {
double partX = Math.pow((point1.getX() - point2.getX()), 2);
double partY = Math.pow((point1.getY() - point2.getY()), 2);
return Math.sqrt(partX + partY);
}
/**
* computing IoU
*
* @param rec1: (y0, x0, y1, x1), which reflects (top, left, bottom, right)
* @param rec2: (y0, x0, y1, x1)
* @return scala value of IoU
*/
public static float compute_iou(int[] rec1, int[] rec2) {
// computing area of each rectangles
int S_rec1 = (rec1[2] - rec1[0]) * (rec1[3] - rec1[1]);
int S_rec2 = (rec2[2] - rec2[0]) * (rec2[3] - rec2[1]);
// computing the sum_area
int sum_area = S_rec1 + S_rec2;
// find the each edge of intersect rectangle
int left_line = Math.max(rec1[1], rec2[1]);
int right_line = Math.min(rec1[3], rec2[3]);
int top_line = Math.max(rec1[0], rec2[0]);
int bottom_line = Math.min(rec1[2], rec2[2]);
// judge if there is an intersect
if (left_line >= right_line || top_line >= bottom_line) {
return 0.0f;
} else {
float intersect = (right_line - left_line) * (bottom_line - top_line);
return (intersect / (sum_area - intersect)) * 1.0f;
}
}
}

View File

@ -0,0 +1,131 @@
package me.aias.ocr.utils;
import ai.djl.util.Utils;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import me.aias.ocr.configuration.FileProperties;
import org.apache.commons.compress.utils.FileNameUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
/**
* 文件上传工具包
*/
public class FileUtils {
/**
* @param file 文件
* @param path 文件存放路径
* @param fileName 源文件名
* @return
*/
public static boolean upload(MultipartFile file, String path, String fileName) {
// 生成新的文件名
//String realPath = path + "/" + FileNameUtils.getFileName(fileName);
Path filePath = Paths.get(path + fileName);
File dest = filePath.toAbsolutePath().toFile();
//判断文件父目录是否存在
if (!dest.getParentFile().exists()) {
dest.getParentFile().mkdir();
}
try {
//保存文件
file.transferTo(dest);
return true;
} catch (IllegalStateException e) {
e.printStackTrace();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
/**
* 获取文件后缀
*
* @param fileName
* @return
*/
public static String getSuffix(String fileName) {
return fileName.substring(fileName.lastIndexOf("."));
}
/**
* 生成新的文件名
*
* @param fileOriginName 源文件名
* @return
*/
public static String getFileName(String fileOriginName) {
return UUIDUtils.getUUID() + getSuffix(fileOriginName);
}
/**
* 读取json文件
*
* @param path 文件路径信息
* @param fileName 文件名
* @return
*/
public static String readFile(String path, String fileName) throws IOException {
StringBuilder json = new StringBuilder();
Path filePath = Paths.get(path + fileName);
List<String> lines = Utils.readLines(filePath, true);
lines.stream()
.filter(line -> (line != null && line != ""))
.forEach(
line -> {
json.append(line);
});
return json.toString();
}
/**
* 保存json文件
*
* @param path 文件路径信息
* @param fileName 文件名
* @param json json信息
* @return
*/
public static void saveFile(String path, String fileName, String json) throws IOException {
Path filePath = Paths.get(path + fileName);
try (PrintStream ps = new PrintStream(new FileOutputStream(filePath.toFile()))) {
ps.print(json);
}
}
/**
* 删除json文件
*
* @param path 文件路径信息
* @param fileName 文件名
* @return
*/
public static void removeFile(String path, String fileName) {
Path filePath = Paths.get(path + fileName);
filePath.toFile().delete();
}
/**
* Check & create file path
*
* @param fileRelativePath 文件路径信息
* @return
*/
public static void checkAndCreatePath(String fileRelativePath) {
//Check & create file path
Path filePath = Paths.get(fileRelativePath).toAbsolutePath();
File file = filePath.toFile();
if (!file.exists() && !file.isDirectory()) {
file.mkdirs();
}
}
}

View File

@ -0,0 +1,66 @@
package me.aias.ocr.utils;
import ai.djl.ndarray.NDArray;
import ai.djl.ndarray.NDManager;
import me.aias.ocr.model.Point;
import org.bytedeco.javacpp.indexer.DoubleRawIndexer;
import org.bytedeco.opencv.global.opencv_core;
import org.bytedeco.opencv.opencv_core.Mat;
import org.bytedeco.opencv.opencv_core.Point2f;
import java.util.List;
public class NDArrayUtils {
// NDArray opencv_core.Mat
public static Mat toOpenCVMat(NDArray points, int rows, int cols) {
double[] doubleArray = points.toDoubleArray();
// CV_32F = FloatRawIndexer
// CV_64F = DoubleRawIndexer
Mat mat = new Mat(rows, cols, opencv_core.CV_64F);
DoubleRawIndexer ldIdx = mat.createIndexer();
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
ldIdx.put(i, j, doubleArray[i * cols + j]);
}
}
ldIdx.release();
return mat;
}
// NDArray opencv_core.Point2f
public static Point2f toOpenCVPoint2f(NDArray points, int rows) {
double[] doubleArray = points.toDoubleArray();
Point2f points2f = new Point2f(rows);
for (int i = 0; i < rows; i++) {
points2f.position(i).x((float) doubleArray[i * 2]).y((float) doubleArray[i * 2 + 1]);
}
return points2f;
}
// Double array opencv_core.Point2f
public static Point2f toOpenCVPoint2f(double[] doubleArray, int rows) {
Point2f points2f = new Point2f(rows);
for (int i = 0; i < rows; i++) {
points2f.position(i).x((float) doubleArray[i * 2]).y((float) doubleArray[i * 2 + 1]);
}
return points2f;
}
// list opencv_core.Point2f
public static Point2f toOpenCVPoint2f(List<ai.djl.modality.cv.output.Point> points, int rows) {
Point2f points2f = new Point2f(points.size());
for (int i = 0; i < rows; i++) {
ai.djl.modality.cv.output.Point point = points.get(i);
points2f.position(i).x((float) point.getX()).y((float) point.getY());
}
return points2f;
}
}

View File

@ -0,0 +1,82 @@
package me.aias.ocr.utils;
import org.bytedeco.javacpp.indexer.DoubleRawIndexer;
import org.bytedeco.opencv.global.opencv_core;
import org.bytedeco.opencv.global.opencv_imgproc;
import org.bytedeco.opencv.opencv_core.CvMat;
import org.bytedeco.opencv.opencv_core.Mat;
import org.bytedeco.opencv.opencv_core.Point2f;
import org.bytedeco.opencv.opencv_core.Point2fVector;
import java.nio.FloatBuffer;
import static org.bytedeco.opencv.global.opencv_calib3d.findHomography;
import static org.bytedeco.opencv.global.opencv_core.cvCreateMat;
public class OpenCVUtils {
public static Mat affineTransform(
Mat src, Point2f srcPoints, Point2f dstPoints) {
Mat dst = src.clone();
// https://github.com/bytedeco/javacv/issues/788
Mat warp_mat = opencv_imgproc.getAffineTransform(srcPoints.position(0), dstPoints.position(0));
opencv_imgproc.warpAffine(src, dst, warp_mat, dst.size());
return dst;
}
public static Mat perspectiveTransform(
Mat src, Point2f srcPoints, Point2f dstPoints) {
Mat dst = src.clone();
Mat warp_mat = opencv_imgproc.getPerspectiveTransform(srcPoints.position(0), dstPoints.position(0));
opencv_imgproc.warpPerspective(src, dst, warp_mat, dst.size());
return dst;
}
public static Mat getHomography(Mat src, double[] srcPoints, double[] dstPoints) {
Mat dst = src.clone();
Mat warp_mat = createHomography(srcPoints, dstPoints);
opencv_imgproc.warpPerspective(src, dst, warp_mat, dst.size());
return dst;
}
public static Mat createHomography(double[] src, double[] dst) {
CvMat srcPoints;
CvMat dstPoints;
int nbPoints = src.length / 2;
Mat homography;
srcPoints = cvCreateMat(2, nbPoints, opencv_core.CV_32FC1);
dstPoints = cvCreateMat(2, nbPoints, opencv_core.CV_32FC1);
Mat newSvdMat = new Mat(2, 3, opencv_core.CV_32FC1);
// homography = cvCreateMat(3, 3, opencv_core.CV_32FC1);
for (int i = 0; i < nbPoints; i++) {
srcPoints.put(i, src[2 * i]);
srcPoints.put(i + nbPoints, src[2 * i + 1]);
dstPoints.put(i, dst[2 * i]);
dstPoints.put(i + nbPoints, dst[2 * i + 1]);
}
homography = findHomography(returnMat(srcPoints), returnMat(dstPoints));
return homography;
}
public static Mat returnMat(CvMat mtx) {
double valor;
final int rows = mtx.rows();
final int cols = mtx.cols();
Mat mat = new Mat(rows, cols, opencv_core.CV_64F);
final int step = mtx.step() / 4;
FloatBuffer buf = mtx.getFloatBuffer();
DoubleRawIndexer ldIdx = mat.createIndexer();
for (int row = 0; row < rows; row++) {
buf.position(row * step);
for (int col = 0; col < cols; col++) {
valor = buf.get();
ldIdx.put(row, col, valor);
}
}
ldIdx.release();
return mat;
}
}

View File

@ -0,0 +1,135 @@
package me.aias.ocr.utils;
import ai.djl.ndarray.NDArray;
import ai.djl.ndarray.NDManager;
import me.aias.ocr.model.Point;
import org.bytedeco.javacpp.indexer.DoubleRawIndexer;
import org.bytedeco.opencv.opencv_core.Mat;
import java.util.List;
/**
* @author Calvin
* @date Oct 19, 2021
*/
public class PointUtils {
public static ai.djl.modality.cv.output.Point getCenterPoint(List<Point> points) {
double sumX = 0;
double sumY = 0;
for (Point point : points) {
sumX = sumX + point.getX();
sumY = sumY + point.getY();
}
ai.djl.modality.cv.output.Point centerPoint = new ai.djl.modality.cv.output.Point(sumX / 4, sumY / 4);
return centerPoint;
}
public static Point transformPoint(NDManager manager, Mat mat, Point point) {
double[][] pointsArray = new double[3][3];
DoubleRawIndexer ldIdx = mat.createIndexer();
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
pointsArray[i][j] = ldIdx.get(i, j);
}
}
NDArray ndPoints = manager.create(pointsArray);
double[] vector = new double[3];
vector[0] = point.getX();
vector[1] = point.getY();
vector[2] = 1f;
NDArray vPoints = manager.create(vector);
vPoints = vPoints.reshape(3, 1);
NDArray result = ndPoints.matMul(vPoints);
double[] dArray = result.toDoubleArray();
if (dArray[2] != 0) {
point.setX((int) (dArray[0] / dArray[2]));
point.setY((int) (dArray[1] / dArray[2]));
}
return point;
}
public static List<Point> transformPoints(NDManager manager, Mat mat, List<Point> points) {
int cols = mat.cols();
int rows = mat.rows();
double[][] pointsArray = new double[rows][cols];
DoubleRawIndexer ldIdx = mat.createIndexer();
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
pointsArray[i][j] = ldIdx.get(i, j);
}
}
NDArray ndPoints = manager.create(pointsArray);
double[] vector = new double[3];
for (int i = 0; i < points.size(); i++) {
vector[0] = points.get(i).getX();
vector[1] = points.get(i).getY();
vector[2] = 1f;
NDArray vPoints = manager.create(vector);
vPoints = vPoints.reshape(3, 1);
NDArray result = ndPoints.matMul(vPoints);
double[] dArray = result.toDoubleArray();
if (dArray.length > 2) {
if (dArray[2] != 0) {
points.get(i).setX((int) (dArray[0] / dArray[2]));
points.get(i).setY((int) (dArray[1] / dArray[2]));
}
} else {
points.get(i).setX((int) (dArray[0]));
points.get(i).setY((int) (dArray[1]));
}
}
return points;
}
/**
* Get (x1,y1,x2,y2) coordinations
*
* @param points
* @return
*/
public static int[] rectXYXY(List<Point> points) {
int left = points.get(0).getX();
int top = points.get(0).getY();
int right = points.get(2).getX();
int bottom = points.get(2).getY();
return new int[]{left, top, right, bottom};
}
/**
* Get (x1,y1,w,h) coordinations
*
* @param points
* @return
*/
public static int[] rectXYWH(List<Point> points) {
int minX = Integer.MAX_VALUE;
int minY = Integer.MAX_VALUE;
int maxX = Integer.MIN_VALUE;
int maxY = Integer.MIN_VALUE;
for (Point point : points) {
int x = point.getX();
int y = point.getY();
if (x < minX)
minX = x;
if (x > maxX)
maxX = x;
if (y < minY)
minY = y;
if (y > maxY)
maxY = y;
}
int w = maxX - minX;
int h = maxY - minY;
return new int[]{minX, minY, w, h};
}
}

View File

@ -0,0 +1,14 @@
package me.aias.ocr.utils;
import java.util.UUID;
/**
* 生成文件名
*/
public class UUIDUtils {
public static String getUUID() {
return UUID.randomUUID().toString().replace("-", "");
}
}

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/java" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -0,0 +1,70 @@
# Server Port
server:
port: 8089
tomcat:
uri-encoding: UTF-8
baseUri: http://127.0.0.1:${server.port}
# Swagger-ui
swagger:
enabled: true
spring:
servlet:
multipart:
enabled: true
max-file-size: 30MB
max-request-size: 30MB
http:
encoding:
charset: utf-8
enabled: true
force: true
messages:
encoding: UTF-8
# File path
file:
mac:
path: file/
linux:
path: file/
windows:
path: C:\ocr\file\
# File max size - MB
maxSize: 100
# Model type: mobile, light, server
model:
type: mobile
table:
# Layout detection model URI
layout: https://aias-home.oss-cn-beijing.aliyuncs.com/models/ocr_models/ppyolov2_r50vd_dcn_365e_publaynet_infer.zip
# Table detection model URI
table-en: https://aias-home.oss-cn-beijing.aliyuncs.com/models/ocr_models/en_table.zip
mobile:
# mobile detection model URI
det: https://aias-home.oss-cn-beijing.aliyuncs.com/models/ocr_models/ch_ppocr_mobile_v2.0_det_infer.zip
# mobile recognition model URI
rec: https://aias-home.oss-cn-beijing.aliyuncs.com/models/ocr_models/ch_ppocr_mobile_v2.0_rec_infer.zip
light:
# light detection model URI
det: https://aias-home.oss-cn-beijing.aliyuncs.com/models/ocr_models/ch_PP-OCRv2_det_infer.zip
# light recognition model URI
rec: https://aias-home.oss-cn-beijing.aliyuncs.com/models/ocr_models/ch_PP-OCRv2_rec_infer.zip
server:
# server detection model URI
det: https://aias-home.oss-cn-beijing.aliyuncs.com/models/ocr_models/ch_ppocr_server_v2.0_det_infer.zip
# server recognition model URI
rec: https://aias-home.oss-cn-beijing.aliyuncs.com/models/ocr_models/ch_ppocr_server_v2.0_rec_infer.zip
# Verify image transformation result
image:
debug: true
# distance calculation type: L2, IoU
distance:
type: L2

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
<Appenders>
<Console name="console" target="SYSTEM_OUT">
<PatternLayout
pattern="[%-5level] - %msg%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="info" additivity="false">
<AppenderRef ref="console"/>
</Root>
<Logger name="me.calvin" level="${sys:me.calvin.logging.level:-info}" additivity="false">
<AppenderRef ref="console"/>
</Logger>
</Loggers>
</Configuration>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/java" isTestSource="true" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="main" />
</component>
</module>

View File

@ -0,0 +1,14 @@
# http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
insert_final_newline = false
trim_trailing_whitespace = false

View File

@ -0,0 +1,6 @@
# just a flag
ENV = 'development'
# base api
VUE_APP_BASE_API = 'http://127.0.0.1:8089'

View File

@ -0,0 +1,6 @@
# just a flag
ENV = 'production'
# base api
VUE_APP_BASE_API = 'http://127.0.0.1:8089'

View File

@ -0,0 +1,8 @@
NODE_ENV = production
# just a flag
ENV = 'staging'
# base api
VUE_APP_BASE_API = '/stage-api'

View File

@ -0,0 +1,4 @@
build/*.js
src/assets
public
dist

View File

@ -0,0 +1,198 @@
module.exports = {
root: true,
parserOptions: {
parser: 'babel-eslint',
sourceType: 'module'
},
env: {
browser: true,
node: true,
es6: true,
},
extends: ['plugin:vue/recommended', 'eslint:recommended'],
// add your custom rules here
//it is base on https://github.com/vuejs/eslint-config-vue
rules: {
"vue/max-attributes-per-line": [2, {
"singleline": 10,
"multiline": {
"max": 1,
"allowFirstLine": false
}
}],
"vue/singleline-html-element-content-newline": "off",
"vue/multiline-html-element-content-newline":"off",
"vue/name-property-casing": ["error", "PascalCase"],
"vue/no-v-html": "off",
'accessor-pairs': 2,
'arrow-spacing': [2, {
'before': true,
'after': true
}],
'block-spacing': [2, 'always'],
'brace-style': [2, '1tbs', {
'allowSingleLine': true
}],
'camelcase': [0, {
'properties': 'always'
}],
'comma-dangle': [2, 'never'],
'comma-spacing': [2, {
'before': false,
'after': true
}],
'comma-style': [2, 'last'],
'constructor-super': 2,
'curly': [2, 'multi-line'],
'dot-location': [2, 'property'],
'eol-last': 2,
'eqeqeq': ["error", "always", {"null": "ignore"}],
'generator-star-spacing': [2, {
'before': true,
'after': true
}],
'handle-callback-err': [2, '^(err|error)$'],
'indent': [2, 2, {
'SwitchCase': 1
}],
'jsx-quotes': [2, 'prefer-single'],
'key-spacing': [2, {
'beforeColon': false,
'afterColon': true
}],
'keyword-spacing': [2, {
'before': true,
'after': true
}],
'new-cap': [2, {
'newIsCap': true,
'capIsNew': false
}],
'new-parens': 2,
'no-array-constructor': 2,
'no-caller': 2,
'no-console': 'off',
'no-class-assign': 2,
'no-cond-assign': 2,
'no-const-assign': 2,
'no-control-regex': 0,
'no-delete-var': 2,
'no-dupe-args': 2,
'no-dupe-class-members': 2,
'no-dupe-keys': 2,
'no-duplicate-case': 2,
'no-empty-character-class': 2,
'no-empty-pattern': 2,
'no-eval': 2,
'no-ex-assign': 2,
'no-extend-native': 2,
'no-extra-bind': 2,
'no-extra-boolean-cast': 2,
'no-extra-parens': [2, 'functions'],
'no-fallthrough': 2,
'no-floating-decimal': 2,
'no-func-assign': 2,
'no-implied-eval': 2,
'no-inner-declarations': [2, 'functions'],
'no-invalid-regexp': 2,
'no-irregular-whitespace': 2,
'no-iterator': 2,
'no-label-var': 2,
'no-labels': [2, {
'allowLoop': false,
'allowSwitch': false
}],
'no-lone-blocks': 2,
'no-mixed-spaces-and-tabs': 2,
'no-multi-spaces': 2,
'no-multi-str': 2,
'no-multiple-empty-lines': [2, {
'max': 1
}],
'no-native-reassign': 2,
'no-negated-in-lhs': 2,
'no-new-object': 2,
'no-new-require': 2,
'no-new-symbol': 2,
'no-new-wrappers': 2,
'no-obj-calls': 2,
'no-octal': 2,
'no-octal-escape': 2,
'no-path-concat': 2,
'no-proto': 2,
'no-redeclare': 2,
'no-regex-spaces': 2,
'no-return-assign': [2, 'except-parens'],
'no-self-assign': 2,
'no-self-compare': 2,
'no-sequences': 2,
'no-shadow-restricted-names': 2,
'no-spaced-func': 2,
'no-sparse-arrays': 2,
'no-this-before-super': 2,
'no-throw-literal': 2,
'no-trailing-spaces': 2,
'no-undef': 2,
'no-undef-init': 2,
'no-unexpected-multiline': 2,
'no-unmodified-loop-condition': 2,
'no-unneeded-ternary': [2, {
'defaultAssignment': false
}],
'no-unreachable': 2,
'no-unsafe-finally': 2,
'no-unused-vars': [2, {
'vars': 'all',
'args': 'none'
}],
'no-useless-call': 2,
'no-useless-computed-key': 2,
'no-useless-constructor': 2,
'no-useless-escape': 0,
'no-whitespace-before-property': 2,
'no-with': 2,
'one-var': [2, {
'initialized': 'never'
}],
'operator-linebreak': [2, 'after', {
'overrides': {
'?': 'before',
':': 'before'
}
}],
'padded-blocks': [2, 'never'],
'quotes': [2, 'single', {
'avoidEscape': true,
'allowTemplateLiterals': true
}],
'semi': [2, 'never'],
'semi-spacing': [2, {
'before': false,
'after': true
}],
'space-before-blocks': [2, 'always'],
'space-before-function-paren': [2, 'never'],
'space-in-parens': [2, 'never'],
'space-infix-ops': 2,
'space-unary-ops': [2, {
'words': true,
'nonwords': false
}],
'spaced-comment': [2, 'always', {
'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
}],
'template-curly-spacing': [2, 'never'],
'use-isnan': 2,
'valid-typeof': 2,
'wrap-iife': [2, 'any'],
'yield-star-spacing': [2, 'both'],
'yoda': [2, 'never'],
'prefer-const': 2,
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
'object-curly-spacing': [2, 'always', {
objectsInObjects: false
}],
'array-bracket-spacing': [2, 'never']
}
}

View File

@ -0,0 +1,5 @@
language: node_js
node_js: 10
script: npm run test
notifications:
email: false

View File

@ -0,0 +1,14 @@
module.exports = {
presets: [
// https://github.com/vuejs/vue-cli/tree/master/packages/@vue/babel-preset-app
'@vue/cli-plugin-babel/preset'
],
'env': {
'development': {
// babel-plugin-dynamic-import-node plugin only does one thing by converting all import() to require().
// This plugin can significantly increase the speed of hot updates, when you have a large number of pages.
// https://panjiachen.github.io/vue-element-admin-site/guide/advanced/lazy-loading.html
'plugins': ['dynamic-import-node']
}
}
}

View File

@ -0,0 +1,35 @@
const { run } = require('runjs')
const chalk = require('chalk')
const config = require('../vue.config.js')
const rawArgv = process.argv.slice(2)
const args = rawArgv.join(' ')
if (process.env.npm_config_preview || rawArgv.includes('--preview')) {
const report = rawArgv.includes('--report')
run(`vue-cli-service build ${args}`)
const port = 9526
const publicPath = config.publicPath
var connect = require('connect')
var serveStatic = require('serve-static')
const app = connect()
app.use(
publicPath,
serveStatic('./dist', {
index: ['index.html', '/']
})
)
app.listen(port, function () {
console.log(chalk.green(`> Preview at http://localhost:${port}${publicPath}`))
if (report) {
console.log(chalk.green(`> Report at http://localhost:${port}${publicPath}report.html`))
}
})
} else {
run(`vue-cli-service build ${args}`)
}

View File

@ -0,0 +1,24 @@
module.exports = {
moduleFileExtensions: ['js', 'jsx', 'json', 'vue'],
transform: {
'^.+\\.vue$': 'vue-jest',
'.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$':
'jest-transform-stub',
'^.+\\.jsx?$': 'babel-jest'
},
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1'
},
snapshotSerializers: ['jest-serializer-vue'],
testMatch: [
'**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
],
collectCoverageFrom: ['src/utils/**/*.{js,vue}', '!src/utils/auth.js', '!src/utils/request.js', 'src/components/**/*.{js,vue}'],
coverageDirectory: '<rootDir>/tests/unit/coverage',
// 'collectCoverage': true,
'coverageReporters': [
'lcov',
'text-summary'
],
testURL: 'http://localhost/'
}

View File

@ -0,0 +1,9 @@
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
}
},
"exclude": ["node_modules", "dist"]
}

View File

@ -0,0 +1,65 @@
{
"name": "ocr-ui",
"version": "1.0.0",
"description": "OCR UI Demo",
"author": "Calvin <693544619@qq.com>",
"scripts": {
"dev": "vue-cli-service serve",
"build:prod": "vue-cli-service build",
"build:stage": "vue-cli-service build --mode staging",
"preview": "node build/index.js --preview",
"lint": "eslint --ext .js,.vue src",
"test:unit": "jest --clearCache && vue-cli-service test:unit",
"test:ci": "npm run lint && npm run test:unit"
},
"dependencies": {
"axios": "0.18.1",
"core-js": "3.6.5",
"easy-circular-progress": "1.0.4",
"echarts": "^4.2.1",
"element-ui": "2.13.2",
"js-base64": "^2.6.4",
"js-cookie": "2.2.0",
"normalize.css": "7.0.0",
"nprogress": "0.2.0",
"path-to-regexp": "2.4.0",
"vertx3-eventbus-client": "^3.9.4",
"vue": "2.6.10",
"vue-count-to": "^1.0.13",
"vue-json-viewer": "^2.2.18",
"vue-router": "3.0.6",
"vuex": "3.1.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "4.4.4",
"@vue/cli-plugin-eslint": "4.4.4",
"@vue/cli-plugin-unit-jest": "4.4.4",
"@vue/cli-service": "4.4.4",
"@vue/test-utils": "1.0.0-beta.29",
"autoprefixer": "9.5.1",
"babel-eslint": "10.1.0",
"babel-jest": "23.6.0",
"babel-plugin-dynamic-import-node": "2.3.3",
"chalk": "2.4.2",
"connect": "3.6.6",
"eslint": "6.7.2",
"eslint-plugin-vue": "6.2.2",
"html-webpack-plugin": "3.2.0",
"mockjs": "1.0.1-beta3",
"runjs": "4.3.2",
"sass": "1.26.8",
"sass-loader": "8.0.2",
"script-ext-html-webpack-plugin": "2.1.3",
"serve-static": "1.13.2",
"vue-template-compiler": "2.6.10"
},
"browserslist": [
"> 1%",
"last 2 versions"
],
"engines": {
"node": ">=8.9",
"npm": ">= 3.0.0"
},
"license": "MIT"
}

View File

@ -0,0 +1,8 @@
// https://github.com/michael-ciniawsky/postcss-load-config
module.exports = {
'plugins': {
// to edit target browsers: use "browserslist" field in package.json
'autoprefixer': {}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= webpackConfig.name %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= webpackConfig.name %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

View File

@ -0,0 +1,11 @@
<template>
<div id="app">
<router-view />
</div>
</template>
<script>
export default {
name: 'App'
}
</script>

View File

@ -0,0 +1,14 @@
import request from '@/utils/request'
export function generalInfoForImageUrl(data) {
return request({
url: '/inference/generalInfoForImageUrl',
method: 'get',
params: {
url: data.url
}
})
}
export default { generalInfoForImageUrl }

View File

@ -0,0 +1,24 @@
import request from '@/utils/request'
export function tableInfoForImageUrl(data) {
return request({
url: '/table/tableInfoForImageUrl',
method: 'get',
params: {
url: data.url
}
})
}
export function autoTableInfoForImageUrl(data) {
return request({
url: '/table/autoTableInfoForImageUrl',
method: 'get',
params: {
url: data.url
}
})
}
export default { tableInfoForImageUrl, autoTableInfoForImageUrl }

View File

@ -0,0 +1,68 @@
import request from '@/utils/request'
export function infoForImageUrl(uid, data) {
return request({
url: '/template/infoForImageUrl',
method: 'get',
params: {
uid: uid,
url: data.url
}
})
}
export function getTemplate(uid) {
return request({
url: '/template/getTemplate',
method: 'get',
params: {
uid: uid
}
})
}
export function getTemplates() {
return request({
url: '/template/getTemplates',
method: 'get'
})
}
export function updateTemplate(data) {
return request({
url: '/template/updateTemplate',
method: 'post',
data
})
}
export function getLabelData(data) {
return request({
url: '/template/getLabelData',
method: 'post',
data
})
}
export function addTemplate(name, imageFile) {
return request({
url: '/template/updateTemplate',
method: 'post',
params: {
name: name,
imageFile: imageFile
}
})
}
export function removeTemplate(uid) {
return request({
url: '/template/removeTemplate',
method: 'post',
params: {
uid: uid
}
})
}
export default { getTemplate, getTemplates, updateTemplate, getLabelData, addTemplate, removeTemplate }

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@ -0,0 +1,78 @@
<template>
<el-breadcrumb class="app-breadcrumb" separator="/">
<transition-group name="breadcrumb">
<el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path">
<span v-if="item.redirect==='noRedirect'||index==levelList.length-1" class="no-redirect">{{ item.meta.title }}</span>
<a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
</el-breadcrumb-item>
</transition-group>
</el-breadcrumb>
</template>
<script>
import pathToRegexp from 'path-to-regexp'
export default {
data() {
return {
levelList: null
}
},
watch: {
$route() {
this.getBreadcrumb()
}
},
created() {
this.getBreadcrumb()
},
methods: {
getBreadcrumb() {
// only show routes with meta.title
let matched = this.$route.matched.filter(item => item.meta && item.meta.title)
const first = matched[0]
if (!this.isDashboard(first)) {
matched = [{ path: '/dashboard', meta: { title: 'Dashboard' }}].concat(matched)
}
this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
},
isDashboard(route) {
const name = route && route.name
if (!name) {
return false
}
return name.trim().toLocaleLowerCase() === 'Dashboard'.toLocaleLowerCase()
},
pathCompile(path) {
// To solve this problem https://github.com/PanJiaChen/vue-element-admin/issues/561
const { params } = this.$route
var toPath = pathToRegexp.compile(path)
return toPath(params)
},
handleLink(item) {
const { redirect, path } = item
if (redirect) {
this.$router.push(redirect)
return
}
this.$router.push(this.pathCompile(path))
}
}
}
</script>
<style lang="scss" scoped>
.app-breadcrumb.el-breadcrumb {
display: inline-block;
font-size: 14px;
line-height: 50px;
margin-left: 8px;
.no-redirect {
color: #97a8be;
cursor: text;
}
}
</style>

View File

@ -0,0 +1,44 @@
<template>
<div style="padding: 0 15px;" @click="toggleClick">
<svg
:class="{'is-active':isActive}"
class="hamburger"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
width="64"
height="64"
>
<path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" />
</svg>
</div>
</template>
<script>
export default {
name: 'Hamburger',
props: {
isActive: {
type: Boolean,
default: false
}
},
methods: {
toggleClick() {
this.$emit('toggleClick')
}
}
}
</script>
<style scoped>
.hamburger {
display: inline-block;
vertical-align: middle;
width: 20px;
height: 20px;
}
.hamburger.is-active {
transform: rotate(180deg);
}
</style>

View File

@ -0,0 +1,62 @@
<template>
<div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" />
<svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
<use :xlink:href="iconName" />
</svg>
</template>
<script>
// doc: https://panjiachen.github.io/vue-element-admin-site/feature/component/svg-icon.html#usage
import { isExternal } from '@/utils/validate'
export default {
name: 'SvgIcon',
props: {
iconClass: {
type: String,
required: true
},
className: {
type: String,
default: ''
}
},
computed: {
isExternal() {
return isExternal(this.iconClass)
},
iconName() {
return `#icon-${this.iconClass}`
},
svgClass() {
if (this.className) {
return 'svg-icon ' + this.className
} else {
return 'svg-icon'
}
},
styleExternalIcon() {
return {
mask: `url(${this.iconClass}) no-repeat 50% 50%`,
'-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%`
}
}
}
}
</script>
<style scoped>
.svg-icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
.svg-external-icon {
background-color: currentColor;
mask-size: cover!important;
display: inline-block;
}
</style>

View File

@ -0,0 +1,40 @@
<template>
<section class="app-main">
<transition name="fade-transform" mode="out-in">
<router-view :key="key" />
</transition>
</section>
</template>
<script>
export default {
name: 'AppMain',
computed: {
key() {
return this.$route.path
}
}
}
</script>
<style scoped>
.app-main {
/*50 = navbar */
min-height: calc(100vh - 50px);
width: 100%;
position: relative;
overflow: hidden;
}
.fixed-header+.app-main {
padding-top: 50px;
}
</style>
<style lang="scss">
// fix css style bug in open el-dialog
.el-popup-parent--hidden {
.fixed-header {
padding-right: 15px;
}
}
</style>

View File

@ -0,0 +1,111 @@
<template>
<div class="navbar">
<hamburger :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
<breadcrumb class="breadcrumb-container" />
</div>
</template>
<script>
import { mapGetters } from 'vuex'
import Breadcrumb from '@/components/Breadcrumb'
import Hamburger from '@/components/Hamburger'
export default {
components: {
Breadcrumb,
Hamburger
},
computed: {
...mapGetters([
'sidebar',
'avatar'
])
},
methods: {
toggleSideBar() {
this.$store.dispatch('app/toggleSideBar')
}
}
}
</script>
<style lang="scss" scoped>
.navbar {
height: 50px;
overflow: hidden;
position: relative;
background: #fff;
box-shadow: 0 1px 4px rgba(0,21,41,.08);
.hamburger-container {
line-height: 46px;
height: 100%;
float: left;
cursor: pointer;
transition: background .3s;
-webkit-tap-highlight-color:transparent;
&:hover {
background: rgba(0, 0, 0, .025)
}
}
.breadcrumb-container {
float: left;
}
.right-menu {
float: right;
height: 100%;
line-height: 50px;
&:focus {
outline: none;
}
.right-menu-item {
display: inline-block;
padding: 0 8px;
height: 100%;
font-size: 18px;
color: #5a5e66;
vertical-align: text-bottom;
&.hover-effect {
cursor: pointer;
transition: background .3s;
&:hover {
background: rgba(0, 0, 0, .025)
}
}
}
.avatar-container {
margin-right: 30px;
.avatar-wrapper {
margin-top: 5px;
position: relative;
.user-avatar {
cursor: pointer;
width: 40px;
height: 40px;
border-radius: 10px;
}
.el-icon-caret-bottom {
cursor: pointer;
position: absolute;
right: -20px;
top: 25px;
font-size: 12px;
}
}
}
}
}
</style>

View File

@ -0,0 +1,26 @@
export default {
computed: {
device() {
return this.$store.state.app.device
}
},
mounted() {
// In order to fix the click on menu on the ios device will trigger the mouseleave bug
// https://github.com/PanJiaChen/vue-element-admin/issues/1135
this.fixBugIniOS()
},
methods: {
fixBugIniOS() {
const $subMenu = this.$refs.subMenu
if ($subMenu) {
const handleMouseleave = $subMenu.handleMouseleave
$subMenu.handleMouseleave = (e) => {
if (this.device === 'mobile') {
return
}
handleMouseleave(e)
}
}
}
}
}

View File

@ -0,0 +1,41 @@
<script>
export default {
name: 'MenuItem',
functional: true,
props: {
icon: {
type: String,
default: ''
},
title: {
type: String,
default: ''
}
},
render(h, context) {
const { icon, title } = context.props
const vnodes = []
if (icon) {
if (icon.includes('el-icon')) {
vnodes.push(<i class={[icon, 'sub-el-icon']} />)
} else {
vnodes.push(<svg-icon icon-class={icon}/>)
}
}
if (title) {
vnodes.push(<span slot='title'>{(title)}</span>)
}
return vnodes
}
}
</script>
<style scoped>
.sub-el-icon {
color: currentColor;
width: 1em;
height: 1em;
}
</style>

Some files were not shown because too many files have changed in this diff Show More