pyxllib 0.3.96__py3-none-any.whl → 0.3.200__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (358) hide show
  1. pyxllib/__init__.py +21 -21
  2. pyxllib/algo/__init__.py +8 -8
  3. pyxllib/algo/disjoint.py +54 -54
  4. pyxllib/algo/geo.py +541 -529
  5. pyxllib/algo/intervals.py +964 -964
  6. pyxllib/algo/matcher.py +389 -311
  7. pyxllib/algo/newbie.py +166 -166
  8. pyxllib/algo/pupil.py +629 -461
  9. pyxllib/algo/shapelylib.py +67 -67
  10. pyxllib/algo/specialist.py +241 -240
  11. pyxllib/algo/stat.py +494 -458
  12. pyxllib/algo/treelib.py +149 -149
  13. pyxllib/algo/unitlib.py +66 -66
  14. {pyxlpr → pyxllib/autogui}/__init__.py +5 -5
  15. pyxllib/autogui/activewin.py +246 -0
  16. pyxllib/autogui/all.py +9 -0
  17. pyxllib/{ext/autogui → autogui}/autogui.py +852 -823
  18. pyxllib/autogui/uiautolib.py +362 -0
  19. pyxllib/{ext/autogui → autogui}/virtualkey.py +102 -102
  20. pyxllib/autogui/wechat.py +827 -0
  21. pyxllib/autogui/wechat_msg.py +421 -0
  22. pyxllib/autogui/wxautolib.py +84 -0
  23. pyxllib/cv/__init__.py +5 -5
  24. pyxllib/cv/expert.py +267 -267
  25. pyxllib/cv/imfile.py +159 -159
  26. pyxllib/cv/imhash.py +39 -39
  27. pyxllib/cv/pupil.py +9 -9
  28. pyxllib/cv/rgbfmt.py +1525 -1525
  29. pyxllib/cv/slidercaptcha.py +137 -0
  30. pyxllib/cv/trackbartools.py +251 -251
  31. pyxllib/cv/xlcvlib.py +1040 -1040
  32. pyxllib/cv/xlpillib.py +423 -423
  33. pyxllib/data/echarts.py +240 -129
  34. pyxllib/data/jsonlib.py +89 -0
  35. pyxllib/data/oss.py +72 -72
  36. pyxllib/data/pglib.py +1127 -643
  37. pyxllib/data/sqlite.py +568 -341
  38. pyxllib/data/sqllib.py +297 -297
  39. pyxllib/ext/JLineViewer.py +505 -492
  40. pyxllib/ext/__init__.py +6 -6
  41. pyxllib/ext/demolib.py +246 -246
  42. pyxllib/ext/drissionlib.py +277 -0
  43. pyxllib/ext/kq5034lib.py +12 -1606
  44. pyxllib/ext/old.py +663 -663
  45. pyxllib/ext/qt.py +449 -449
  46. pyxllib/ext/robustprocfile.py +497 -0
  47. pyxllib/ext/seleniumlib.py +76 -76
  48. pyxllib/ext/tk.py +173 -173
  49. pyxllib/ext/unixlib.py +827 -826
  50. pyxllib/ext/utools.py +351 -338
  51. pyxllib/ext/webhook.py +124 -101
  52. pyxllib/ext/win32lib.py +40 -40
  53. pyxllib/ext/wjxlib.py +88 -0
  54. pyxllib/ext/wpsapi.py +124 -0
  55. pyxllib/ext/xlwork.py +9 -0
  56. pyxllib/ext/yuquelib.py +1105 -173
  57. pyxllib/file/__init__.py +17 -17
  58. pyxllib/file/docxlib.py +761 -761
  59. pyxllib/file/gitlib.py +309 -309
  60. pyxllib/file/libreoffice.py +165 -0
  61. pyxllib/file/movielib.py +148 -139
  62. pyxllib/file/newbie.py +10 -10
  63. pyxllib/file/onenotelib.py +1469 -1469
  64. pyxllib/file/packlib/__init__.py +330 -293
  65. pyxllib/file/packlib/zipfile.py +2441 -2441
  66. pyxllib/file/pdflib.py +426 -426
  67. pyxllib/file/pupil.py +185 -185
  68. pyxllib/file/specialist/__init__.py +685 -685
  69. pyxllib/file/specialist/dirlib.py +799 -799
  70. pyxllib/file/specialist/download.py +193 -186
  71. pyxllib/file/specialist/filelib.py +2829 -2618
  72. pyxllib/file/xlsxlib.py +3131 -2976
  73. pyxllib/file/xlsyncfile.py +341 -0
  74. pyxllib/prog/__init__.py +5 -5
  75. pyxllib/prog/cachetools.py +64 -0
  76. pyxllib/prog/deprecatedlib.py +233 -233
  77. pyxllib/prog/filelock.py +42 -0
  78. pyxllib/prog/ipyexec.py +253 -253
  79. pyxllib/prog/multiprogs.py +940 -0
  80. pyxllib/prog/newbie.py +451 -444
  81. pyxllib/prog/pupil.py +1197 -1128
  82. pyxllib/prog/sitepackages.py +33 -33
  83. pyxllib/prog/specialist/__init__.py +391 -217
  84. pyxllib/prog/specialist/bc.py +203 -200
  85. pyxllib/prog/specialist/browser.py +497 -488
  86. pyxllib/prog/specialist/common.py +347 -347
  87. pyxllib/prog/specialist/datetime.py +199 -131
  88. pyxllib/prog/specialist/tictoc.py +240 -241
  89. pyxllib/prog/specialist/xllog.py +180 -180
  90. pyxllib/prog/xlosenv.py +108 -101
  91. pyxllib/stdlib/__init__.py +17 -17
  92. pyxllib/stdlib/tablepyxl/__init__.py +10 -10
  93. pyxllib/stdlib/tablepyxl/style.py +303 -303
  94. pyxllib/stdlib/tablepyxl/tablepyxl.py +130 -130
  95. pyxllib/text/__init__.py +8 -8
  96. pyxllib/text/ahocorasick.py +39 -39
  97. pyxllib/text/airscript.js +744 -0
  98. pyxllib/text/charclasslib.py +121 -109
  99. pyxllib/text/jiebalib.py +267 -264
  100. pyxllib/text/jinjalib.py +32 -0
  101. pyxllib/text/jsa_ai_prompt.md +271 -0
  102. pyxllib/text/jscode.py +922 -767
  103. pyxllib/text/latex/__init__.py +158 -158
  104. pyxllib/text/levenshtein.py +303 -303
  105. pyxllib/text/nestenv.py +1215 -1215
  106. pyxllib/text/newbie.py +300 -288
  107. pyxllib/text/pupil/__init__.py +8 -8
  108. pyxllib/text/pupil/common.py +1121 -1095
  109. pyxllib/text/pupil/xlalign.py +326 -326
  110. pyxllib/text/pycode.py +47 -47
  111. pyxllib/text/specialist/__init__.py +8 -8
  112. pyxllib/text/specialist/common.py +112 -112
  113. pyxllib/text/specialist/ptag.py +186 -186
  114. pyxllib/text/spellchecker.py +172 -172
  115. pyxllib/text/templates/echart_base.html +11 -0
  116. pyxllib/text/templates/highlight_code.html +17 -0
  117. pyxllib/text/templates/latex_editor.html +103 -0
  118. pyxllib/text/vbacode.py +17 -17
  119. pyxllib/text/xmllib.py +747 -685
  120. pyxllib/xl.py +42 -38
  121. pyxllib/xlcv.py +17 -17
  122. pyxllib-0.3.200.dist-info/METADATA +48 -0
  123. pyxllib-0.3.200.dist-info/RECORD +126 -0
  124. {pyxllib-0.3.96.dist-info → pyxllib-0.3.200.dist-info}/WHEEL +1 -2
  125. {pyxllib-0.3.96.dist-info → pyxllib-0.3.200.dist-info/licenses}/LICENSE +190 -190
  126. pyxllib/ext/autogui/__init__.py +0 -8
  127. pyxllib-0.3.96.dist-info/METADATA +0 -51
  128. pyxllib-0.3.96.dist-info/RECORD +0 -333
  129. pyxllib-0.3.96.dist-info/top_level.txt +0 -2
  130. pyxlpr/ai/__init__.py +0 -5
  131. pyxlpr/ai/clientlib.py +0 -1281
  132. pyxlpr/ai/specialist.py +0 -286
  133. pyxlpr/ai/torch_app.py +0 -172
  134. pyxlpr/ai/xlpaddle.py +0 -655
  135. pyxlpr/ai/xltorch.py +0 -705
  136. pyxlpr/data/__init__.py +0 -11
  137. pyxlpr/data/coco.py +0 -1325
  138. pyxlpr/data/datacls.py +0 -365
  139. pyxlpr/data/datasets.py +0 -200
  140. pyxlpr/data/gptlib.py +0 -1291
  141. pyxlpr/data/icdar/__init__.py +0 -96
  142. pyxlpr/data/icdar/deteval.py +0 -377
  143. pyxlpr/data/icdar/icdar2013.py +0 -341
  144. pyxlpr/data/icdar/iou.py +0 -340
  145. pyxlpr/data/icdar/rrc_evaluation_funcs_1_1.py +0 -463
  146. pyxlpr/data/imtextline.py +0 -473
  147. pyxlpr/data/labelme.py +0 -866
  148. pyxlpr/data/removeline.py +0 -179
  149. pyxlpr/data/specialist.py +0 -57
  150. pyxlpr/eval/__init__.py +0 -85
  151. pyxlpr/paddleocr.py +0 -776
  152. pyxlpr/ppocr/__init__.py +0 -15
  153. pyxlpr/ppocr/configs/rec/multi_language/generate_multi_language_configs.py +0 -226
  154. pyxlpr/ppocr/data/__init__.py +0 -135
  155. pyxlpr/ppocr/data/imaug/ColorJitter.py +0 -26
  156. pyxlpr/ppocr/data/imaug/__init__.py +0 -67
  157. pyxlpr/ppocr/data/imaug/copy_paste.py +0 -170
  158. pyxlpr/ppocr/data/imaug/east_process.py +0 -437
  159. pyxlpr/ppocr/data/imaug/gen_table_mask.py +0 -244
  160. pyxlpr/ppocr/data/imaug/iaa_augment.py +0 -114
  161. pyxlpr/ppocr/data/imaug/label_ops.py +0 -789
  162. pyxlpr/ppocr/data/imaug/make_border_map.py +0 -184
  163. pyxlpr/ppocr/data/imaug/make_pse_gt.py +0 -106
  164. pyxlpr/ppocr/data/imaug/make_shrink_map.py +0 -126
  165. pyxlpr/ppocr/data/imaug/operators.py +0 -433
  166. pyxlpr/ppocr/data/imaug/pg_process.py +0 -906
  167. pyxlpr/ppocr/data/imaug/randaugment.py +0 -143
  168. pyxlpr/ppocr/data/imaug/random_crop_data.py +0 -239
  169. pyxlpr/ppocr/data/imaug/rec_img_aug.py +0 -533
  170. pyxlpr/ppocr/data/imaug/sast_process.py +0 -777
  171. pyxlpr/ppocr/data/imaug/text_image_aug/__init__.py +0 -17
  172. pyxlpr/ppocr/data/imaug/text_image_aug/augment.py +0 -120
  173. pyxlpr/ppocr/data/imaug/text_image_aug/warp_mls.py +0 -168
  174. pyxlpr/ppocr/data/lmdb_dataset.py +0 -115
  175. pyxlpr/ppocr/data/pgnet_dataset.py +0 -104
  176. pyxlpr/ppocr/data/pubtab_dataset.py +0 -107
  177. pyxlpr/ppocr/data/simple_dataset.py +0 -372
  178. pyxlpr/ppocr/losses/__init__.py +0 -61
  179. pyxlpr/ppocr/losses/ace_loss.py +0 -52
  180. pyxlpr/ppocr/losses/basic_loss.py +0 -135
  181. pyxlpr/ppocr/losses/center_loss.py +0 -88
  182. pyxlpr/ppocr/losses/cls_loss.py +0 -30
  183. pyxlpr/ppocr/losses/combined_loss.py +0 -67
  184. pyxlpr/ppocr/losses/det_basic_loss.py +0 -208
  185. pyxlpr/ppocr/losses/det_db_loss.py +0 -80
  186. pyxlpr/ppocr/losses/det_east_loss.py +0 -63
  187. pyxlpr/ppocr/losses/det_pse_loss.py +0 -149
  188. pyxlpr/ppocr/losses/det_sast_loss.py +0 -121
  189. pyxlpr/ppocr/losses/distillation_loss.py +0 -272
  190. pyxlpr/ppocr/losses/e2e_pg_loss.py +0 -140
  191. pyxlpr/ppocr/losses/kie_sdmgr_loss.py +0 -113
  192. pyxlpr/ppocr/losses/rec_aster_loss.py +0 -99
  193. pyxlpr/ppocr/losses/rec_att_loss.py +0 -39
  194. pyxlpr/ppocr/losses/rec_ctc_loss.py +0 -44
  195. pyxlpr/ppocr/losses/rec_enhanced_ctc_loss.py +0 -70
  196. pyxlpr/ppocr/losses/rec_nrtr_loss.py +0 -30
  197. pyxlpr/ppocr/losses/rec_sar_loss.py +0 -28
  198. pyxlpr/ppocr/losses/rec_srn_loss.py +0 -47
  199. pyxlpr/ppocr/losses/table_att_loss.py +0 -109
  200. pyxlpr/ppocr/metrics/__init__.py +0 -44
  201. pyxlpr/ppocr/metrics/cls_metric.py +0 -45
  202. pyxlpr/ppocr/metrics/det_metric.py +0 -82
  203. pyxlpr/ppocr/metrics/distillation_metric.py +0 -73
  204. pyxlpr/ppocr/metrics/e2e_metric.py +0 -86
  205. pyxlpr/ppocr/metrics/eval_det_iou.py +0 -274
  206. pyxlpr/ppocr/metrics/kie_metric.py +0 -70
  207. pyxlpr/ppocr/metrics/rec_metric.py +0 -75
  208. pyxlpr/ppocr/metrics/table_metric.py +0 -50
  209. pyxlpr/ppocr/modeling/architectures/__init__.py +0 -32
  210. pyxlpr/ppocr/modeling/architectures/base_model.py +0 -88
  211. pyxlpr/ppocr/modeling/architectures/distillation_model.py +0 -60
  212. pyxlpr/ppocr/modeling/backbones/__init__.py +0 -54
  213. pyxlpr/ppocr/modeling/backbones/det_mobilenet_v3.py +0 -268
  214. pyxlpr/ppocr/modeling/backbones/det_resnet_vd.py +0 -246
  215. pyxlpr/ppocr/modeling/backbones/det_resnet_vd_sast.py +0 -285
  216. pyxlpr/ppocr/modeling/backbones/e2e_resnet_vd_pg.py +0 -265
  217. pyxlpr/ppocr/modeling/backbones/kie_unet_sdmgr.py +0 -186
  218. pyxlpr/ppocr/modeling/backbones/rec_mobilenet_v3.py +0 -138
  219. pyxlpr/ppocr/modeling/backbones/rec_mv1_enhance.py +0 -258
  220. pyxlpr/ppocr/modeling/backbones/rec_nrtr_mtb.py +0 -48
  221. pyxlpr/ppocr/modeling/backbones/rec_resnet_31.py +0 -210
  222. pyxlpr/ppocr/modeling/backbones/rec_resnet_aster.py +0 -143
  223. pyxlpr/ppocr/modeling/backbones/rec_resnet_fpn.py +0 -307
  224. pyxlpr/ppocr/modeling/backbones/rec_resnet_vd.py +0 -286
  225. pyxlpr/ppocr/modeling/heads/__init__.py +0 -54
  226. pyxlpr/ppocr/modeling/heads/cls_head.py +0 -52
  227. pyxlpr/ppocr/modeling/heads/det_db_head.py +0 -118
  228. pyxlpr/ppocr/modeling/heads/det_east_head.py +0 -121
  229. pyxlpr/ppocr/modeling/heads/det_pse_head.py +0 -37
  230. pyxlpr/ppocr/modeling/heads/det_sast_head.py +0 -128
  231. pyxlpr/ppocr/modeling/heads/e2e_pg_head.py +0 -253
  232. pyxlpr/ppocr/modeling/heads/kie_sdmgr_head.py +0 -206
  233. pyxlpr/ppocr/modeling/heads/multiheadAttention.py +0 -163
  234. pyxlpr/ppocr/modeling/heads/rec_aster_head.py +0 -393
  235. pyxlpr/ppocr/modeling/heads/rec_att_head.py +0 -202
  236. pyxlpr/ppocr/modeling/heads/rec_ctc_head.py +0 -88
  237. pyxlpr/ppocr/modeling/heads/rec_nrtr_head.py +0 -826
  238. pyxlpr/ppocr/modeling/heads/rec_sar_head.py +0 -402
  239. pyxlpr/ppocr/modeling/heads/rec_srn_head.py +0 -280
  240. pyxlpr/ppocr/modeling/heads/self_attention.py +0 -406
  241. pyxlpr/ppocr/modeling/heads/table_att_head.py +0 -246
  242. pyxlpr/ppocr/modeling/necks/__init__.py +0 -32
  243. pyxlpr/ppocr/modeling/necks/db_fpn.py +0 -111
  244. pyxlpr/ppocr/modeling/necks/east_fpn.py +0 -188
  245. pyxlpr/ppocr/modeling/necks/fpn.py +0 -138
  246. pyxlpr/ppocr/modeling/necks/pg_fpn.py +0 -314
  247. pyxlpr/ppocr/modeling/necks/rnn.py +0 -92
  248. pyxlpr/ppocr/modeling/necks/sast_fpn.py +0 -284
  249. pyxlpr/ppocr/modeling/necks/table_fpn.py +0 -110
  250. pyxlpr/ppocr/modeling/transforms/__init__.py +0 -28
  251. pyxlpr/ppocr/modeling/transforms/stn.py +0 -135
  252. pyxlpr/ppocr/modeling/transforms/tps.py +0 -308
  253. pyxlpr/ppocr/modeling/transforms/tps_spatial_transformer.py +0 -156
  254. pyxlpr/ppocr/optimizer/__init__.py +0 -61
  255. pyxlpr/ppocr/optimizer/learning_rate.py +0 -228
  256. pyxlpr/ppocr/optimizer/lr_scheduler.py +0 -49
  257. pyxlpr/ppocr/optimizer/optimizer.py +0 -160
  258. pyxlpr/ppocr/optimizer/regularizer.py +0 -52
  259. pyxlpr/ppocr/postprocess/__init__.py +0 -55
  260. pyxlpr/ppocr/postprocess/cls_postprocess.py +0 -33
  261. pyxlpr/ppocr/postprocess/db_postprocess.py +0 -234
  262. pyxlpr/ppocr/postprocess/east_postprocess.py +0 -143
  263. pyxlpr/ppocr/postprocess/locality_aware_nms.py +0 -200
  264. pyxlpr/ppocr/postprocess/pg_postprocess.py +0 -52
  265. pyxlpr/ppocr/postprocess/pse_postprocess/__init__.py +0 -15
  266. pyxlpr/ppocr/postprocess/pse_postprocess/pse/__init__.py +0 -29
  267. pyxlpr/ppocr/postprocess/pse_postprocess/pse/setup.py +0 -14
  268. pyxlpr/ppocr/postprocess/pse_postprocess/pse_postprocess.py +0 -118
  269. pyxlpr/ppocr/postprocess/rec_postprocess.py +0 -654
  270. pyxlpr/ppocr/postprocess/sast_postprocess.py +0 -355
  271. pyxlpr/ppocr/tools/__init__.py +0 -14
  272. pyxlpr/ppocr/tools/eval.py +0 -83
  273. pyxlpr/ppocr/tools/export_center.py +0 -77
  274. pyxlpr/ppocr/tools/export_model.py +0 -129
  275. pyxlpr/ppocr/tools/infer/predict_cls.py +0 -151
  276. pyxlpr/ppocr/tools/infer/predict_det.py +0 -300
  277. pyxlpr/ppocr/tools/infer/predict_e2e.py +0 -169
  278. pyxlpr/ppocr/tools/infer/predict_rec.py +0 -414
  279. pyxlpr/ppocr/tools/infer/predict_system.py +0 -204
  280. pyxlpr/ppocr/tools/infer/utility.py +0 -629
  281. pyxlpr/ppocr/tools/infer_cls.py +0 -83
  282. pyxlpr/ppocr/tools/infer_det.py +0 -134
  283. pyxlpr/ppocr/tools/infer_e2e.py +0 -122
  284. pyxlpr/ppocr/tools/infer_kie.py +0 -153
  285. pyxlpr/ppocr/tools/infer_rec.py +0 -146
  286. pyxlpr/ppocr/tools/infer_table.py +0 -107
  287. pyxlpr/ppocr/tools/program.py +0 -596
  288. pyxlpr/ppocr/tools/test_hubserving.py +0 -117
  289. pyxlpr/ppocr/tools/train.py +0 -163
  290. pyxlpr/ppocr/tools/xlprog.py +0 -748
  291. pyxlpr/ppocr/utils/EN_symbol_dict.txt +0 -94
  292. pyxlpr/ppocr/utils/__init__.py +0 -24
  293. pyxlpr/ppocr/utils/dict/ar_dict.txt +0 -117
  294. pyxlpr/ppocr/utils/dict/arabic_dict.txt +0 -162
  295. pyxlpr/ppocr/utils/dict/be_dict.txt +0 -145
  296. pyxlpr/ppocr/utils/dict/bg_dict.txt +0 -140
  297. pyxlpr/ppocr/utils/dict/chinese_cht_dict.txt +0 -8421
  298. pyxlpr/ppocr/utils/dict/cyrillic_dict.txt +0 -163
  299. pyxlpr/ppocr/utils/dict/devanagari_dict.txt +0 -167
  300. pyxlpr/ppocr/utils/dict/en_dict.txt +0 -63
  301. pyxlpr/ppocr/utils/dict/fa_dict.txt +0 -136
  302. pyxlpr/ppocr/utils/dict/french_dict.txt +0 -136
  303. pyxlpr/ppocr/utils/dict/german_dict.txt +0 -143
  304. pyxlpr/ppocr/utils/dict/hi_dict.txt +0 -162
  305. pyxlpr/ppocr/utils/dict/it_dict.txt +0 -118
  306. pyxlpr/ppocr/utils/dict/japan_dict.txt +0 -4399
  307. pyxlpr/ppocr/utils/dict/ka_dict.txt +0 -153
  308. pyxlpr/ppocr/utils/dict/korean_dict.txt +0 -3688
  309. pyxlpr/ppocr/utils/dict/latin_dict.txt +0 -185
  310. pyxlpr/ppocr/utils/dict/mr_dict.txt +0 -153
  311. pyxlpr/ppocr/utils/dict/ne_dict.txt +0 -153
  312. pyxlpr/ppocr/utils/dict/oc_dict.txt +0 -96
  313. pyxlpr/ppocr/utils/dict/pu_dict.txt +0 -130
  314. pyxlpr/ppocr/utils/dict/rs_dict.txt +0 -91
  315. pyxlpr/ppocr/utils/dict/rsc_dict.txt +0 -134
  316. pyxlpr/ppocr/utils/dict/ru_dict.txt +0 -125
  317. pyxlpr/ppocr/utils/dict/ta_dict.txt +0 -128
  318. pyxlpr/ppocr/utils/dict/table_dict.txt +0 -277
  319. pyxlpr/ppocr/utils/dict/table_structure_dict.txt +0 -2759
  320. pyxlpr/ppocr/utils/dict/te_dict.txt +0 -151
  321. pyxlpr/ppocr/utils/dict/ug_dict.txt +0 -114
  322. pyxlpr/ppocr/utils/dict/uk_dict.txt +0 -142
  323. pyxlpr/ppocr/utils/dict/ur_dict.txt +0 -137
  324. pyxlpr/ppocr/utils/dict/xi_dict.txt +0 -110
  325. pyxlpr/ppocr/utils/dict90.txt +0 -90
  326. pyxlpr/ppocr/utils/e2e_metric/Deteval.py +0 -574
  327. pyxlpr/ppocr/utils/e2e_metric/polygon_fast.py +0 -83
  328. pyxlpr/ppocr/utils/e2e_utils/extract_batchsize.py +0 -87
  329. pyxlpr/ppocr/utils/e2e_utils/extract_textpoint_fast.py +0 -457
  330. pyxlpr/ppocr/utils/e2e_utils/extract_textpoint_slow.py +0 -592
  331. pyxlpr/ppocr/utils/e2e_utils/pgnet_pp_utils.py +0 -162
  332. pyxlpr/ppocr/utils/e2e_utils/visual.py +0 -162
  333. pyxlpr/ppocr/utils/en_dict.txt +0 -95
  334. pyxlpr/ppocr/utils/gen_label.py +0 -81
  335. pyxlpr/ppocr/utils/ic15_dict.txt +0 -36
  336. pyxlpr/ppocr/utils/iou.py +0 -54
  337. pyxlpr/ppocr/utils/logging.py +0 -69
  338. pyxlpr/ppocr/utils/network.py +0 -84
  339. pyxlpr/ppocr/utils/ppocr_keys_v1.txt +0 -6623
  340. pyxlpr/ppocr/utils/profiler.py +0 -110
  341. pyxlpr/ppocr/utils/save_load.py +0 -150
  342. pyxlpr/ppocr/utils/stats.py +0 -72
  343. pyxlpr/ppocr/utils/utility.py +0 -80
  344. pyxlpr/ppstructure/__init__.py +0 -13
  345. pyxlpr/ppstructure/predict_system.py +0 -187
  346. pyxlpr/ppstructure/table/__init__.py +0 -13
  347. pyxlpr/ppstructure/table/eval_table.py +0 -72
  348. pyxlpr/ppstructure/table/matcher.py +0 -192
  349. pyxlpr/ppstructure/table/predict_structure.py +0 -136
  350. pyxlpr/ppstructure/table/predict_table.py +0 -221
  351. pyxlpr/ppstructure/table/table_metric/__init__.py +0 -16
  352. pyxlpr/ppstructure/table/table_metric/parallel.py +0 -51
  353. pyxlpr/ppstructure/table/table_metric/table_metric.py +0 -247
  354. pyxlpr/ppstructure/table/tablepyxl/__init__.py +0 -13
  355. pyxlpr/ppstructure/table/tablepyxl/style.py +0 -283
  356. pyxlpr/ppstructure/table/tablepyxl/tablepyxl.py +0 -118
  357. pyxlpr/ppstructure/utility.py +0 -71
  358. pyxlpr/xlai.py +0 -10
