paddleocr.py 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722
  1. # Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. import os
  15. import sys
  16. import importlib
  17. __dir__ = os.path.dirname(__file__)
  18. import paddle
  19. sys.path.append(os.path.join(__dir__, ''))
  20. import cv2
  21. import logging
  22. import numpy as np
  23. from pathlib import Path
  24. tools = importlib.import_module('.', 'tools')
  25. ppocr = importlib.import_module('.', 'ppocr')
  26. ppstructure = importlib.import_module('.', 'ppstructure')
  27. from tools.infer import predict_system
  28. from ppocr.utils.logging import get_logger
  29. logger = get_logger()
  30. from ppocr.utils.utility import check_and_read, get_image_file_list
  31. from ppocr.utils.network import maybe_download, download_with_progressbar, is_link, confirm_model_dir_url
  32. from tools.infer.utility import draw_ocr, str2bool, check_gpu
  33. from ppstructure.utility import init_args, draw_structure_result
  34. from ppstructure.predict_system import StructureSystem, save_structure_res, to_excel
  35. __all__ = [
  36. 'PaddleOCR', 'PPStructure', 'draw_ocr', 'draw_structure_result',
  37. 'save_structure_res', 'download_with_progressbar', 'to_excel'
  38. ]
  39. SUPPORT_DET_MODEL = ['DB']
  40. VERSION = '2.6.1.0'
  41. SUPPORT_REC_MODEL = ['CRNN', 'SVTR_LCNet']
  42. BASE_DIR = os.path.expanduser("~/.paddleocr/")
  43. DEFAULT_OCR_MODEL_VERSION = 'PP-OCRv3'
  44. SUPPORT_OCR_MODEL_VERSION = ['PP-OCR', 'PP-OCRv2', 'PP-OCRv3']
  45. DEFAULT_STRUCTURE_MODEL_VERSION = 'PP-StructureV2'
  46. SUPPORT_STRUCTURE_MODEL_VERSION = ['PP-Structure', 'PP-StructureV2']
  47. MODEL_URLS = {
  48. 'OCR': {
  49. 'PP-OCRv3': {
  50. 'det': {
  51. 'ch': {
  52. 'url':
  53. 'https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_det_infer.tar',
  54. },
  55. 'en': {
  56. 'url':
  57. 'https://paddleocr.bj.bcebos.com/PP-OCRv3/english/en_PP-OCRv3_det_infer.tar',
  58. },
  59. 'ml': {
  60. 'url':
  61. 'https://paddleocr.bj.bcebos.com/PP-OCRv3/multilingual/Multilingual_PP-OCRv3_det_infer.tar'
  62. }
  63. },
  64. 'rec': {
  65. 'ch': {
  66. 'url':
  67. 'https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_rec_infer.tar',
  68. 'dict_path': './ppocr/utils/ppocr_keys_v1.txt'
  69. },
  70. 'en': {
  71. 'url':
  72. 'https://paddleocr.bj.bcebos.com/PP-OCRv3/english/en_PP-OCRv3_rec_infer.tar',
  73. 'dict_path': './ppocr/utils/en_dict.txt'
  74. },
  75. 'korean': {
  76. 'url':
  77. 'https://paddleocr.bj.bcebos.com/PP-OCRv3/multilingual/korean_PP-OCRv3_rec_infer.tar',
  78. 'dict_path': './ppocr/utils/dict/korean_dict.txt'
  79. },
  80. 'japan': {
  81. 'url':
  82. 'https://paddleocr.bj.bcebos.com/PP-OCRv3/multilingual/japan_PP-OCRv3_rec_infer.tar',
  83. 'dict_path': './ppocr/utils/dict/japan_dict.txt'
  84. },
  85. 'chinese_cht': {
  86. 'url':
  87. 'https://paddleocr.bj.bcebos.com/PP-OCRv3/multilingual/chinese_cht_PP-OCRv3_rec_infer.tar',
  88. 'dict_path': './ppocr/utils/dict/chinese_cht_dict.txt'
  89. },
  90. 'ta': {
  91. 'url':
  92. 'https://paddleocr.bj.bcebos.com/PP-OCRv3/multilingual/ta_PP-OCRv3_rec_infer.tar',
  93. 'dict_path': './ppocr/utils/dict/ta_dict.txt'
  94. },
  95. 'te': {
  96. 'url':
  97. 'https://paddleocr.bj.bcebos.com/PP-OCRv3/multilingual/te_PP-OCRv3_rec_infer.tar',
  98. 'dict_path': './ppocr/utils/dict/te_dict.txt'
  99. },
  100. 'ka': {
  101. 'url':
  102. 'https://paddleocr.bj.bcebos.com/PP-OCRv3/multilingual/ka_PP-OCRv3_rec_infer.tar',
  103. 'dict_path': './ppocr/utils/dict/ka_dict.txt'
  104. },
  105. 'latin': {
  106. 'url':
  107. 'https://paddleocr.bj.bcebos.com/PP-OCRv3/multilingual/latin_PP-OCRv3_rec_infer.tar',
  108. 'dict_path': './ppocr/utils/dict/latin_dict.txt'
  109. },
  110. 'arabic': {
  111. 'url':
  112. 'https://paddleocr.bj.bcebos.com/PP-OCRv3/multilingual/arabic_PP-OCRv3_rec_infer.tar',
  113. 'dict_path': './ppocr/utils/dict/arabic_dict.txt'
  114. },
  115. 'cyrillic': {
  116. 'url':
  117. 'https://paddleocr.bj.bcebos.com/PP-OCRv3/multilingual/cyrillic_PP-OCRv3_rec_infer.tar',
  118. 'dict_path': './ppocr/utils/dict/cyrillic_dict.txt'
  119. },
  120. 'devanagari': {
  121. 'url':
  122. 'https://paddleocr.bj.bcebos.com/PP-OCRv3/multilingual/devanagari_PP-OCRv3_rec_infer.tar',
  123. 'dict_path': './ppocr/utils/dict/devanagari_dict.txt'
  124. },
  125. },
  126. 'cls': {
  127. 'ch': {
  128. 'url':
  129. 'https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_cls_infer.tar',
  130. }
  131. },
  132. },
  133. 'PP-OCRv2': {
  134. 'det': {
  135. 'ch': {
  136. 'url':
  137. 'https://paddleocr.bj.bcebos.com/PP-OCRv2/chinese/ch_PP-OCRv2_det_infer.tar',
  138. },
  139. },
  140. 'rec': {
  141. 'ch': {
  142. 'url':
  143. 'https://paddleocr.bj.bcebos.com/PP-OCRv2/chinese/ch_PP-OCRv2_rec_infer.tar',
  144. 'dict_path': './ppocr/utils/ppocr_keys_v1.txt'
  145. }
  146. },
  147. 'cls': {
  148. 'ch': {
  149. 'url':
  150. 'https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_cls_infer.tar',
  151. }
  152. },
  153. },
  154. 'PP-OCR': {
  155. 'det': {
  156. 'ch': {
  157. 'url':
  158. 'https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_det_infer.tar',
  159. },
  160. 'en': {
  161. 'url':
  162. 'https://paddleocr.bj.bcebos.com/dygraph_v2.0/multilingual/en_ppocr_mobile_v2.0_det_infer.tar',
  163. },
  164. 'structure': {
  165. 'url':
  166. 'https://paddleocr.bj.bcebos.com/dygraph_v2.0/table/en_ppocr_mobile_v2.0_table_det_infer.tar'
  167. }
  168. },
  169. 'rec': {
  170. 'ch': {
  171. 'url':
  172. 'https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_rec_infer.tar',
  173. 'dict_path': './ppocr/utils/ppocr_keys_v1.txt'
  174. },
  175. 'en': {
  176. 'url':
  177. 'https://paddleocr.bj.bcebos.com/dygraph_v2.0/multilingual/en_number_mobile_v2.0_rec_infer.tar',
  178. 'dict_path': './ppocr/utils/en_dict.txt'
  179. },
  180. 'french': {
  181. 'url':
  182. 'https://paddleocr.bj.bcebos.com/dygraph_v2.0/multilingual/french_mobile_v2.0_rec_infer.tar',
  183. 'dict_path': './ppocr/utils/dict/french_dict.txt'
  184. },
  185. 'german': {
  186. 'url':
  187. 'https://paddleocr.bj.bcebos.com/dygraph_v2.0/multilingual/german_mobile_v2.0_rec_infer.tar',
  188. 'dict_path': './ppocr/utils/dict/german_dict.txt'
  189. },
  190. 'korean': {
  191. 'url':
  192. 'https://paddleocr.bj.bcebos.com/dygraph_v2.0/multilingual/korean_mobile_v2.0_rec_infer.tar',
  193. 'dict_path': './ppocr/utils/dict/korean_dict.txt'
  194. },
  195. 'japan': {
  196. 'url':
  197. 'https://paddleocr.bj.bcebos.com/dygraph_v2.0/multilingual/japan_mobile_v2.0_rec_infer.tar',
  198. 'dict_path': './ppocr/utils/dict/japan_dict.txt'
  199. },
  200. 'chinese_cht': {
  201. 'url':
  202. 'https://paddleocr.bj.bcebos.com/dygraph_v2.0/multilingual/chinese_cht_mobile_v2.0_rec_infer.tar',
  203. 'dict_path': './ppocr/utils/dict/chinese_cht_dict.txt'
  204. },
  205. 'ta': {
  206. 'url':
  207. 'https://paddleocr.bj.bcebos.com/dygraph_v2.0/multilingual/ta_mobile_v2.0_rec_infer.tar',
  208. 'dict_path': './ppocr/utils/dict/ta_dict.txt'
  209. },
  210. 'te': {
  211. 'url':
  212. 'https://paddleocr.bj.bcebos.com/dygraph_v2.0/multilingual/te_mobile_v2.0_rec_infer.tar',
  213. 'dict_path': './ppocr/utils/dict/te_dict.txt'
  214. },
  215. 'ka': {
  216. 'url':
  217. 'https://paddleocr.bj.bcebos.com/dygraph_v2.0/multilingual/ka_mobile_v2.0_rec_infer.tar',
  218. 'dict_path': './ppocr/utils/dict/ka_dict.txt'
  219. },
  220. 'latin': {
  221. 'url':
  222. 'https://paddleocr.bj.bcebos.com/dygraph_v2.0/multilingual/latin_ppocr_mobile_v2.0_rec_infer.tar',
  223. 'dict_path': './ppocr/utils/dict/latin_dict.txt'
  224. },
  225. 'arabic': {
  226. 'url':
  227. 'https://paddleocr.bj.bcebos.com/dygraph_v2.0/multilingual/arabic_ppocr_mobile_v2.0_rec_infer.tar',
  228. 'dict_path': './ppocr/utils/dict/arabic_dict.txt'
  229. },
  230. 'cyrillic': {
  231. 'url':
  232. 'https://paddleocr.bj.bcebos.com/dygraph_v2.0/multilingual/cyrillic_ppocr_mobile_v2.0_rec_infer.tar',
  233. 'dict_path': './ppocr/utils/dict/cyrillic_dict.txt'
  234. },
  235. 'devanagari': {
  236. 'url':
  237. 'https://paddleocr.bj.bcebos.com/dygraph_v2.0/multilingual/devanagari_ppocr_mobile_v2.0_rec_infer.tar',
  238. 'dict_path': './ppocr/utils/dict/devanagari_dict.txt'
  239. },
  240. 'structure': {
  241. 'url':
  242. 'https://paddleocr.bj.bcebos.com/dygraph_v2.0/table/en_ppocr_mobile_v2.0_table_rec_infer.tar',
  243. 'dict_path': 'ppocr/utils/dict/table_dict.txt'
  244. }
  245. },
  246. 'cls': {
  247. 'ch': {
  248. 'url':
  249. 'https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_cls_infer.tar',
  250. }
  251. },
  252. }
  253. },
  254. 'STRUCTURE': {
  255. 'PP-Structure': {
  256. 'table': {
  257. 'en': {
  258. 'url':
  259. 'https://paddleocr.bj.bcebos.com/dygraph_v2.0/table/en_ppocr_mobile_v2.0_table_structure_infer.tar',
  260. 'dict_path': 'ppocr/utils/dict/table_structure_dict.txt'
  261. }
  262. }
  263. },
  264. 'PP-StructureV2': {
  265. 'table': {
  266. 'en': {
  267. 'url':
  268. 'https://paddleocr.bj.bcebos.com/ppstructure/models/slanet/en_ppstructure_mobile_v2.0_SLANet_infer.tar',
  269. 'dict_path': 'ppocr/utils/dict/table_structure_dict.txt'
  270. },
  271. 'ch': {
  272. 'url':
  273. 'https://paddleocr.bj.bcebos.com/ppstructure/models/slanet/ch_ppstructure_mobile_v2.0_SLANet_infer.tar',
  274. 'dict_path': 'ppocr/utils/dict/table_structure_dict_ch.txt'
  275. }
  276. },
  277. 'layout': {
  278. 'en': {
  279. 'url':
  280. 'https://paddleocr.bj.bcebos.com/ppstructure/models/layout/picodet_lcnet_x1_0_fgd_layout_infer.tar',
  281. 'dict_path':
  282. 'ppocr/utils/dict/layout_dict/layout_publaynet_dict.txt'
  283. },
  284. 'ch': {
  285. 'url':
  286. 'https://paddleocr.bj.bcebos.com/ppstructure/models/layout/picodet_lcnet_x1_0_fgd_layout_cdla_infer.tar',
  287. 'dict_path':
  288. 'ppocr/utils/dict/layout_dict/layout_cdla_dict.txt'
  289. }
  290. }
  291. }
  292. }
  293. }
  294. def parse_args(mMain=True):
  295. import argparse
  296. parser = init_args()
  297. parser.add_help = mMain
  298. parser.add_argument("--lang", type=str, default='ch')
  299. parser.add_argument("--det", type=str2bool, default=True)
  300. parser.add_argument("--rec", type=str2bool, default=True)
  301. parser.add_argument("--type", type=str, default='ocr')
  302. parser.add_argument(
  303. "--ocr_version",
  304. type=str,
  305. choices=SUPPORT_OCR_MODEL_VERSION,
  306. default='PP-OCRv3',
  307. help='OCR Model version, the current model support list is as follows: '
  308. '1. PP-OCRv3 Support Chinese and English detection and recognition model, and direction classifier model'
  309. '2. PP-OCRv2 Support Chinese detection and recognition model. '
  310. '3. PP-OCR support Chinese detection, recognition and direction classifier and multilingual recognition model.'
  311. )
  312. parser.add_argument(
  313. "--structure_version",
  314. type=str,
  315. choices=SUPPORT_STRUCTURE_MODEL_VERSION,
  316. default='PP-StructureV2',
  317. help='Model version, the current model support list is as follows:'
  318. ' 1. PP-Structure Support en table structure model.'
  319. ' 2. PP-StructureV2 Support ch and en table structure model.')
  320. for action in parser._actions:
  321. if action.dest in [
  322. 'rec_char_dict_path', 'table_char_dict_path', 'layout_dict_path'
  323. ]:
  324. action.default = None
  325. if mMain:
  326. return parser.parse_args()
  327. else:
  328. inference_args_dict = {}
  329. for action in parser._actions:
  330. inference_args_dict[action.dest] = action.default
  331. return argparse.Namespace(**inference_args_dict)
  332. def parse_lang(lang):
  333. latin_lang = [
  334. 'af', 'az', 'bs', 'cs', 'cy', 'da', 'de', 'es', 'et', 'fr', 'ga', 'hr',
  335. 'hu', 'id', 'is', 'it', 'ku', 'la', 'lt', 'lv', 'mi', 'ms', 'mt', 'nl',
  336. 'no', 'oc', 'pi', 'pl', 'pt', 'ro', 'rs_latin', 'sk', 'sl', 'sq', 'sv',
  337. 'sw', 'tl', 'tr', 'uz', 'vi', 'french', 'german'
  338. ]
  339. arabic_lang = ['ar', 'fa', 'ug', 'ur']
  340. cyrillic_lang = [
  341. 'ru', 'rs_cyrillic', 'be', 'bg', 'uk', 'mn', 'abq', 'ady', 'kbd', 'ava',
  342. 'dar', 'inh', 'che', 'lbe', 'lez', 'tab'
  343. ]
  344. devanagari_lang = [
  345. 'hi', 'mr', 'ne', 'bh', 'mai', 'ang', 'bho', 'mah', 'sck', 'new', 'gom',
  346. 'sa', 'bgc'
  347. ]
  348. if lang in latin_lang:
  349. lang = "latin"
  350. elif lang in arabic_lang:
  351. lang = "arabic"
  352. elif lang in cyrillic_lang:
  353. lang = "cyrillic"
  354. elif lang in devanagari_lang:
  355. lang = "devanagari"
  356. assert lang in MODEL_URLS['OCR'][DEFAULT_OCR_MODEL_VERSION][
  357. 'rec'], 'param lang must in {}, but got {}'.format(
  358. MODEL_URLS['OCR'][DEFAULT_OCR_MODEL_VERSION]['rec'].keys(), lang)
  359. if lang == "ch":
  360. det_lang = "ch"
  361. elif lang == 'structure':
  362. det_lang = 'structure'
  363. elif lang in ["en", "latin"]:
  364. det_lang = "en"
  365. else:
  366. det_lang = "ml"
  367. return lang, det_lang
  368. def get_model_config(type, version, model_type, lang):
  369. if type == 'OCR':
  370. DEFAULT_MODEL_VERSION = DEFAULT_OCR_MODEL_VERSION
  371. elif type == 'STRUCTURE':
  372. DEFAULT_MODEL_VERSION = DEFAULT_STRUCTURE_MODEL_VERSION
  373. else:
  374. raise NotImplementedError
  375. model_urls = MODEL_URLS[type]
  376. if version not in model_urls:
  377. version = DEFAULT_MODEL_VERSION
  378. if model_type not in model_urls[version]:
  379. if model_type in model_urls[DEFAULT_MODEL_VERSION]:
  380. version = DEFAULT_MODEL_VERSION
  381. else:
  382. logger.error('{} models is not support, we only support {}'.format(
  383. model_type, model_urls[DEFAULT_MODEL_VERSION].keys()))
  384. sys.exit(-1)
  385. if lang not in model_urls[version][model_type]:
  386. if lang in model_urls[DEFAULT_MODEL_VERSION][model_type]:
  387. version = DEFAULT_MODEL_VERSION
  388. else:
  389. logger.error(
  390. 'lang {} is not support, we only support {} for {} models'.
  391. format(lang, model_urls[DEFAULT_MODEL_VERSION][model_type].keys(
  392. ), model_type))
  393. sys.exit(-1)
  394. return model_urls[version][model_type][lang]
  395. def img_decode(content: bytes):
  396. np_arr = np.frombuffer(content, dtype=np.uint8)
  397. return cv2.imdecode(np_arr, cv2.IMREAD_COLOR)
  398. def check_img(img):
  399. if isinstance(img, bytes):
  400. img = img_decode(img)
  401. if isinstance(img, str):
  402. # download net image
  403. if is_link(img):
  404. download_with_progressbar(img, 'tmp.jpg')
  405. img = 'tmp.jpg'
  406. image_file = img
  407. img, flag_gif, flag_pdf = check_and_read(image_file)
  408. if not flag_gif and not flag_pdf:
  409. with open(image_file, 'rb') as f:
  410. img = img_decode(f.read())
  411. if img is None:
  412. logger.error("error in loading image:{}".format(image_file))
  413. return None
  414. if isinstance(img, np.ndarray) and len(img.shape) == 2:
  415. img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
  416. return img
  417. class PaddleOCR(predict_system.TextSystem):
  418. def __init__(self, **kwargs):
  419. """
  420. paddleocr package
  421. args:
  422. **kwargs: other params show in paddleocr --help
  423. """
  424. params = parse_args(mMain=False)
  425. params.__dict__.update(**kwargs)
  426. assert params.ocr_version in SUPPORT_OCR_MODEL_VERSION, "ocr_version must in {}, but get {}".format(
  427. SUPPORT_OCR_MODEL_VERSION, params.ocr_version)
  428. params.use_gpu = check_gpu(params.use_gpu)
  429. if not params.show_log:
  430. logger.setLevel(logging.INFO)
  431. self.use_angle_cls = params.use_angle_cls
  432. lang, det_lang = parse_lang(params.lang)
  433. # init model dir
  434. det_model_config = get_model_config('OCR', params.ocr_version, 'det',
  435. det_lang)
  436. params.det_model_dir, det_url = confirm_model_dir_url(
  437. params.det_model_dir,
  438. os.path.join(BASE_DIR, 'whl', 'det', det_lang),
  439. det_model_config['url'])
  440. rec_model_config = get_model_config('OCR', params.ocr_version, 'rec',
  441. lang)
  442. params.rec_model_dir, rec_url = confirm_model_dir_url(
  443. params.rec_model_dir,
  444. os.path.join(BASE_DIR, 'whl', 'rec', lang), rec_model_config['url'])
  445. cls_model_config = get_model_config('OCR', params.ocr_version, 'cls',
  446. 'ch')
  447. params.cls_model_dir, cls_url = confirm_model_dir_url(
  448. params.cls_model_dir,
  449. os.path.join(BASE_DIR, 'whl', 'cls'), cls_model_config['url'])
  450. if params.ocr_version == 'PP-OCRv3':
  451. params.rec_image_shape = "3, 48, 320"
  452. else:
  453. params.rec_image_shape = "3, 32, 320"
  454. # download model if using paddle infer
  455. if not params.use_onnx:
  456. maybe_download(params.det_model_dir, det_url)
  457. maybe_download(params.rec_model_dir, rec_url)
  458. maybe_download(params.cls_model_dir, cls_url)
  459. if params.det_algorithm not in SUPPORT_DET_MODEL:
  460. logger.error('det_algorithm must in {}'.format(SUPPORT_DET_MODEL))
  461. sys.exit(0)
  462. if params.rec_algorithm not in SUPPORT_REC_MODEL:
  463. logger.error('rec_algorithm must in {}'.format(SUPPORT_REC_MODEL))
  464. sys.exit(0)
  465. if params.rec_char_dict_path is None:
  466. params.rec_char_dict_path = str(
  467. Path(__file__).parent / rec_model_config['dict_path'])
  468. logger.debug(params)
  469. # init det_model and rec_model
  470. super().__init__(params)
  471. self.page_num = params.page_num
  472. def ocr(self, img, det=True, rec=True, cls=True):
  473. """
  474. ocr with paddleocr
  475. args:
  476. img: img for ocr, support ndarray, img_path and list or ndarray
  477. det: use text detection or not. If false, only rec will be exec. Default is True
  478. rec: use text recognition or not. If false, only det will be exec. Default is True
  479. cls: use angle classifier or not. Default is True. If true, the text with rotation of 180 degrees can be recognized. If no text is rotated by 180 degrees, use cls=False to get better performance. Text with rotation of 90 or 270 degrees can be recognized even if cls=False.
  480. """
  481. assert isinstance(img, (np.ndarray, list, str, bytes))
  482. if isinstance(img, list) and det == True:
  483. logger.error('When input a list of images, det must be false')
  484. exit(0)
  485. if cls == True and self.use_angle_cls == False:
  486. logger.warning(
  487. 'Since the angle classifier is not initialized, the angle classifier will not be uesd during the forward process'
  488. )
  489. img = check_img(img)
  490. # for infer pdf file
  491. if isinstance(img, list):
  492. if self.page_num > len(img) or self.page_num == 0:
  493. self.page_num = len(img)
  494. imgs = img[:self.page_num]
  495. else:
  496. imgs = [img]
  497. if det and rec:
  498. ocr_res = []
  499. for idx, img in enumerate(imgs):
  500. dt_boxes, rec_res, _ = self.__call__(img, cls)
  501. tmp_res = [[box.tolist(), res]
  502. for box, res in zip(dt_boxes, rec_res)]
  503. ocr_res.append(tmp_res)
  504. return ocr_res
  505. elif det and not rec:
  506. ocr_res = []
  507. for idx, img in enumerate(imgs):
  508. dt_boxes, elapse = self.text_detector(img)
  509. tmp_res = [box.tolist() for box in dt_boxes]
  510. ocr_res.append(tmp_res)
  511. return ocr_res
  512. else:
  513. ocr_res = []
  514. cls_res = []
  515. for idx, img in enumerate(imgs):
  516. if not isinstance(img, list):
  517. img = [img]
  518. if self.use_angle_cls and cls:
  519. img, cls_res_tmp, elapse = self.text_classifier(img)
  520. if not rec:
  521. cls_res.append(cls_res_tmp)
  522. rec_res, elapse = self.text_recognizer(img)
  523. ocr_res.append(rec_res)
  524. if not rec:
  525. return cls_res
  526. return ocr_res
  527. class PPStructure(StructureSystem):
  528. def __init__(self, **kwargs):
  529. params = parse_args(mMain=False)
  530. params.__dict__.update(**kwargs)
  531. assert params.structure_version in SUPPORT_STRUCTURE_MODEL_VERSION, "structure_version must in {}, but get {}".format(
  532. SUPPORT_STRUCTURE_MODEL_VERSION, params.structure_version)
  533. params.use_gpu = check_gpu(params.use_gpu)
  534. params.mode = 'structure'
  535. if not params.show_log:
  536. logger.setLevel(logging.INFO)
  537. lang, det_lang = parse_lang(params.lang)
  538. if lang == 'ch':
  539. table_lang = 'ch'
  540. else:
  541. table_lang = 'en'
  542. if params.structure_version == 'PP-Structure':
  543. params.merge_no_span_structure = False
  544. # init model dir
  545. det_model_config = get_model_config('OCR', params.ocr_version, 'det',
  546. det_lang)
  547. params.det_model_dir, det_url = confirm_model_dir_url(
  548. params.det_model_dir,
  549. os.path.join(BASE_DIR, 'whl', 'det', det_lang),
  550. det_model_config['url'])
  551. rec_model_config = get_model_config('OCR', params.ocr_version, 'rec',
  552. lang)
  553. params.rec_model_dir, rec_url = confirm_model_dir_url(
  554. params.rec_model_dir,
  555. os.path.join(BASE_DIR, 'whl', 'rec', lang), rec_model_config['url'])
  556. table_model_config = get_model_config(
  557. 'STRUCTURE', params.structure_version, 'table', table_lang)
  558. params.table_model_dir, table_url = confirm_model_dir_url(
  559. params.table_model_dir,
  560. os.path.join(BASE_DIR, 'whl', 'table'), table_model_config['url'])
  561. layout_model_config = get_model_config(
  562. 'STRUCTURE', params.structure_version, 'layout', lang)
  563. params.layout_model_dir, layout_url = confirm_model_dir_url(
  564. params.layout_model_dir,
  565. os.path.join(BASE_DIR, 'whl', 'layout'), layout_model_config['url'])
  566. # download model
  567. maybe_download(params.det_model_dir, det_url)
  568. maybe_download(params.rec_model_dir, rec_url)
  569. maybe_download(params.table_model_dir, table_url)
  570. maybe_download(params.layout_model_dir, layout_url)
  571. if params.rec_char_dict_path is None:
  572. params.rec_char_dict_path = str(
  573. Path(__file__).parent / rec_model_config['dict_path'])
  574. if params.table_char_dict_path is None:
  575. params.table_char_dict_path = str(
  576. Path(__file__).parent / table_model_config['dict_path'])
  577. if params.layout_dict_path is None:
  578. params.layout_dict_path = str(
  579. Path(__file__).parent / layout_model_config['dict_path'])
  580. logger.debug(params)
  581. super().__init__(params)
  582. def __call__(self, img, return_ocr_result_in_table=False, img_idx=0):
  583. img = check_img(img)
  584. res, _ = super().__call__(
  585. img, return_ocr_result_in_table, img_idx=img_idx)
  586. return res
  587. def main():
  588. # for cmd
  589. args = parse_args(mMain=True)
  590. image_dir = args.image_dir
  591. if is_link(image_dir):
  592. download_with_progressbar(image_dir, 'tmp.jpg')
  593. image_file_list = ['tmp.jpg']
  594. else:
  595. image_file_list = get_image_file_list(args.image_dir)
  596. if len(image_file_list) == 0:
  597. logger.error('no images find in {}'.format(args.image_dir))
  598. return
  599. if args.type == 'ocr':
  600. engine = PaddleOCR(**(args.__dict__))
  601. elif args.type == 'structure':
  602. engine = PPStructure(**(args.__dict__))
  603. else:
  604. raise NotImplementedError
  605. for img_path in image_file_list:
  606. img_name = os.path.basename(img_path).split('.')[0]
  607. logger.info('{}{}{}'.format('*' * 10, img_path, '*' * 10))
  608. if args.type == 'ocr':
  609. result = engine.ocr(img_path,
  610. det=args.det,
  611. rec=args.rec,
  612. cls=args.use_angle_cls)
  613. if result is not None:
  614. for idx in range(len(result)):
  615. res = result[idx]
  616. for line in res:
  617. logger.info(line)
  618. elif args.type == 'structure':
  619. img, flag_gif, flag_pdf = check_and_read(img_path)
  620. if not flag_gif and not flag_pdf:
  621. img = cv2.imread(img_path)
  622. if args.recovery and args.use_pdf2docx_api and flag_pdf:
  623. from pdf2docx.converter import Converter
  624. docx_file = os.path.join(args.output,
  625. '{}.docx'.format(img_name))
  626. cv = Converter(img_path)
  627. cv.convert(docx_file)
  628. cv.close()
  629. logger.info('docx save to {}'.format(docx_file))
  630. continue
  631. if not flag_pdf:
  632. if img is None:
  633. logger.error("error in loading image:{}".format(img_path))
  634. continue
  635. img_paths = [[img_path, img]]
  636. else:
  637. img_paths = []
  638. for index, pdf_img in enumerate(img):
  639. os.makedirs(
  640. os.path.join(args.output, img_name), exist_ok=True)
  641. pdf_img_path = os.path.join(
  642. args.output, img_name,
  643. img_name + '_' + str(index) + '.jpg')
  644. cv2.imwrite(pdf_img_path, pdf_img)
  645. img_paths.append([pdf_img_path, pdf_img])
  646. all_res = []
  647. for index, (new_img_path, img) in enumerate(img_paths):
  648. logger.info('processing {}/{} page:'.format(index + 1,
  649. len(img_paths)))
  650. new_img_name = os.path.basename(new_img_path).split('.')[0]
  651. result = engine(new_img_path, img_idx=index)
  652. save_structure_res(result, args.output, img_name, index)
  653. if args.recovery and result != []:
  654. from copy import deepcopy
  655. from ppstructure.recovery.recovery_to_doc import sorted_layout_boxes
  656. h, w, _ = img.shape
  657. result_cp = deepcopy(result)
  658. result_sorted = sorted_layout_boxes(result_cp, w)
  659. all_res += result_sorted
  660. if args.recovery and all_res != []:
  661. try:
  662. from ppstructure.recovery.recovery_to_doc import convert_info_docx
  663. convert_info_docx(img, all_res, args.output, img_name)
  664. except Exception as ex:
  665. logger.error(
  666. "error in layout recovery image:{}, err msg: {}".format(
  667. img_name, ex))
  668. continue
  669. for item in all_res:
  670. item.pop('img')
  671. item.pop('res')
  672. logger.info(item)
  673. logger.info('result save to {}'.format(args.output))