paddleocr.py 30 KB

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