pyxlpr/ai/clientlib.py DELETED
@@ -1,1281 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- # @Author : 陈坤泽
4
- # @Email : 877362867@qq.com
5
- # @Date : 2020/05/30 21:14
6
-
7
- """
8
- 百度人工智能API,常用URL
9
- 使用文档:https://cloud.baidu.com/doc/OCR/s/Ek3h7xypm
10
- 调用次数:https://console.bce.baidu.com/ai/?_=1653139065257#/ai/ocr/overview/index
11
-
12
-
13
- """
14
- import os
15
- import base64
16
- import json
17
- import pprint
18
- import statistics
19
- import time
20
-
21
- import cv2
22
- import numpy as np
23
- import requests
24
-
25
- from pyxllib.prog.newbie import round_int
26
- from pyxllib.prog.pupil import check_install_package, is_url
27
- from pyxllib.prog.xlosenv import XlOsEnv
28
- from pyxllib.algo.geo import xywh2ltrb, rect_bounds
29
- from pyxllib.file.specialist import XlPath, get_etag
30
- from pyxllib.cv.expert import xlcv
31
-
32
-
33
- def __1_转类labelme标注():
34
- """ 将百度api获得的各种业务结果,转成类似labelme的标注格式
35
-
36
- 统一成一种风格,易分析的结构
37
- """
38
-
39
-
40
- def loc2points(loc, ratio=1):
41
- """ 百度的location格式转为 {'points': [[a, b], [c, d]], 'shape_type: 'rectangle'} """
42
- # 目前关注到的都是矩形,不知道有没可能有其他格式
43
- ltrb = xywh2ltrb([loc['left'], loc['top'], loc['width'], loc['height']])
44
- if ratio != 1:
45
- ltrb = [x * ratio for x in ltrb]
46
- l, t, r, b = round_int(ltrb, ndim=1)
47
- return {'points': [[l, t], [r, b]],
48
- 'shape_type': 'rectangle'}
49
-
50
-
51
- def loc2points2(loc, ratio=1):
52
- """ 百度的location格式转为 {'points': [[a, b], [c, d]], 'shape_type: 'rectangle'} """
53
- # 目前关注到的都是矩形,不知道有没可能有其他格式
54
- ltrb = xywh2ltrb([loc['left'], loc['top'], loc['right'] - loc['left'], loc['bottom'] - loc['top']])
55
- if ratio != 1:
56
- ltrb = [x * ratio for x in ltrb]
57
- l, t, r, b = round_int(ltrb, ndim=1)
58
- return {'points': [[l, t], [r, b]],
59
- 'shape_type': 'rectangle'}
60
-
61
-
62
- def polygon2rect(pts):
63
- l, t, r, b = rect_bounds(pts)
64
- return [[l, t], [r, b]]
65
-
66
-
67
- def zoom_point(pt, ratio):
68
- """ 返回的还是{x: 123, y: 456}的字典结构 """
69
- if ratio != 1:
70
- return {k: round_int(v * ratio) for k, v in pt.items()}
71
- return pt
72
-
73
-
74
- def zoom_point2(pt, ratio):
75
- """ 输入x,y的字典坐标,返回的还是[123, 456]的list结构 """
76
- pt = [pt['x'], pt['y']]
77
- if ratio != 1:
78
- return [round_int(v * ratio) for v in pt]
79
- return pt
80
-
81
-
82
- def zoom_labelme(d, ratio):
83
- """ 对labelme的标注进行缩放 """
84
- ratio2 = 1 / ratio
85
- for sp in d['shapes']:
86
- sp['points'] = [[round_int(p[0] * ratio2), round_int(p[1] * ratio2)] for p in sp['points']]
87
- d['imageHeight'] = round_int(d['imageHeight'] * ratio2)
88
- d['imageWidth'] = round_int(d['imageWidth'] * ratio2)
89
- return d
90
-
91
-
92
- def labelmelike_extend_args(core_func):
93
- """ 扩展 main_func 函数,支持一些通用上下游切面功能
94
-
95
- 支持 main_keys,主要数据字段名称
96
- 支持 remove_keys,批量移除一些不需要的参数值
97
- """
98
-
99
- def wrapper(data, ratio, main_key, remove_keys=None, *, clear_empty_shape=False):
100
- """
101
- :param clear_empty_shape: 在考虑要不要把清除空shape,四边形转矩形等功能写到这里,暂时还未写对应功能
102
- """
103
- # 1 转主要的数据结构
104
- if main_key in data:
105
- data['shapes'] = core_func(data[main_key], ratio)
106
-
107
- # 2 删除不需要的键值
108
- if remove_keys is None:
109
- _remove_keys = set()
110
- elif not isinstance(remove_keys, (list, tuple, set)):
111
- _remove_keys = [remove_keys]
112
- else:
113
- _remove_keys = remove_keys
114
- for k in ({main_key} | set(_remove_keys)):
115
- if k in data:
116
- del data[k]
117
-
118
- return data
119
-
120
- return wrapper
121
-
122
-
123
- class ToLabelmeLike:
124
- """ 注意配合装饰器的使用
125
- 这里每个函数,只要实现输入核心识别结果清单,返回shapes的代码即可。上下游一些切面操作是统一的。
126
- """
127
-
128
- @staticmethod
129
- @labelmelike_extend_args
130
- def list_word(ls, ratio):
131
- shapes = []
132
- for w in ls:
133
- shape = {}
134
- if 'location' in w:
135
- shape.update(loc2points(w['location'], ratio))
136
- if 'words' in w:
137
- # shape['label'] = json.dumps({'text': x['words']}, ensure_ascii=False)
138
- shape['label'] = {'text': w['words']} # 不转字符串
139
- shapes.append(shape)
140
- return shapes
141
-
142
- @staticmethod
143
- @labelmelike_extend_args
144
- def list_word2(ls, ratio):
145
- shapes = []
146
- for w in ls:
147
- shape = {}
148
- shape.update(loc2points(w['words']['words_location'], ratio))
149
- shape['label'] = {'text': w['words']['word'], 'category': w['words_type']}
150
- shapes.append(shape)
151
- return shapes
152
-
153
- @staticmethod
154
- @labelmelike_extend_args
155
- def dict_word(d, ratio):
156
- shapes = []
157
- for k, w in d.items():
158
- shape = {'label': {'category': k}}
159
- if 'location' in w:
160
- shape.update(loc2points(w['location'], ratio))
161
- if 'words' in w:
162
- shape['label']['text'] = w['words']
163
- shapes.append(shape)
164
- return shapes
165
-
166
- @staticmethod
167
- @labelmelike_extend_args
168
- def dict_str(d, ratio):
169
- return [{'label': {'text': v, 'category': k}} for k, v in d.items()]
170
-
171
- @staticmethod
172
- @labelmelike_extend_args
173
- def dict_strs(d, ratio):
174
- shapes = []
175
- for k, texts in d.items():
176
- shapes.append({'label': {'category': k, 'text': ','.join(texts)}})
177
- return shapes
178
-
179
-
180
- def __2_定制不同输出格式():
181
- pass
182
-
183
-
184
- class XlAiClient:
185
- """
186
- 封装该类
187
- 目的1:合并输入文件和url的识别
188
- 目的2:带透明底的png百度api识别不了,要先转成RGB格式
189
- """
190
- META_OPTS_NAME = {'record_files', # 是否记录传入的图片等数据
191
- 'record_xlapi', # 是否记录api处理结果
192
- 'use_exists_xlapi', # 是否使用已有的api结果
193
- 'record_xlserver', # 是否记录调用纪录
194
- }
195
-
196
- def __init__(self, auto_login=True, check=True):
197
- # 1 默认值
198
- self.db = None
199
-
200
- self._aipocr = None
201
-
202
- self._mathpix_header = None
203
-
204
- self._priu_header = None
205
- self._priu_host = None
206
-
207
- # 2 如果环境变量预存了账号信息,自动加载使用
208
- accounts = XlOsEnv.get('XlAiAccounts', decoding=True)
209
- if accounts and auto_login:
210
- if 'aipocr' in accounts:
211
- self.login_aipocr(**accounts['aipocr'])
212
- if 'mathpix' in accounts:
213
- self.login_mathpix(**accounts['mathpix'])
214
- if 'priu' in accounts:
215
- self.login_priu(**accounts['priu'], check=check)
216
-
217
- def __A1_登录账号(self):
218
- pass
219
-
220
- def set_database(self, db):
221
- """ 是否关联数据库,查找已运行过的结果,或存储运行结果
222
-
223
- from pyxllib.data.pglib import XlprDb
224
- db = XlprDb.connect()
225
- self.setup_database(db)
226
- """
227
- self.db = db
228
-
229
- def login_aipocr(self, app_id, api_key, secret_key):
230
- """
231
- 注:带透明底的png百度api识别不了,要先转成RGB格式
232
- """
233
- check_install_package('aip', 'baidu-aip')
234
- import aip
235
-
236
- self._aipocr = aip.AipOcr(str(app_id), api_key, secret_key)
237
-
238
- def login_mathpix(self, app_id, app_key):
239
- self._mathpix_header = {'Content-type': 'application/json'}
240
- self._mathpix_header.update({'app_id': app_id, 'app_key': app_key})
241
-
242
- def login_priu(self, token, host=None, *, check=True):
243
- """ 福建省模式识别与图像理解重点实验室
244
-
245
- :param str|list[str] host:
246
- str, 主机IP,比如'118.195.202.82'
247
- list, 也可以输入一个列表,会从左到右依次尝试链接,使用第一个能成功链接的ip,常用语优先选用局域网,找不到再使用公网接口
248
- """
249
- self._priu_header = {'Content-type': 'application/json'}
250
- self._priu_header.update({'Token': token})
251
-
252
- if host is None:
253
- # 优先尝试局域网链接,如果失败则尝试公网链接。公网默认用https,如果需要效率可以自己输入http的host。
254
- hosts = ['172.16.170.136', 'https://xmutpriu.com']
255
- elif isinstance(host, str):
256
- hosts = [host]
257
- elif isinstance(host, (list, tuple)):
258
- hosts = host
259
- else:
260
- raise TypeError
261
-
262
- # 确保都有http或https前缀
263
- for i, host in enumerate(hosts):
264
- if 'http' not in host:
265
- hosts[i] = f'http://{host}'
266
-
267
- if check:
268
- connent = False
269
- for host in hosts:
270
- try:
271
- if '欢迎来到 厦门理工' in requests.get(f'{host}/test_page', timeout=5).text:
272
- self._priu_host = host
273
- connent = True
274
- break
275
- except (requests.exceptions.ConnectionError, requests.exceptions.ReadTimeout):
276
- continue
277
-
278
- if not connent:
279
- raise requests.exceptions.ConnectionError('PRIU接口登录失败')
280
- return connent
281
- else:
282
- self._priu_host = hosts[0] # 不检查的场景,一般都是局域网内使用
283
- return None
284
-
285
- def __A2_调整图片和关联数据库(self):
286
- pass
287
-
288
- @classmethod
289
- def adjust_image(cls, in_, flags=1, *, b64decode=True, to_buffer=True, b64encode=False,
290
- min_length=15, max_length=4096,
291
- limit_b64buffer_size=4 * 1024 ** 2):
292
- """ 这里是使用API接口,比较通用的一套图片处理操作
293
-
294
- :param in_: 可以是本地文件,也可以是图片url地址,也可以是Image对象
295
- 注意这个函数,输入是url,也会获取重置图片数据上传
296
- 如果为了效率明确只传url,可以用aip.AipOcr原生的相关url函数
297
- :param b64decode: 如果输入是bytes类型,是否要用b64解码,默认需要
298
- :return: 返回图片文件二进制值的buffer, 缩放系数(小余1是缩小,大于1是放大)
299
- """
300
- # 1 取不同来源的数据
301
- # 下面应该是比较通用的一套操作,如果有特殊接口,可以另外处理,不一定要通过该接口处理图片
302
- if isinstance(in_, bytes):
303
- im = xlcv.read_from_buffer(in_, flags, b64decode=b64decode)
304
- elif is_url(in_):
305
- im = xlcv.read_from_url(in_, flags)
306
- else:
307
- im = xlcv.read(in_, flags)
308
- origin_height = im.shape[0]
309
-
310
- if im.dtype == 'uint16':
311
- im = cv2.convertScaleAbs(im)
312
-
313
- # 2 图片尺寸不符合要求,要缩放
314
- if min_length or max_length:
315
- im = xlcv.adjust_shape(im, min_length, max_length)
316
-
317
- # 3 图片文件不能过大,要调整
318
- if limit_b64buffer_size:
319
- # b64后大小固定会变4/3,所以留给原文件的大小是要缩水,只有0.75;再以防万一总不能卡得刚刚好,所以设为0.74
320
- im = xlcv.reduce_filesize(im, limit_b64buffer_size * 0.74)
321
- current_height = im.shape[0]
322
-
323
- if to_buffer:
324
- im = xlcv.to_buffer(im, '.jpg', b64encode=b64encode)
325
- ratio = current_height / origin_height
326
- return im, ratio
327
-
328
- def _divide_options_with_meta(self, options, meta_opts):
329
- """ 会改变原始输入的两个字典值,但是新返回的才是真正有效的字典 """
330
- options = options or {} # 这里也要先处理,防止options是None类型
331
- meta_opts = meta_opts or {} # 这里也要先处理,防止是None类型
332
-
333
- for name in self.META_OPTS_NAME:
334
- if name in options:
335
- meta_opts[name] = options[name]
336
- del options[name]
337
-
338
- options = options or {}
339
- options = {k: options[k] for k in sorted(options.keys())} # 对参数进行排序,方便记录到数据库后标记唯一
340
-
341
- return options, meta_opts
342
-
343
- def run_aipocr_with_db(self, func, buffer, options=None, **meta_opts):
344
- """ 这一套主要是适配百度视觉api接口的情况,基本都是输入一个buffer和一个options
345
- 如果自己模型有特殊接口范式,可以额外定制,比如 run_textapi_with_db 等,可以拷贝这个函数后做定制微调
346
-
347
- :param func: 被封装的带执行的api函数
348
- :param buffer: 图片二进制数据
349
- :param options: 执行api功能的配套采纳数
350
- :param meta_opts:
351
- record_files: 是否保存数据文件
352
- False, 0,表示不存储
353
- True,表示存储,但默认只存储4MB以内的文件
354
- int,可以写一个整数,表示只存储多大Byte范围内的文件
355
- record_xlapi: 新结果是否记录到数据库
356
- use_exists_xlapi: 如果数据库里已有记录,是否直接复用
357
- 注意看函数实现,但这个机制生效已经获得res的时候,变不会显式执行record_files
358
- 这是出于效率的考虑,一般情况下,这种应该是已经存储过文件了
359
- 如果要怕以前执行过api但没存储files,可以关闭use_exists_xlapi,就可以显式重新执行保存一次
360
- mode_name: 可以指定存入数据库的功能名,默认用func的名称
361
- """
362
- # 1 参数处理
363
- options, meta_opts = self._divide_options_with_meta(options, meta_opts)
364
- if self.db is None: # 没有数据库的时候直接执行函数返回结果就好
365
- return func(buffer, options)
366
-
367
- # 以下元参数默认值,根据不同的api接口需求,可以设置不同的默认值
368
- record_files = meta_opts.get('record_files', True) # 是否保存数据文件
369
- if record_files is True:
370
- record_files = 4 * 1024 ** 2
371
- record_xlapi = meta_opts.get('record_xlapi', True)
372
- use_exists_xlapi = meta_opts.get('use_exists_xlapi', True)
373
- mode_name = meta_opts.get('mode_name', func.__name__)
374
-
375
- image_etag = None # 先不计算etag,只在需要的时候再计算
376
- res = None # api结果
377
-
378
- # 2 核心函数
379
- if use_exists_xlapi: # 定义如何获取已有的识别结果
380
- image_etag = image_etag or get_etag(buffer) # trick: 使用这个机制确保etag从头到尾不会重复计算,需要的话只会计算一次
381
- res = self.db.get_xlapi_record(mode=mode_name, image=image_etag, **options)
382
-
383
- # 否则调用百度的接口识别
384
- # TODO 这里使用协程逻辑最合理但配置麻烦,需要func底层等做协程的适配支持
385
- # 使用多线程测试了并没有更快,也发现主要耗时是post,数据库不会花太多时间,就先不改动了
386
- # 等以后数据库大了,看运行是否会慢,可以再测试是否有必要弄协程
387
- if res is None or 'error_code' in res:
388
- tt = time.time()
389
- res = func(buffer, options)
390
- elapse_ms = round_int(1000 * (time.time() - tt))
391
-
392
- if len(buffer) < record_files: # 定义数据的缓存方式
393
- image_etag = image_etag or get_etag(buffer)
394
- self.db.insert_row2files(buffer, etag=image_etag, name='.jpg')
395
-
396
- if record_xlapi: # 定义api的执行结果的保存方式
397
- image_etag = image_etag or get_etag(buffer)
398
- input = {'mode': mode_name, 'image': image_etag}
399
- if options:
400
- input.update(options)
401
- xlapi_id = self.db.insert_row2xlapi(input, res, elapse_ms, on_conflict='REPLACE')
402
- res['xlapi_id'] = xlapi_id
403
-
404
- # 3 收尾
405
- if 'log_id' in res: # 有xlapi_id的标记,就不用百度原本的log_id了
406
- del res['log_id']
407
-
408
- return res
409
-
410
- def __B1_通用(self):
411
- pass
412
-
413
- def general(self, image, **options):
414
- """ 通用文字识别(标准含位置版): https://cloud.baidu.com/doc/OCR/s/vk3h7y58v
415
- 500次/天赠送 + 超出按量计费
416
-
417
- 注意只要ratio!=1涉及到缩放的,偏移误差是会变大的~~
418
- """
419
- buffer, ratio = self.adjust_image(image)
420
- result_dict = self.run_aipocr_with_db(self._aipocr.general, buffer, options)
421
- result_dict = ToLabelmeLike.list_word(result_dict, 1 / ratio, 'words_result', 'words_result_num')
422
- return result_dict
423
-
424
- def basicGeneral(self, image, **options):
425
- """ 通用文字识别(标准版): https://cloud.baidu.com/doc/OCR/s/zk3h7xz52
426
- 5万次/天赠送 + 超出按量计费
427
- """
428
- buffer, ratio = self.adjust_image(image)
429
- result_dict = self.run_aipocr_with_db(self._aipocr.basicGeneral, buffer, options)
430
- result_dict = ToLabelmeLike.list_word(result_dict, 1 / ratio, 'words_result', 'words_result_num')
431
- return result_dict
432
-
433
- def accurate(self, image, **options):
434
- """ 通用文字识别(高精度含位置版): https://cloud.baidu.com/doc/OCR/s/tk3h7y2aq """
435
- sz = 10 * 1024 ** 2
436
- buffer, ratio = self.adjust_image(image, max_length=8192, limit_b64buffer_size=sz, to_buffer=True)
437
- result_dict = self.run_aipocr_with_db(self._aipocr.accurate, buffer, options, save_buffer_threshold_size=sz)
438
- result_dict = ToLabelmeLike.list_word(result_dict, 1 / ratio, 'words_result', 'words_result_num')
439
- return result_dict
440
-
441
- def basicAccurate(self, image, **options):
442
- """ 通用文字识别(高精度版): https://cloud.baidu.com/doc/OCR/s/1k3h7y3db """
443
- sz = 10 * 1024 ** 2
444
- buffer, ratio = self.adjust_image(image, max_length=8192, limit_b64buffer_size=sz, to_buffer=True)
445
- result_dict = self.run_aipocr_with_db(self._aipocr.basicAccurate, buffer, options,
446
- save_buffer_threshold_size=sz)
447
- result_dict = ToLabelmeLike.list_word(result_dict, 1 / ratio, 'words_result', 'words_result_num')
448
- return result_dict
449
-
450
- def webimageLoc(self, image, **options):
451
- """ 网络图片文字识别(含位置版): https://cloud.baidu.com/doc/OCR/s/Nkaz574we """
452
- buffer, ratio = self.adjust_image(image)
453
- result_dict = self.run_aipocr_with_db(self._aipocr.webimageLoc, buffer, options)
454
- result_dict = ToLabelmeLike.list_word(result_dict, 1 / ratio, 'words_result', 'words_result_num')
455
- return result_dict
456
-
457
- def webImage(self, image, **options):
458
- """ 网络图片文字识别: https://cloud.baidu.com/doc/OCR/s/Sk3h7xyad """
459
- buffer, ratio = self.adjust_image(image)
460
- result_dict = self.run_aipocr_with_db(self._aipocr.webImage, buffer, options)
461
- result_dict = ToLabelmeLike.list_word(result_dict, 1 / ratio, 'words_result', 'words_result_num')
462
- return result_dict
463
-
464
- def handwriting(self, image, **options):
465
- """ 手写文字识别: https://cloud.baidu.com/doc/OCR/s/hk3h7y2qq """
466
- buffer, ratio = self.adjust_image(image)
467
- result_dict = self.run_aipocr_with_db(self._aipocr.handwriting, buffer, options)
468
- result_dict = ToLabelmeLike.list_word(result_dict, 1 / ratio, 'words_result', 'words_result_num')
469
- return result_dict
470
-
471
- def numbers(self, image, **options):
472
- """ 数字识别: https://cloud.baidu.com/doc/OCR/s/Ok3h7y1vo """
473
- buffer, ratio = self.adjust_image(image)
474
- result_dict = self.run_aipocr_with_db(self._aipocr.numbers, buffer, options)
475
- result_dict = ToLabelmeLike.list_word(result_dict, 1 / ratio, 'words_result', 'words_result_num')
476
- return result_dict
477
-
478
- def qrcode(self, image, **options):
479
- """ 二维码识别: https://cloud.baidu.com/doc/OCR/s/qk3h7y5o7 """
480
- buffer, ratio = self.adjust_image(image)
481
- result_dict = self.run_aipocr_with_db(self._aipocr.qrcode, buffer, options)
482
-
483
- ls = result_dict['codes_result']
484
- shapes = []
485
- for x in ls:
486
- # assert len(x['text']) == 1, '取到的文本list长度大于1'
487
- shapes.append({'label': {'text': ','.join(x['text']), 'category': x['type']}})
488
- result_dict['shapes'] = shapes
489
-
490
- del result_dict['codes_result']
491
- del result_dict['codes_result_num']
492
- return result_dict
493
-
494
- def form(self, image, **options):
495
- """ 表格文字识别(同步接口): https://cloud.baidu.com/doc/OCR/s/ik3h7xyxf
496
-
497
- 备注:
498
- 0、有异步接口
499
- 1、返回是四边形结构,实际值都是矩形,先转成矩形处理了
500
- 2、因为矩形,这个不能处理倾斜的表格
501
- 3、看起来支持多表格
502
- """
503
- from bisect import bisect_left
504
- from pyxllib.file.xlsxlib import XlWorkbook
505
-
506
- # 1 单表处理功能
507
- def zoom_coords(table, ratio):
508
- for k, xs in table.items():
509
- if k == 'vertexes_location':
510
- table[k] = [zoom_point(pt, ratio) for pt in table[k]]
511
- else:
512
- for x in table[k]:
513
- x['vertexes_location'] = [zoom_point(pt, ratio) for pt in x['vertexes_location']]
514
-
515
- def parse_split_points(cells, cls='row', name='y'):
516
- # 计算行列数量,初始化空list
517
- n = max([x[cls] for x in cells]) + 2
518
- spans = [[] for i in range(n)]
519
- # 加入所有行列数据
520
- for x in cells:
521
- spans[x[cls]].append(x['vertexes_location'][0][name])
522
- spans[-1].append(table['vertexes_location'][2][name])
523
- # 计算平均行列位置
524
- spans = [statistics.mean(vs) for vs in spans if vs]
525
- # 合并临近的行列
526
- min_gap = 3 # 两行/列间距小余min_gap像素,合并为1行/列
527
- spans = [v for a, v in zip([0] + spans, spans) if v - a > min_gap]
528
- # 计算分割线(以中间为准)
529
- spans = [round_int((a + b) / 2) for a, b in zip(spans, spans[1:])]
530
- return spans
531
-
532
- def location2rowcol(loc, rowspan, colspan):
533
- p1, p2 = loc[0], loc[2]
534
- pos = {
535
- 'row': bisect_left(rowspan, p1['y']) + 1, # 我的数据改成从1开始编号了
536
- 'column': bisect_left(colspan, p1['x']) + 1,
537
- 'end_row': bisect_left(rowspan, p2['y']),
538
- 'end_column': bisect_left(colspan, p2['x']),
539
- }
540
- return pos
541
-
542
- def parse_table(table):
543
- # 1 计算行、列分界线
544
- rowspan = parse_split_points(table['body'], 'row', 'y')
545
- colspan = parse_split_points(table['body'], 'column', 'x')
546
-
547
- # 2 shapes
548
- shapes = []
549
- # 这个表格暂时转labelme格式,但泛用来说,其实不应该转labelme,它有其特殊性
550
- # location虽然给的是四边形,但看目前数据其实就是矩形
551
- for k, xs in table.items():
552
- if k == 'vertexes_location':
553
- sp = {'label': {'text': '', 'category': 'table'},
554
- 'points': polygon2rect([(p['x'], p['y']) for p in table['vertexes_location']]),
555
- 'shape_type': 'rectangle'}
556
- shapes.append(sp)
557
- else:
558
- for x in xs:
559
- label = {'text': x['words'], 'probability': x['probability'], 'category': k}
560
- label.update(location2rowcol(x['vertexes_location'], rowspan, colspan))
561
- sp = {'label': label,
562
- 'points': polygon2rect([(p['x'], p['y']) for p in x['vertexes_location']]),
563
- 'shape_type': 'rectangle'}
564
- shapes.append(sp)
565
-
566
- # 3 tables
567
- # 3.1 表格主体内容
568
- wb = XlWorkbook()
569
- ws = wb.active
570
- for sp in shapes:
571
- x = sp['label']
572
- if x['category'] != 'body':
573
- continue
574
- # ws.cell(x['row'], x['column'], x['text'])
575
- cel = ws.cell(x['row'], x['column']).mcell()
576
- cel.value = (cel.value or '') + x['text']
577
- if x['end_row'] - x['row'] + x['end_column'] - x['column'] > 0:
578
- ws.merge_cells(start_row=x['row'], start_column=x['column'],
579
- end_row=x['end_row'], end_column=x['end_column'])
580
- # wb.save('/home/chenkunze/data/aipocr_test/a.xlsx') # debug: 保存中间结果查看
581
-
582
- # 3.2 其他内容整体性拼接
583
- htmltable = ['<div>']
584
- header = '<br/>'.join([x['words'] for x in table['header']])
585
- footer = '<br/>'.join([x['words'] for x in table['footer']])
586
- if header:
587
- htmltable.append(f'<p>{header}</p>')
588
- htmltable.append(ws.to_html())
589
- if footer:
590
- htmltable.append(f'<p>{footer}</p>')
591
- htmltable.append('</div>')
592
-
593
- return shapes, '\n'.join(htmltable)
594
-
595
- # 2 主体解析功能
596
-
597
- buffer, ratio = self.adjust_image(image)
598
- result_dict = self.run_aipocr_with_db(self._aipocr.form, buffer, options)
599
- shapes = []
600
- htmltables = []
601
- for table in result_dict['forms_result']:
602
- if ratio != 1:
603
- zoom_coords(table, 1 / ratio)
604
- _shapes, htmltable = parse_table(table)
605
- shapes += _shapes
606
- htmltables.append(htmltable)
607
-
608
- # 3 收尾
609
- result_dict['shapes'] = shapes
610
- result_dict['htmltables'] = htmltables
611
- del result_dict['forms_result']
612
- del result_dict['forms_result_num']
613
- return result_dict
614
-
615
- def doc_analysis_office(self, image, **options):
616
- """ 办公文档识别: https://cloud.baidu.com/doc/OCR/s/ykg9c09ji """
617
- buffer, ratio = self.adjust_image(image)
618
- result_dict = self.run_aipocr_with_db(self._aipocr.doc_analysis_office, buffer, options)
619
- result_dict = ToLabelmeLike.list_word2(result_dict, 1 / ratio, 'results', 'results_num')
620
- return result_dict
621
-
622
- def seal(self, image, **options):
623
- """ 印章识别: https://cloud.baidu.com/doc/OCR/s/Mk3h7y47a """
624
- buffer, ratio = self.adjust_image(image)
625
- result_dict = self.run_aipocr_with_db(self._aipocr.seal, buffer, options)
626
-
627
- shapes = []
628
- for x in result_dict['result']:
629
- shape = {'label': {}}
630
- shape.update(loc2points(x['location'], 1 / ratio))
631
- shape['label']['text'] = x['major']['words']
632
- shape['label']['minor'] = ','.join(x['minor'])
633
- shape['label']['category'] = x['type']
634
- shapes.append(shape)
635
-
636
- result_dict['shapes'] = shapes
637
- del result_dict['result']
638
- del result_dict['result_num']
639
- return result_dict
640
-
641
- def __B2_卡证(self):
642
- pass
643
-
644
- def idcard(self, image, **options):
645
- """ 身份证识别: https://cloud.baidu.com/doc/OCR/s/rk3h7xzck """
646
-
647
- def idcard_front(image, options=None):
648
- return self._aipocr.idcard(image,
649
- options.get('id_card_side', 'front'), # 默认识别带照片一面
650
- options)
651
-
652
- buffer, ratio = self.adjust_image(image)
653
- result_dict = self.run_aipocr_with_db(idcard_front, buffer, options)
654
- result_dict = ToLabelmeLike.dict_word(result_dict, 1 / ratio, 'words_result', 'words_result')
655
- return result_dict
656
-
657
- def idcard_back(self, image, **options):
658
- def func(image, options=None):
659
- return self._aipocr.idcard(image,
660
- options.get('id_card_side', 'back'), # 识别国徽一面
661
- options)
662
-
663
- buffer, ratio = self.adjust_image(image)
664
- result_dict = self.run_aipocr_with_db(func, buffer, options, mode_name='idcard_back')
665
- result_dict = ToLabelmeLike.dict_word(result_dict, 1 / ratio, 'words_result', 'words_result')
666
- return result_dict
667
-
668
- def bankcard(self, image, **options):
669
- """ 银行卡识别: https://cloud.baidu.com/doc/OCR/s/ak3h7xxg3 """
670
- buffer, ratio = self.adjust_image(image)
671
- result_dict = self.run_aipocr_with_db(self._aipocr.bankcard, buffer, options)
672
- result_dict = ToLabelmeLike.dict_str(result_dict, 1 / ratio, 'result', 'words_result_num')
673
- return result_dict
674
-
675
- def businessLicense(self, image, **options):
676
- """ 营业执照识别: https://cloud.baidu.com/doc/OCR/s/sk3h7y3zs """
677
- buffer, ratio = self.adjust_image(image)
678
- result_dict = self.run_aipocr_with_db(self._aipocr.businessLicense, buffer, options)
679
- result_dict = ToLabelmeLike.dict_word(result_dict, 1 / ratio, 'words_result', 'words_result_num')
680
- return result_dict
681
-
682
- def businessCard(self, image, **options):
683
- """ 名片识别: https://cloud.baidu.com/doc/OCR/s/5k3h7xyi2 """
684
- buffer, ratio = self.adjust_image(image)
685
- result_dict = self.run_aipocr_with_db(self._aipocr.businessCard, buffer, options)
686
- result_dict = ToLabelmeLike.dict_strs(result_dict, 1 / ratio, 'words_result')
687
- return result_dict
688
-
689
- def passport(self, image, **options):
690
- """ 护照识别: https://cloud.baidu.com/doc/OCR/s/Wk3h7y1gi """
691
- buffer, ratio = self.adjust_image(image)
692
- result_dict = self.run_aipocr_with_db(self._aipocr.passport, buffer, options)
693
- result_dict = ToLabelmeLike.dict_word(result_dict, 1 / ratio, 'words_result', 'words_result_num')
694
- return result_dict
695
-
696
- def HKMacauExitentrypermit(self, image, **options):
697
- """ 港澳通行证识别: https://cloud.baidu.com/doc/OCR/s/4k3h7y0ly """
698
- buffer, ratio = self.adjust_image(image)
699
- result_dict = self.run_aipocr_with_db(self._aipocr.HKMacauExitentrypermit, buffer, options)
700
- result_dict = ToLabelmeLike.dict_word(result_dict, 1 / ratio, 'words_result', 'words_result_num')
701
- return result_dict
702
-
703
- def taiwanExitentrypermit(self, image, **options):
704
- """ 台湾通行证识别: https://cloud.baidu.com/doc/OCR/s/kk3h7y2yc """
705
- buffer, ratio = self.adjust_image(image)
706
- result_dict = self.run_aipocr_with_db(self._aipocr.taiwanExitentrypermit, buffer, options)
707
- result_dict = ToLabelmeLike.dict_word(result_dict, 1 / ratio, 'words_result', 'words_result_num')
708
- return result_dict
709
-
710
- def householdRegister(self, image, **options):
711
- """ 户口本识别: https://cloud.baidu.com/doc/OCR/s/ak3h7xzk7 """
712
- buffer, ratio = self.adjust_image(image)
713
- result_dict = self.run_aipocr_with_db(self._aipocr.householdRegister, buffer, options)
714
- result_dict = ToLabelmeLike.dict_word(result_dict, 1 / ratio, 'words_result', 'words_result_num')
715
- return result_dict
716
-
717
- def birthCertificate(self, image, **options):
718
- """ 出生医学证明识别: https://cloud.baidu.com/doc/OCR/s/mk3h7y1o6 """
719
- buffer, ratio = self.adjust_image(image)
720
- result_dict = self.run_aipocr_with_db(self._aipocr.birthCertificate, buffer, options)
721
- result_dict = ToLabelmeLike.dict_word(result_dict, 1 / ratio, 'words_result', 'words_result_num')
722
- return result_dict
723
-
724
- def __B3_交通(self):
725
- pass
726
-
727
- def vehicleLicense(self, image, **options):
728
- """ 行驶证识别: https://cloud.baidu.com/doc/OCR/s/yk3h7y3ks """
729
- buffer, ratio = self.adjust_image(image)
730
- result_dict = self.run_aipocr_with_db(self._aipocr.vehicleLicense, buffer, options)
731
- result_dict = ToLabelmeLike.dict_word(result_dict, 1 / ratio, 'words_result', 'words_result_num')
732
- return result_dict
733
-
734
- def drivingLicense(self, image, **options):
735
- """ 驾驶证识别: https://cloud.baidu.com/doc/OCR/s/Vk3h7xzz7 """
736
- buffer, ratio = self.adjust_image(image)
737
- result_dict = self.run_aipocr_with_db(self._aipocr.drivingLicense, buffer, options)
738
- result_dict = ToLabelmeLike.dict_word(result_dict, 1 / ratio, 'words_result', 'words_result_num')
739
- return result_dict
740
-
741
- def licensePlate(self, image, **options):
742
- """ 车牌识别: https://cloud.baidu.com/doc/OCR/s/ck3h7y191 """
743
- buffer, ratio = self.adjust_image(image)
744
- result_dict = self.run_aipocr_with_db(self._aipocr.licensePlate, buffer, options)
745
-
746
- if 'words_result' in result_dict:
747
- d = result_dict['words_result']
748
- else:
749
- d = {'number': '', 'color': '', 'probability': [0], 'vertexes_location': []}
750
-
751
- # 近似key_text,但有点不太一样
752
- # 已测试过 车牌 只能识别一个
753
- label = {'text': d['number'],
754
- 'color': d['color']}
755
- shape = {'label': label,
756
- 'score': sum(d['probability']) / len(d['probability']),
757
- 'points': [zoom_point2(pt, 1 / ratio) for pt in d['vertexes_location']],
758
- 'shape_type': 'polygon'}
759
- result_dict['shapes'] = [shape]
760
-
761
- if 'words_result' in result_dict:
762
- del result_dict['words_result']
763
- return result_dict
764
-
765
- def vinCode(self, image, **options):
766
- """ VIN码识别: https://cloud.baidu.com/doc/OCR/s/zk3h7y51e """
767
- buffer, ratio = self.adjust_image(image)
768
- result_dict = self.run_aipocr_with_db(self._aipocr.vinCode, buffer, options)
769
- result_dict = ToLabelmeLike.list_word(result_dict, 1 / ratio, 'words_result', 'words_result_num')
770
- return result_dict
771
-
772
- def vehicleInvoice(self, image, **options):
773
- """ 机动车销售发票识别: https://cloud.baidu.com/doc/OCR/s/vk3h7y4tx """
774
- buffer, ratio = self.adjust_image(image)
775
- result_dict = self.run_aipocr_with_db(self._aipocr.vehicleInvoice, buffer, options)
776
- result_dict = ToLabelmeLike.dict_str(result_dict, 1 / ratio, 'words_result', 'words_result_num')
777
- return result_dict
778
-
779
- def vehicleCertificate(self, image, **options):
780
- """ 车辆合格证识别: https://cloud.baidu.com/doc/OCR/s/yk3h7y3sc """
781
- buffer, ratio = self.adjust_image(image)
782
- result_dict = self.run_aipocr_with_db(self._aipocr.vehicleCertificate, buffer, options)
783
- result_dict = ToLabelmeLike.dict_str(result_dict, 1 / ratio, 'words_result', 'words_result_num')
784
- return result_dict
785
-
786
- def raw_mixed_multi_vehicle(self, image, **options):
787
- """ 车辆证照混贴识别: https://cloud.baidu.com/doc/OCR/s/Kksfsbngb """
788
- buffer, ratio = self.adjust_image(image)
789
- result_dict = self.run_aipocr_with_db(self._aipocr.mixed_multi_vehicle, buffer, options)
790
-
791
- if ratio != 1:
792
- for x in result_dict['words_result']:
793
- x['location'] = {k: round_int(v / ratio) for k, v in x['location'].items()}
794
-
795
- return result_dict
796
-
797
- def mixed_multi_vehicle(self, image, **options):
798
- result_dict = self.raw_mixed_multi_vehicle(image, **options)
799
- pprint.pprint(result_dict)
800
-
801
- shapes = []
802
- for x in result_dict.get('words_result', []):
803
- shape = {'label': {}}
804
- shape.update(loc2points(x['location']))
805
- shape['label']['text'] = json.dumps({w['word_name']: w['word'] for w in x['license_info']},
806
- ensure_ascii=False)
807
- shape['label']['category'] = x['card_type']
808
- shape['label']['score'] = x['probability']
809
- shapes.append(shape)
810
-
811
- result_dict['shapes'] = shapes
812
- if 'words_result' in result_dict:
813
- del result_dict['words_result']
814
- if 'words_result_num' in result_dict:
815
- del result_dict['words_result_num']
816
- return result_dict
817
-
818
- def vehicle_registration_certificate(self, image, **options):
819
- """ 机动车登记证书识别: https://cloud.baidu.com/doc/OCR/s/qknzs5zzo """
820
- buffer, ratio = self.adjust_image(image)
821
- result_dict = self.run_aipocr_with_db(self._aipocr.vehicle_registration_certificate, buffer, options)
822
- result_dict = ToLabelmeLike.dict_word(result_dict, 1 / ratio, 'words_result', 'words_result_num')
823
- return result_dict
824
-
825
- def weightNote(self, image, **options):
826
- """ 磅单识别: https://cloud.baidu.com/doc/OCR/s/Uksfp9far """
827
- buffer, ratio = self.adjust_image(image)
828
- result_dict = self.run_aipocr_with_db(self._aipocr.weightNote, buffer, options)
829
-
830
- shapes = []
831
- for x in result_dict['words_result']:
832
- for k, vs in x.items():
833
- shape = {'category': k,
834
- 'label': ''.join([v['word'] for v in vs])}
835
- shapes.append(shape)
836
-
837
- result_dict['shapes'] = shapes
838
- del result_dict['words_result']
839
- del result_dict['words_result_num']
840
- return result_dict
841
-
842
- def __B4_财务(self):
843
- pass
844
-
845
- def multipleInvoice(self, image, **options):
846
- """ 智能财务票据识别: https://cloud.baidu.com/doc/OCR/s/7ktb8md0j """
847
- buffer, ratio = self.adjust_image(image)
848
- result_dict = self.run_aipocr_with_db(self._aipocr.multipleInvoice, buffer, options)
849
-
850
- shapes = []
851
- for x in result_dict['words_result']:
852
- shape = {'category': x['type'], 'label': {'text': ''}}
853
- shape.update(loc2points(x, 1 / ratio))
854
- shapes.append(shape)
855
-
856
- result_dict['shapes'] = shapes
857
- del result_dict['words_result']
858
- del result_dict['words_result_num']
859
- return result_dict
860
-
861
- def quotaInvoice(self, image, **options):
862
- """ 定额发票识别: https://cloud.baidu.com/doc/OCR/s/lk3h7y4ev """
863
- buffer, ratio = self.adjust_image(image)
864
- result_dict = self.run_aipocr_with_db(self._aipocr.quotaInvoice, buffer, options)
865
- result_dict = ToLabelmeLike.dict_str(result_dict, 1 / ratio, 'words_result', 'words_result_num')
866
- return result_dict
867
-
868
- def invoice(self, image, **options):
869
- """ 通用机打发票识别: https://cloud.baidu.com/doc/OCR/s/Pk3h7y06q """
870
- buffer, ratio = self.adjust_image(image)
871
- result_dict = self.run_aipocr_with_db(self._aipocr.invoice, buffer, options)
872
-
873
- shapes = []
874
- for k, v in result_dict['words_result'].items():
875
- shape = {'label': {'category': k}}
876
- if isinstance(v, list):
877
- shape['label']['text'] = '\n'.join([w['word'] for w in v])
878
- else:
879
- shape['label']['text'] = v
880
- shapes.append(shape)
881
-
882
- result_dict['shapes'] = shapes
883
- del result_dict['words_result']
884
- del result_dict['words_result_num']
885
- return result_dict
886
-
887
- def trainTicket(self, image, **options):
888
- """ 火车票识别: https://cloud.baidu.com/doc/OCR/s/Ok3h7y35u """
889
- buffer, ratio = self.adjust_image(image)
890
- result_dict = self.run_aipocr_with_db(self._aipocr.trainTicket, buffer, options)
891
- result_dict = ToLabelmeLike.dict_str(result_dict, 1 / ratio, 'words_result', 'words_result_num')
892
- return result_dict
893
-
894
- def taxiReceipt(self, image, **options):
895
- """ 出租车票识别: https://cloud.baidu.com/doc/OCR/s/Zk3h7xxnn """
896
- buffer, ratio = self.adjust_image(image)
897
- result_dict = self.run_aipocr_with_db(self._aipocr.taxiReceipt, buffer, options)
898
- result_dict = ToLabelmeLike.dict_str(result_dict, 1 / ratio, 'words_result', 'words_result_num')
899
- return result_dict
900
-
901
- def airTicket(self, image, **options):
902
- """ 飞机行程单识别: https://cloud.baidu.com/doc/OCR/s/Qk3h7xzro """
903
- buffer, ratio = self.adjust_image(image)
904
- result_dict = self.run_aipocr_with_db(self._aipocr.airTicket, buffer, options)
905
- result_dict = ToLabelmeLike.dict_str(result_dict, 1 / ratio, 'words_result', 'words_result_num')
906
- return result_dict
907
-
908
- def onlineTaxiItinerary(self, image, **options):
909
- """ 网约车行程单识别: https://cloud.baidu.com/doc/OCR/s/Bkocoyu9n """
910
-
911
- def func(image, options=None):
912
- return self._aipocr.onlineTaxiItinerary(image)
913
-
914
- buffer, ratio = self.adjust_image(image)
915
- result_dict = self.run_aipocr_with_db(func, buffer, options, mode_name='onlineTaxiItinerary')
916
-
917
- shapes = []
918
- for k, v in result_dict['words_result'].items():
919
- if k == 'items':
920
- shape = {'label': {'category': 'item'}}
921
- shape['label']['text'] = json.dumps(v, ensure_ascii=False)
922
- else:
923
- shape = {'label': {'category': k}}
924
- shape['label']['text'] = v
925
- shapes.append(shape)
926
-
927
- result_dict['shapes'] = shapes
928
- del result_dict['words_result']
929
- del result_dict['words_result_num']
930
- return result_dict
931
-
932
- def receipt(self, image, **options):
933
- """ receipt: https://cloud.baidu.com/doc/OCR/s/6k3h7y11b """
934
- buffer, ratio = self.adjust_image(image)
935
- result_dict = self.run_aipocr_with_db(self._aipocr.receipt, buffer, options)
936
- result_dict = ToLabelmeLike.list_word(result_dict, 1 / ratio, 'words_result', 'words_result_num')
937
- return result_dict
938
-
939
- def __B5_医疗(self):
940
- pass
941
-
942
- def raw_medicalInvoice(self, image, **options):
943
- """ 医疗发票识别: https://cloud.baidu.com/doc/OCR/s/yke30j1hq """
944
- buffer, ratio = self.adjust_image(image)
945
- result_dict = self.run_aipocr_with_db(self._aipocr.medicalInvoice, buffer, options)
946
- return result_dict
947
-
948
- def raw_medicalDetail(self, image, **options):
949
- """ 医疗费用明细识别: https://cloud.baidu.com/doc/OCR/s/Bknjnwlyj """
950
- buffer, ratio = self.adjust_image(image)
951
- result_dict = self.run_aipocr_with_db(self._aipocr.medicalDetail, buffer, options)
952
- return result_dict
953
-
954
- def raw_insuranceDocuments(self, image, **options):
955
- """ 保险单识别: https://cloud.baidu.com/doc/OCR/s/Wk3h7y0eb """
956
- buffer, ratio = self.adjust_image(image)
957
- result_dict = self.run_aipocr_with_db(self._aipocr.insuranceDocuments, buffer, options)
958
- return result_dict
959
-
960
- def __B6_教育(self):
961
- pass
962
-
963
- def docAnalysis(self, image, **options):
964
- """ 试卷分析与识别: https://cloud.baidu.com/doc/OCR/s/jk9m7mj1l
965
- 总量1000次
966
- """
967
- buffer, ratio = self.adjust_image(image)
968
- result_dict = self.run_aipocr_with_db(self._aipocr.docAnalysis, buffer, options)
969
-
970
- shapes = []
971
- for x in result_dict['results']:
972
- shape = loc2points(x['words']['words_location'], 1 / ratio)
973
- # 有line_probability字段,但实际并没有返回置信度~
974
- shape['label'] = {'category': x['words_type'], 'text': x['words']['word']}
975
- shapes.append(shape)
976
-
977
- result_dict['shapes'] = shapes
978
- del result_dict['results']
979
- del result_dict['results_num']
980
- return result_dict
981
-
982
- def formula(self, image, **options):
983
- """ 公式识别: https://cloud.baidu.com/doc/OCR/s/Ok3h7xxva
984
- 总共1000次
985
- """
986
- buffer, ratio = self.adjust_image(image)
987
- result_dict = self.run_aipocr_with_db(self._aipocr.formula, buffer, options)
988
- result_dict = ToLabelmeLike.list_word(result_dict, 1 / ratio, 'words_result', 'words_result_num')
989
- return result_dict
990
-
991
- def __B7_其他(self):
992
- pass
993
-
994
- def meter(self, image, **options):
995
- """ 仪器仪表盘读数识别: https://cloud.baidu.com/doc/OCR/s/Jkafike0v """
996
- buffer, ratio = self.adjust_image(image)
997
- result_dict = self.run_aipocr_with_db(self._aipocr.meter, buffer, options)
998
- result_dict = ToLabelmeLike.list_word(result_dict, 1 / ratio, 'words_result', 'words_result_num')
999
- return result_dict
1000
-
1001
- def raw_facade(self, image, **options):
1002
- """ 门脸文字识别: https://cloud.baidu.com/doc/OCR/s/wk5hw3cvo """
1003
- buffer, ratio = self.adjust_image(image)
1004
- result_dict = self.run_aipocr_with_db(self._aipocr.facade, buffer, options)
1005
- return result_dict
1006
-
1007
- def facade(self, image, **options):
1008
- result_dict = self.raw_facade(image, options)
1009
-
1010
- shapes = []
1011
- for x in result_dict['words_result']:
1012
- shape = {'label': {'text': x['words'], 'score': x['score']}}
1013
- shapes.append(shape)
1014
-
1015
- result_dict['shapes'] = shapes
1016
- del result_dict['words_result']
1017
- del result_dict['words_result_num']
1018
- return result_dict
1019
-
1020
- def __C_其他三方api接口(self):
1021
- pass
1022
-
1023
- def mathpix_latex(self, image, **options):
1024
- """ 调用mathpix识别单张图片的公式
1025
-
1026
- 【return】
1027
- {'auto_rotate_confidence': 0.0003554748584377876,
1028
- 'auto_rotate_degrees': 0,
1029
- 'detection_list': ['is_printed'],
1030
- 'detection_map': {'contains_chart': 0,
1031
- 'contains_diagram': 0,
1032
- 'contains_graph': 0,
1033
- 'contains_table': 0,
1034
- 'is_blank': 0,
1035
- 'is_inverted': 0,
1036
- 'is_not_math': 0,
1037
- 'is_printed': 0.9996553659439087},
1038
- 'error': '',
1039
- 'latex': '\\left. \\begin{array} { l } { \\alpha / / \\beta } \\\\ { \\gamma '
1040
- '\\cap \\alpha = a } \\\\ { \\gamma \\cap \\beta = b } \\end{array} '
1041
- '\\right\\} \\Rightarrow a / / b',
1042
- 'latex_confidence': 0.9824940343387425,
1043
- 'latex_confidence_rate': 0.9994673295454546,
1044
- 'latex_list': [],
1045
- 'position': {'height': 160, 'top_left_x': 0, 'top_left_y': 0, 'width': 266},
1046
- 'request_id': '2022_05_28_762803ab687ff5ba1d80g'}
1047
- """
1048
-
1049
- def func(buffer, options):
1050
- image_uri = f'data:image/jpg;base64,' + base64.b64encode(buffer).decode()
1051
- for i in range(3): # 尝试3次
1052
- try:
1053
- r = requests.post('https://api.mathpix.com/v3/latex',
1054
- data=json.dumps({'src': image_uri}),
1055
- headers=self._mathpix_header)
1056
- return json.loads(r.text)
1057
- except requests.exceptions.ConnectionError:
1058
- pass
1059
- else:
1060
- return {'latex': '', 'error': 'requests.exceptions.ConnectionError'}
1061
-
1062
- # mathpix的接口没有说限制图片大小,但我还是按照百度的规范处理下更好
1063
- buffer, ratio = self.adjust_image(image)
1064
- result_dict = self.run_aipocr_with_db(func, buffer, options, mode_name='mathpix_latex')
1065
- if 'position' in result_dict:
1066
- result_dict['position'] = zoom_point(result_dict['position'], ratio)
1067
- return result_dict
1068
-
1069
- def __D_福建省模式识别与图像理解重点实验室(self):
1070
- pass
1071
-
1072
- def _priu_read_image(self, image, min_length=None, max_length=None,
1073
- limit_b64buffer_size=None, b64encode=None, **kwargs):
1074
- # 默认不进行尺寸、文件大小压缩,这样会由平台上负责进行ratio缩放计算
1075
- buffer, ratio = self.adjust_image(image,
1076
- min_length=min_length, max_length=max_length,
1077
- limit_b64buffer_size=limit_b64buffer_size,
1078
- b64encode=True, **kwargs)
1079
- assert ratio == 1, f'本地不做缩放,由服务器进行缩放处理'
1080
- return buffer.decode()
1081
-
1082
- def priu_api(self, mode, image=None, texts=None, options=None, timeout=30, **meta_opts):
1083
- """ 借助服务器来调用该类中含有的其他函数接口
1084
-
1085
- 使用该接口的时候,因为服务器一般会有图片等的备份,所以本接口默认不对图片进行备份
1086
- 另外因为可能会调用自定义的模型功能,自定义的模型可能迭代较快,不适合在数据库缓存结果,所以也不记录json结果
1087
-
1088
- :param mode: 使用的api接口名称
1089
- :param image: image、texts、options都是比较常用的几个参数键值,所以显式地写出来
1090
- :param options: 有时候为了严谨,api相关的参数可能要单独打包
1091
- 但其实这里的参数混入meta_opts也没事,底层会有divide拆分函数,能区分开不同的参数类型
1092
- :param timeout: 超时30秒的限制,有些特殊情况可以设置的更短
1093
- :param meta_opts: 也可以自己额外扩展一些键值,兼容一些特殊的输入范式的api接口
1094
- use_exists_xlapi: 是否复用已有的识别结果,避免重复运算,节约api成本
1095
- record_files: 是否保存图片等数据
1096
- record_xlapi: 是否保存api执行结果
1097
- record_xlserver: 是否保存本次调用纪录
1098
- 根据不同的api,这些参数有不同的默认值,但一般都是True
1099
- """
1100
- # 1 统一输入参数的范式
1101
- data = {}
1102
- if image is not None:
1103
- data['image'] = self._priu_read_image(image, b64encode=True)
1104
- if texts is not None:
1105
- data['texts'] = texts
1106
- if options: # 支持对算法的参数打包,但其实也支持从kwargs直接零散输入
1107
- data['options'] = options
1108
- if meta_opts:
1109
- data.update(meta_opts)
1110
-
1111
- try:
1112
- r = requests.post(f'{self._priu_host}/api/{mode}',
1113
- json=data, headers=self._priu_header, timeout=timeout)
1114
- except requests.exceptions.Timeout:
1115
- # 为了方便处理,统一也返回ConnectionError
1116
- raise requests.exceptions.ConnectionError()
1117
- except Exception:
1118
- raise requests.exceptions.ConnectionError()
1119
-
1120
- if r.status_code == 200:
1121
- res = json.loads(r.text)
1122
- else: # TODO 正常状态码不只200,可能还有重定向等某些不一定是错误的状态
1123
- raise requests.exceptions.ConnectionError(r.text)
1124
-
1125
- # 2 统一返回值的范式,默认都是dict。 有些特殊格式表示是图片,这里会自动做后处理解析。
1126
- if isinstance(res, dict) and len(res) == 1 and 'imageData' in res:
1127
- # 只有一张图片情况的数据,直接返回图片
1128
- return xlcv.read_from_buffer(res['imageData'], b64decode=True)
1129
- else:
1130
- return res
1131
-
1132
- def common_ocr(self, image, **options):
1133
- """ 通用文字识别 """
1134
- options.update({'image': self._priu_read_image(image, b64encode=True)})
1135
- r = requests.post(f'{self._priu_host}/api/common_ocr', headers=self._priu_header,
1136
- json=options)
1137
- res = json.loads(r.text)
1138
- return res
1139
-
1140
- def ocr2texts(self, image, mode='common_ocr', **options):
1141
- """ 通用的识别一张图的所有文本
1142
-
1143
- >> xlapi.ocr2texts(im)
1144
- ['OCR文字识别软件', '如何将图片转换成Word', '文章来源:OCR文字识别软件', 'OCR']
1145
- """
1146
- texts = [] # 因图片太小等各种原因,没有识别到结果,默认就设空值
1147
- try:
1148
- d = self.priu_api(mode, image, options=options)
1149
- if 'shapes' in d:
1150
- texts = [sp['label']['text'] for sp in d['shapes']]
1151
- except requests.exceptions.ConnectionError:
1152
- pass
1153
- return texts
1154
-
1155
- def rec_singleline(self, image, mode='common_ocr', **options):
1156
- """ 通用的识别一张图的所有文本,并拼接到一起 """
1157
- texts = self.ocr2texts(image, mode, **options)
1158
- return ' '.join(texts)
1159
-
1160
- def hesuan_layout(self, image):
1161
- """ 核酸版面分析 """
1162
- r = requests.post(f'{self._priu_host}/api/hesuan/layout', headers=self._priu_header,
1163
- json={'image': self._priu_read_image(image)})
1164
- return json.loads(r.text)
1165
-
1166
- def lexical_analysis(self, texts, options=None, return_mode=None):
1167
- """ 词法分析,有分词的效果
1168
-
1169
- >> lexical_analysis(["今天是个好日子", "天气预报说今天要下雨"])
1170
- [['今天', '是', '个', '好日子'], ['天气预报', '说', '今天', '要', '下雨']]
1171
- """
1172
- # TODO 可以增加接口参数,配置返回值类型。其他api同理。
1173
- data = {'texts': texts}
1174
- if options:
1175
- data['options'] = options
1176
- r = requests.post(f'{self._priu_host}/api/lac', json=data, headers=self._priu_header)
1177
- res = json.loads(r.text)
1178
-
1179
- if return_mode == 'raw':
1180
- pass
1181
- else:
1182
- res = [x['word'] for x in res]
1183
- return res
1184
-
1185
- def sentiment_classify(self, texts, options=None):
1186
- """ 情感分析
1187
-
1188
- 返回的值越大表示句子的情感越积极
1189
- >> sentiment_classify(['今天是个好日子', '天气预报说今天要下雨'])
1190
- [0.4555, 0.2513]
1191
- """
1192
- data = {'texts': texts}
1193
- if options:
1194
- data['options'] = options
1195
- r = requests.post(f'{self._priu_host}/api/senta_bilstm', json=data, headers=self._priu_header)
1196
- return json.loads(r.text)
1197
-
1198
- def humanseg(self, image):
1199
- """ 人像抠图
1200
-
1201
- TODO 还没测过特大、特小图会不会有问题~
1202
- """
1203
- im, _ = self.adjust_image(image, 1, to_buffer=False) # 不能用xlcv.read,因为也可能作为服务端接口,输入buffer格式
1204
- mask = self.priu_api('deeplabv3p_xception65_humanseg', im)
1205
- new_im = np.concatenate([im, np.expand_dims(mask, axis=2)], axis=2) # 变成BGRA格式图片
1206
- return new_im
1207
-
1208
- def det_face(self, image):
1209
- """ 人脸识别 """
1210
- lmdict = self.priu_api('ultra_light_fast_generic_face_detector_1mb_640', image)
1211
- return lmdict
1212
-
1213
- def super_resolution(self, image, times=1):
1214
- """ 超分辨率(把图片变高清)
1215
-
1216
- :param times: 放大多少次,每次放大2倍(长宽个放大2倍)
1217
- """
1218
- for _ in range(times):
1219
- image = self.priu_api('falsr_c', image)
1220
- return image
1221
-
1222
- def rec_speech(self, audio_file):
1223
- """ 语音识别 """
1224
- if os.path.isfile(audio_file):
1225
- audio = base64.b64encode(XlPath(audio_file).read_bytes()).decode()
1226
- else:
1227
- raise NotImplementedError
1228
- text = self.priu_api('u2_conformer_wenetspeech', audio=audio)[0]
1229
- return text
1230
-
1231
-
1232
- def demo_aipocr():
1233
- import pprint
1234
- import re
1235
-
1236
- from pyxlpr.data.labelme import LabelmeDict
1237
-
1238
- xlapi = XlAiClient()
1239
- # xlapi.setup_database()
1240
- xlapi._priu_host = 'http://localhost:5003'
1241
-
1242
- mode = 'general'
1243
-
1244
- _dir = XlPath("/home/chenkunze/data/aipocr_test")
1245
- fmode = re.sub(r'^raw_', r'', mode)
1246
- fmode = {'basicAccurate': 'accurate',
1247
- 'basicGeneral': 'general',
1248
- 'webimageLoc': 'webImage',
1249
- 'idcard_back': 'idcard',
1250
- 'vat_invoice_verification': 'vatInvoice',
1251
- 'mathpix_latex': 'formula',
1252
- }.get(fmode, fmode)
1253
- files = _dir.glob_images(f'*/{fmode}/**/*')
1254
-
1255
- for f in list(files):
1256
- # 1 处理指定图片
1257
- # if f.stem != '824ef2b9a5f05422199107721d299f30':
1258
- # continue
1259
-
1260
- # 2 检查字典
1261
- print(f.as_posix())
1262
- d = getattr(xlapi, mode)(f.as_posix())
1263
-
1264
- # browser.html(d['htmltables'][0])
1265
- print()
1266
- pprint.pprint(d)
1267
- print('- ' * 20)
1268
-
1269
- # 3 前置的错误图可以删除;有shapes的可以转labelme;非labelme格式上面print后直接退出
1270
- if 'error_code' in d:
1271
- f.delete()
1272
- elif d.get('shapes', 0):
1273
- # tolabelme
1274
- lmdata = LabelmeDict.gen_data(f)
1275
- lmdata['shapes'] = d['shapes']
1276
- for sp in lmdata['shapes']:
1277
- sp['label'] = json.dumps(sp['label'], ensure_ascii=False)
1278
- f.with_suffix('.json').write_json(lmdata)
1279
- break
1280
- else:
1281
- break