server.py 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799
  1. import base64
  2. import glob
  3. import os
  4. import time
  5. import uuid
  6. import shutil
  7. import xml.etree.cElementTree as ET
  8. from urllib import parse, request
  9. import cv2
  10. import numpy as np
  11. import pypinyin
  12. import requests
  13. from PIL import Image
  14. from django.conf import settings
  15. from pdf2image import convert_from_path
  16. import segment.logging_config as logging
  17. from segment.image_operation.exam_segment import get_page_text
  18. from segment.image_operation.pre_segment import segment2parts
  19. from segment.image_operation.segment import joint_image
  20. from segment.image_operation.split_lines import line_split
  21. from segment.image_operation.utils import create_xml, resize_by_percent
  22. from segment.image_operation.utils import write_single_img
  23. from segment.models import OcrToken
  24. from segment.ocr.group_pictures import group_pictures
  25. from segment.ocr.group_text import group_text
  26. from segment.ocr.penguin_ocr import get_ocr_english_text
  27. logger = logging.getLogger(settings.LOGGING_TYPE)
  28. def convert_pil_to_jpeg(raw_img):
  29. if raw_img.mode == 'L':
  30. channels = raw_img.split()
  31. img = Image.merge("RGB", (channels[0], channels[0], channels[0]))
  32. elif raw_img.mode == 'RGB':
  33. img = raw_img
  34. elif raw_img.mode == 'RGBA':
  35. img = Image.new("RGB", raw_img.size, (255, 255, 255))
  36. img.paste(raw_img, mask=raw_img.split()[3]) # 3 is the alpha channel
  37. else:
  38. img = raw_img
  39. open_cv_image = np.array(img)
  40. return img, open_cv_image
  41. def opencv2base64(img):
  42. image = cv2.imencode('.jpg', img)[1]
  43. base64_data = str(base64.b64encode(image))[2:-1]
  44. return base64_data
  45. def get_dir_next_index_name(path, file_type):
  46. files_list = os.listdir(path)
  47. imgs_list = [file.replace(file_type, '') for file in files_list if file.endswith(file_type)]
  48. length = len(imgs_list)
  49. if length == 0:
  50. return 1
  51. else:
  52. index_name = max(imgs_list)
  53. return int(index_name) + 1
  54. def save_raw_image(subject, datetime, img_file, analysis_type):
  55. # 随机生成新的图片名,自定义路径。
  56. ext = img_file.name.split('.')[-1]
  57. raw_name = img_file.name[0:-len(ext) - 1]
  58. file_name = '{}_{}.{}'.format(raw_name, uuid.uuid4().hex[:10], 'jpg')
  59. raw_img = Image.open(img_file) # 读取上传的网络图像
  60. save_dir = os.path.join(settings.MEDIA_ROOT, analysis_type, subject, datetime)
  61. if not os.path.exists(save_dir):
  62. os.makedirs(save_dir)
  63. save_path = os.path.join(save_dir, file_name)
  64. channels = raw_img.split()
  65. if len(channels) >= 3:
  66. img = Image.merge("RGB", (channels[0], channels[1], channels[2]))
  67. open_cv_image = np.array(img)
  68. img_reload = open_cv_image[:, :, ::-1].copy()
  69. parts_list = segment2parts(img_reload, save_path)
  70. else:
  71. img = raw_img
  72. open_cv_image = np.array(img)
  73. parts_list = segment2parts(open_cv_image, save_path)
  74. # for part in parts_list:
  75. # with open(part['img_part'], 'rb') as f:
  76. # bin_img = f.read()
  77. # part['img_part'] = bin_img
  78. try:
  79. img.save(save_path)
  80. except Exception as e:
  81. raise e
  82. url_path = os.path.join(settings.MEDIA_URL, analysis_type, subject, datetime, file_name).replace('\\', '/')
  83. return save_path, parts_list, url_path
  84. def save_raw_image_without_segment(subject, datetime, img_file, analysis_type):
  85. # 随机生成新的图片名,自定义路径。
  86. ext = img_file.name.split('.')[-1]
  87. raw_name = img_file.name[0:-len(ext) - 1]
  88. file_name = '{}_{}.{}'.format(raw_name, uuid.uuid4().hex[:10], 'jpg')
  89. raw_img = Image.open(img_file) # 读取上传的网络图像
  90. save_dir = os.path.join(settings.MEDIA_ROOT, analysis_type, subject, datetime)
  91. if not os.path.exists(save_dir):
  92. os.makedirs(save_dir)
  93. save_path = os.path.join(save_dir, file_name)
  94. pil_img, open_cv_image = convert_pil_to_jpeg(raw_img)
  95. try:
  96. pil_img.save(save_path)
  97. shutil.copy(save_path, save_path.replace('.jpg', '_small.jpg'))
  98. except Exception as e:
  99. raise e
  100. url_path = os.path.join(settings.MEDIA_URL, analysis_type, subject, datetime, file_name).replace('\\', '/')
  101. return save_path, open_cv_image, url_path
  102. def save_raw_image_without_segment_formula(subject, datetime, img_file, analysis_type):
  103. # 随机生成新的图片名,自定义路径。
  104. ext = img_file.name.split('.')[-1]
  105. raw_name = img_file.name[0:-len(ext) - 1]
  106. file_name = '{}_{}.{}'.format(raw_name, uuid.uuid4().hex[:10], ext)
  107. raw_img = Image.open(img_file) # 读取上传的网络图像
  108. save_dir = os.path.join(settings.MEDIA_ROOT, analysis_type, subject, datetime)
  109. if not os.path.exists(save_dir):
  110. os.makedirs(save_dir)
  111. save_path = os.path.join(save_dir, file_name)
  112. channels = raw_img.split()
  113. # if ext == 'png' and len(channels) >= 3: # 公式ocr分割透明png
  114. # img = Image.merge("RGB", (channels[0], channels[1], channels[2]))
  115. # open_cv_image = np.array(img)
  116. # resize_img = resize_by_percent(open_cv_image, 0.5)
  117. #
  118. # else:
  119. # img = raw_img
  120. # open_cv_image = np.array(img)
  121. # resize_img = resize_by_percent(open_cv_image, 0.5)
  122. try:
  123. raw_img.save(save_path)
  124. # write_single_img(resize_img, save_path.replace('.jpg', '_small.jpg'))
  125. except Exception as e:
  126. raise e
  127. url_path = os.path.join(settings.MEDIA_URL, analysis_type, subject, datetime, file_name).replace('\\', '/')
  128. return save_path, url_path, raw_img
  129. def save_raw_image_in_jpeg(subject, datetime, img_file, analysis_type):
  130. # 随机生成新的图片名,自定义路径。
  131. ext = img_file.name.split('.')[-1]
  132. raw_name = img_file.name[0:-len(ext) - 1]
  133. file_name = '{}_{}.{}'.format(raw_name, uuid.uuid4().hex[:10], 'jpg')
  134. raw_img = Image.open(img_file) # 读取上传的网络图像
  135. save_dir = os.path.join(settings.MEDIA_ROOT, analysis_type, subject, datetime)
  136. if not os.path.exists(save_dir):
  137. os.makedirs(save_dir)
  138. save_path = os.path.join(save_dir, file_name)
  139. if raw_img.mode == 'L':
  140. channels = raw_img.split()
  141. img = Image.merge("RGB", (channels[0], channels[0], channels[0]))
  142. elif raw_img.mode == 'RGB':
  143. img = raw_img
  144. elif raw_img.mode == 'RGBA':
  145. img = Image.new("RGB", raw_img.size, (255, 255, 255))
  146. img.paste(raw_img, mask=raw_img.split()[3]) # 3 is the alpha channel
  147. else:
  148. img = raw_img
  149. open_cv_image = np.array(img)
  150. # resize_img = resize_by_percent(open_cv_image, 0.5)
  151. try:
  152. img.save(save_path)
  153. # write_single_img(resize_img, save_path.replace('.jpg', '_small.jpg'))
  154. except Exception as e:
  155. raise e
  156. url_path = os.path.join(settings.MEDIA_URL, analysis_type, subject, datetime, file_name).replace('\\', '/')
  157. return save_path, url_path, open_cv_image
  158. def ocr_login():
  159. def login():
  160. grant_type = 'client_credentials'
  161. client_id = settings.OCR_CLIENT_ID
  162. client_secret = settings.OCR_CLIENT_SECRET
  163. textmod = {'grant_type': grant_type, 'client_id': client_id, 'client_secret': client_secret}
  164. textmod = parse.urlencode(textmod)
  165. # 输出内容:user=admin&password=admin
  166. header_dict = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko'}
  167. url = 'https://aip.baidubce.com/oauth/2.0/token'
  168. req = request.Request(url='{}{}{}'.format(url, '?', textmod), headers=header_dict)
  169. res = request.urlopen(req).read()
  170. token = eval(res.decode(encoding='utf-8'))['access_token']
  171. lastest_access_token = OcrToken(access_token=token)
  172. lastest_access_token.save()
  173. return token
  174. objects = OcrToken.objects.latest('update_time')
  175. lastest_access_token_db = objects.access_token
  176. lastest_date = objects.update_time
  177. ans_time = time.mktime(lastest_date.timetuple())
  178. update_date = settings.OCR_TOKEN_UPDATE_DATE
  179. current_time = time.time()
  180. if (ans_time + update_date * 24 * 60 * 60) > current_time:
  181. return lastest_access_token_db
  182. else:
  183. return login()
  184. def get_exam_bbox_by_tesseract(img_raw_name, img_path, subject):
  185. error_info = ''
  186. status = 1
  187. text = []
  188. lines_save_dir = img_path.replace('.jpg', '_lines')
  189. img_path = os.path.abspath(img_path)
  190. lines_save_dir = os.path.abspath(lines_save_dir)
  191. if not os.path.exists(lines_save_dir):
  192. os.makedirs(lines_save_dir)
  193. start_time = time.time()
  194. try:
  195. bbox, lines_abs_path_list = line_split(img_path, lines_save_dir, settings.TOLERANCE_PIX_NUMBER) # 分行
  196. except Exception as e:
  197. logger.error('line_split failed: {}'.format(e), exc_info=True)
  198. status = 0
  199. error_info = str(e)
  200. info = {'is_success': status, 'img_name': img_raw_name, 'coordinate': text, 'error': error_info}
  201. return info
  202. time1 = time.time()
  203. logger.info('lines_segment, cost: {}'.format(time1 - start_time))
  204. exam_group = []
  205. try:
  206. _, exam_group = group_pictures(lines_abs_path_list, subject)
  207. logger.info('exam_group info : {}'.format(exam_group))
  208. except (SystemExit, KeyboardInterrupt):
  209. raise
  210. except Exception as e:
  211. logger.error('ocr failed: {}'.format(e), exc_info=True)
  212. status = 0
  213. error_info = error_info + str(e)
  214. time2 = time.time()
  215. logger.info('exam_grouped, cost: {}'.format(time2 - time1))
  216. try:
  217. text = joint_image(img_path, bbox, exam_group)
  218. except (SystemExit, KeyboardInterrupt):
  219. raise
  220. except Exception as e:
  221. logger.error('generate coordinate info failed: {}'.format(e), exc_info=True)
  222. status = 0
  223. error_info = error_info + str(e)
  224. info = {'img_name': img_raw_name, 'coordinate': text}
  225. if error_info:
  226. info = {'img_name': img_raw_name, 'coordinate': text, 'error': error_info}
  227. logger.info('{} done'.format(img_raw_name))
  228. return status, info
  229. def get_ocr_text(access_token, img, subject=None):
  230. textmod = {'access_token': access_token}
  231. textmod = parse.urlencode(textmod)
  232. url = '{}{}{}{}{}'.format(settings.OCR_URL, settings.OCR_ACCURACY, '_basic', '?', textmod)
  233. url_general = '{}{}{}{}{}'.format(settings.OCR_URL, 'general', '_basic', '?', textmod)
  234. headers = {'Content-Type': 'application/x-www-form-urlencoded'}
  235. # image = opecv2base64(img) # 得到 byte 编码的数据
  236. image = img
  237. data = {
  238. 'image': image,
  239. 'detect_direction': 'true',
  240. 'language_type': 'CHN_ENG',
  241. }
  242. if subject == 'english':
  243. resp = requests.post(url, data=data, headers=headers).json()
  244. else:
  245. resp = requests.post(url, data=data, headers=headers).json()
  246. if resp.get('error_msg'):
  247. if 'internal error' in resp.get('error_msg'):
  248. resp = requests.post(url_general, data=data, headers=headers).json()
  249. if resp.get('error_msg'):
  250. raise Exception("ocr {}!".format(resp.get('error_msg')))
  251. else:
  252. raise Exception("ocr {}!".format(resp.get('error_msg')))
  253. words_result = resp.get('words_result')
  254. text_list = [word.get('words') for word in words_result]
  255. # words_list = {'word': text_list, 'subject': subject}
  256. return text_list
  257. def get_ocr_text_and_coordinate_in_raw_format(access_token, img):
  258. textmod = {'access_token': access_token}
  259. textmod = parse.urlencode(textmod)
  260. url = '{}{}{}{}'.format(settings.OCR_BOX_URL, settings.OCR_ACCURACY, '?', textmod)
  261. url_general = '{}{}{}{}'.format(settings.OCR_BOX_URL, 'general', '?', textmod)
  262. headers = {'Content-Type': 'application/x-www-form-urlencoded'}
  263. image_type = 'base64'
  264. group_id = 'group001'
  265. user_id = 'usr001'
  266. # image = base64.b64encode(img) # 得到 byte 编码的数据
  267. image = img
  268. data = {
  269. 'image_type': image_type,
  270. 'group_id': group_id,
  271. 'user_id': user_id,
  272. 'image': image,
  273. 'detect_direction': 'true',
  274. 'recognize_granularity': 'small',
  275. # 'vertexes_location': 'true',
  276. # 'probability': 'true'
  277. }
  278. resp = requests.post(url, data=data, headers=headers).json()
  279. if resp.get('error_msg'):
  280. if 'internal error' in resp.get('error_msg'):
  281. resp = requests.post(url_general, data=data, headers=headers).json()
  282. if resp.get('error_msg'):
  283. raise Exception("ocr {}!".format(resp.get('error_msg')))
  284. else:
  285. raise Exception("ocr {}!".format(resp.get('error_msg')))
  286. return resp
  287. def get_ocr_text_and_coordinate(access_token, img):
  288. textmod = {'access_token': access_token}
  289. textmod = parse.urlencode(textmod)
  290. url = '{}{}{}{}'.format(settings.OCR_BOX_URL, settings.OCR_ACCURACY, '?', textmod)
  291. url_general = '{}{}{}{}'.format(settings.OCR_BOX_URL, 'general', '?', textmod)
  292. headers = {'Content-Type': 'application/x-www-form-urlencoded'}
  293. image_type = 'base64'
  294. group_id = 'group001'
  295. user_id = 'usr001'
  296. # image = base64.b64encode(img) # 得到 byte 编码的数据
  297. image = img
  298. data = {
  299. 'image_type': image_type,
  300. 'group_id': group_id,
  301. 'user_id': user_id,
  302. 'image': image,
  303. 'detect_direction': 'true',
  304. # 'recognize_granularity': 'small',
  305. # 'vertexes_location': 'true',
  306. # 'probability': 'true'
  307. }
  308. resp = requests.post(url, data=data, headers=headers).json()
  309. if resp.get('error_msg'):
  310. if 'internal error' in resp.get('error_msg'):
  311. resp = requests.post(url_general, data=data, headers=headers).json()
  312. if resp.get('error_msg'):
  313. raise Exception("ocr {}!".format(resp.get('error_msg')))
  314. else:
  315. raise Exception("ocr {}!".format(resp.get('error_msg')))
  316. words_result = resp.get('words_result')
  317. text_list = [word.get('words') for word in words_result]
  318. # words_list = {'word': text_list, 'subject': subject}
  319. matrix_lt, matrix_rb = resolve_json(words_result)
  320. return text_list, matrix_lt, matrix_rb
  321. def get_ocr_text_and_coordinate_formula(img, access_token, base64=False):
  322. textmod = {'access_token': access_token}
  323. textmod = parse.urlencode(textmod)
  324. url = '{}{}{}{}'.format(settings.OCR_BOX_URL, settings.OCR_ACCURACY, '?', textmod)
  325. url_general = '{}{}{}{}'.format(settings.OCR_BOX_URL, 'general', '?', textmod)
  326. headers = {'Content-Type': 'application/x-www-form-urlencoded'}
  327. image_type = 'base64'
  328. group_id = 'group001'
  329. user_id = 'usr001'
  330. if base64:
  331. image = img
  332. else:
  333. image = opencv2base64(img)
  334. data = {
  335. 'image_type': image_type,
  336. 'group_id': group_id,
  337. 'user_id': user_id,
  338. 'image': image,
  339. 'detect_direction': 'true',
  340. 'recognize_granularity': 'small',
  341. 'language_type': 'CHN_ENG',
  342. # 'vertexes_location': 'true',
  343. # 'probability': 'true'
  344. }
  345. resp = requests.post(url, data=data, headers=headers).json()
  346. if resp.get('error_msg'):
  347. if 'internal error' in resp.get('error_msg'):
  348. resp = requests.post(url_general, data=data, headers=headers).json()
  349. if resp.get('error_msg'):
  350. raise Exception("ocr {}!".format(resp.get('error_msg')))
  351. else:
  352. raise Exception("ocr {}!".format(resp.get('error_msg')))
  353. words_result = resp.get('words_result')
  354. return words_result
  355. def resolve_json(words_result):
  356. box_list = [item[key] for item in words_result for key in item if key == 'location']
  357. matrix = np.array([0, 0, 0, 0])
  358. for box in box_list:
  359. # num_list = list(box.values())
  360. w = box.get('width')
  361. l = box.get('left')
  362. t = box.get('top')
  363. h = box.get('height')
  364. num_list = [w, t, l, h]
  365. matrix = np.vstack([matrix, np.array(num_list)])
  366. matrix = matrix[1:]
  367. matrix_w = matrix[:, 0:1]
  368. matrix_t = matrix[:, 1:2]
  369. matrix_l = matrix[:, 2:3]
  370. matrix_h = matrix[:, 3:]
  371. matrix_lt = np.hstack([matrix_l, matrix_t])
  372. matrix_wh = np.hstack([matrix_w, matrix_h])
  373. matrix_rb = matrix_lt + matrix_wh
  374. return matrix_lt, matrix_rb
  375. def group_to_coordinate(group_list, matrix_lt, matrix_rb):
  376. matrix_box_vlist = np.array([0, 0, 0, 0])
  377. for element in group_list:
  378. if element[0] < element[1]:
  379. rb = matrix_rb[element[0]:element[1]].max(axis=0)
  380. lt = matrix_lt[element[0]:element[1]].min(axis=0)
  381. matrix_box = np.hstack([lt, rb])
  382. matrix_box_vlist = np.vstack([matrix_box_vlist, matrix_box])
  383. matrix_box_vlist = matrix_box_vlist[1:]
  384. return matrix_box_vlist.tolist()
  385. def get_exam_box(img_raw_name, img_list, save_path, subject, access_token):
  386. status = 1
  387. error_info = ''
  388. box_list = []
  389. words_list_all = []
  390. group_list_all = []
  391. try:
  392. for img_part in img_list:
  393. x_bias = img_part['x_bias']
  394. y_bias = img_part['y_bias']
  395. img = img_part['img_part']
  396. words_list, matrix_lt, matrix_rb = get_ocr_text_and_coordinate(access_token, img)
  397. matrix_lt = matrix_lt + np.asarray([x_bias, y_bias])
  398. matrix_rb = matrix_rb + np.asarray([x_bias, y_bias])
  399. group_list = group_text(words_list, subject)
  400. part_box_list = group_to_coordinate(group_list, matrix_lt, matrix_rb)
  401. box_list = box_list + part_box_list
  402. words_list.append('********************************')
  403. words_list_all = words_list_all + words_list
  404. group_list_all.append(group_list)
  405. try:
  406. txt_backup_path = save_path.replace('.jpg', '.txt')
  407. words_list = [line + ',\n' for line in words_list_all]
  408. with open(txt_backup_path, 'w', encoding='utf-8') as writer:
  409. writer.writelines('subject:' + subject + '\n')
  410. writer.writelines('[\n')
  411. writer.writelines(words_list)
  412. writer.writelines(']\n')
  413. writer.writelines(str(group_list_all))
  414. logger.info('{}试卷: {} 文本信息保存成功'.format(subject, img_raw_name))
  415. except Exception as e:
  416. logger.error('{}试卷: {} 文本信息保存失败: {}'.format(subject, img_raw_name, e), exc_info=True)
  417. # 记录xml坐标信息
  418. tree = ET.parse(r'./segment/exam_info/000000-template.xml') # xml tree
  419. for index_num, exam_bbox in enumerate(box_list):
  420. tree = create_xml('{:02d}'.format(index_num), tree,
  421. exam_bbox[0], exam_bbox[1], exam_bbox[2], exam_bbox[3])
  422. # print(exam_items_bbox)
  423. tree.write(save_path.replace('.jpg', '.xml'))
  424. except Exception as e:
  425. logger.error('{}试卷: {} 坐标生成失败: {}'.format(subject, img_raw_name, e), exc_info=True)
  426. status = 0
  427. error_info = error_info + str(e)
  428. info = {'img_name': img_raw_name, 'coordinate': box_list}
  429. if error_info:
  430. info = {'img_name': img_raw_name, 'coordinate': box_list, 'error': error_info}
  431. logger.info('{} done'.format(img_raw_name))
  432. return status, info
  433. def get_exam_ocr(img_raw_name, img_list, save_path, subject, access_token):
  434. status = 1
  435. error_info = ''
  436. words_list = []
  437. for img_part in img_list:
  438. img = img_part['img_part']
  439. try:
  440. part_words_list = get_ocr_text(access_token, img, subject)
  441. except Exception as e:
  442. part_words_list = []
  443. error_info = error_info + str(e)
  444. words_list = words_list + part_words_list
  445. if len(words_list) < 1:
  446. logger.error('{}试卷: {} OCR解析失败: {}'.format(subject, img_raw_name, error_info), exc_info=True)
  447. status = 0
  448. else:
  449. try:
  450. txt_backup_path = save_path.replace('.jpg', '.txt')
  451. words_list = [line + '\n' for line in words_list]
  452. # # words_list.append(group_list)
  453. with open(txt_backup_path, 'w', encoding='utf-8') as writer:
  454. writer.writelines('subject:' + subject + '\n')
  455. writer.writelines('[\n')
  456. writer.writelines(words_list)
  457. writer.writelines(']\n')
  458. logger.info('{}试卷: {} 文本信息保存成功'.format(subject, img_raw_name))
  459. except Exception as e:
  460. logger.error('{}试卷: {} 文本信息保存失败: {}'.format(subject, img_raw_name, e), exc_info=True)
  461. info = {'img_name': img_raw_name, 'text': words_list}
  462. if error_info:
  463. info = {'img_name': img_raw_name, 'text': words_list, 'error': error_info}
  464. logger.info('{} done'.format(img_raw_name))
  465. return status, info
  466. def get_exam_ocr_single(img_raw_name, img, save_path, subject, access_token):
  467. status = 1
  468. error_info = ''
  469. words_list = []
  470. try:
  471. part_words_list = get_ocr_text(access_token, img)
  472. except Exception as e:
  473. part_words_list = []
  474. error_info = error_info + str(e)
  475. words_list = words_list + part_words_list
  476. if len(words_list) < 1:
  477. logger.error('{}试卷: {} OCR解析失败: {}'.format(subject, img_raw_name, error_info), exc_info=True)
  478. status = 0
  479. else:
  480. try:
  481. txt_backup_path = save_path.replace('.jpg', '.txt')
  482. words_list = [line + ',\n' for line in words_list]
  483. # # words_list.append(group_list)
  484. with open(txt_backup_path, 'w', encoding='utf-8') as writer:
  485. writer.writelines('subject:' + subject + '\n')
  486. writer.writelines('[\n')
  487. writer.writelines(words_list)
  488. writer.writelines(']\n')
  489. logger.info('{}试卷: {} 文本信息保存成功'.format(subject, img_raw_name))
  490. except Exception as e:
  491. logger.error('{}试卷: {} 文本信息保存失败: {}'.format(subject, img_raw_name, e), exc_info=True)
  492. info = {'img_name': img_raw_name, 'text': words_list}
  493. if error_info:
  494. info = {'img_name': img_raw_name, 'text': words_list, 'error': error_info}
  495. logger.info('{} done'.format(img_raw_name))
  496. return status, info
  497. def get_segment_by_ocr_once(opencv_img, token, subject, save_path, img_raw_name):
  498. img = opencv2base64(opencv_img)
  499. resp = get_ocr_text_and_coordinate_in_raw_format(token, img)
  500. if len(opencv_img.shape) == 3:
  501. opencv_img = cv2.cvtColor(opencv_img, cv2.COLOR_BGR2GRAY)
  502. test_list = get_page_text(resp['words_result'], opencv_img)
  503. status = 1
  504. error_info = ''
  505. box_list = []
  506. words_list_all = []
  507. group_list_all = []
  508. try:
  509. for one_page_text in test_list:
  510. words_list = [word.get('words') for word in one_page_text]
  511. matrix_lt, matrix_rb = resolve_json(one_page_text)
  512. group_list = group_text(words_list, subject)
  513. part_box_list = group_to_coordinate(group_list, matrix_lt, matrix_rb)
  514. box_list = box_list + part_box_list
  515. words_list.append('********************************')
  516. words_list_all = words_list_all + words_list
  517. group_list_all.append(group_list)
  518. try:
  519. txt_backup_path = save_path.replace('.jpg', '.txt')
  520. words_list = [line + '\n' for line in words_list_all]
  521. with open(txt_backup_path, 'w', encoding='utf-8') as writer:
  522. writer.writelines('subject:' + subject + '\n')
  523. writer.writelines('[\n')
  524. writer.writelines(words_list)
  525. writer.writelines(']\n')
  526. writer.writelines(str(group_list_all))
  527. logger.info('{}试卷: {} 文本信息保存成功'.format(subject, img_raw_name))
  528. except Exception as e:
  529. logger.error('{}试卷: {} 文本信息保存失败: {}'.format(subject, img_raw_name, e), exc_info=True)
  530. # 记录xml坐标信息
  531. tree = ET.parse(r'./segment/exam_info/000000-template.xml') # xml tree
  532. for index_num, exam_bbox in enumerate(box_list):
  533. tree = create_xml('{:02d}'.format(index_num), tree,
  534. exam_bbox[0], exam_bbox[1], exam_bbox[2], exam_bbox[3])
  535. # print(exam_items_bbox)
  536. tree.write(save_path.replace('.jpg', '.xml'))
  537. except Exception as e:
  538. logger.error('{}试卷: {} 坐标生成失败: {}'.format(subject, img_raw_name, e), exc_info=True)
  539. status = 0
  540. error_info = error_info + str(e)
  541. info = {'img_name': img_raw_name, 'coordinate': box_list}
  542. if error_info:
  543. info = {'img_name': img_raw_name, 'coordinate': box_list, 'error': error_info}
  544. logger.info('{} done'.format(img_raw_name))
  545. return status, info
  546. # opencv_img, token, subject, save_path, img_raw_name
  547. def get_exam_ocr_once(opencv_img, token, subject, save_path, img_raw_name):
  548. img = opencv2base64(opencv_img)
  549. resp = get_ocr_text_and_coordinate_in_raw_format(token, img)
  550. if len(opencv_img.shape) == 3:
  551. opencv_img = cv2.cvtColor(opencv_img, cv2.COLOR_BGR2GRAY)
  552. test_list = get_page_text(resp['words_result'], opencv_img)
  553. words_list = []
  554. for one_page_raw_text in test_list:
  555. one_page_words_list = [word.get('words') for word in one_page_raw_text]
  556. words_list = words_list + one_page_words_list
  557. status = 1
  558. error_info = ''
  559. if len(words_list) < 1:
  560. logger.error('{}试卷: {} OCR解析失败: {}'.format(subject, img_raw_name, error_info), exc_info=True)
  561. status = 0
  562. else:
  563. try:
  564. txt_backup_path = save_path.replace('.jpg', '.txt')
  565. words_list = [line + '\n' for line in words_list]
  566. # # words_list.append(group_list)
  567. with open(txt_backup_path, 'w', encoding='utf-8') as writer:
  568. writer.writelines('subject:' + subject + '\n')
  569. writer.writelines('[\n')
  570. writer.writelines(words_list)
  571. writer.writelines(']\n')
  572. logger.info('{}试卷: {} 文本信息保存成功'.format(subject, img_raw_name))
  573. except Exception as e:
  574. logger.error('{}试卷: {} 文本信息保存失败: {}'.format(subject, img_raw_name, e), exc_info=True)
  575. info = {'img_name': img_raw_name, 'text': words_list}
  576. if error_info:
  577. info = {'img_name': img_raw_name, 'text': words_list, 'error': error_info}
  578. logger.info('{} done'.format(img_raw_name))
  579. return status, info
  580. def save_pdf_image(pdf_file, subject, time_str):
  581. name = pdf_file.name[:-4]
  582. ext0 = pdf_file.name.split('.')[-1]
  583. raw_name0 = ''.join([''.join(i) for i in pypinyin.pinyin(name, style=pypinyin.NORMAL)])
  584. save_dir0 = os.sep.join(
  585. [settings.MEDIA_ROOT, 'ocr', subject, time_str, raw_name0 + '_{}'.format(uuid.uuid4().hex[:10])])
  586. if not os.path.exists(save_dir0):
  587. os.makedirs(save_dir0)
  588. pdf_path = os.sep.join([save_dir0, raw_name0 + '.' + ext0])
  589. with open(pdf_path, 'wb') as pdfFileObj:
  590. for chunk in pdf_file.chunks():
  591. pdfFileObj.write(chunk)
  592. images_list = convert_from_path(pdf_path, dpi=200, output_folder=save_dir0,
  593. output_file='image',
  594. first_page=None, last_page=None, fmt='JPEG')
  595. upload_img_path_list = glob.glob(os.sep.join([save_dir0, '*.jpg']))
  596. try:
  597. images_list = [cv2.cvtColor(np.asarray(ele), cv2.COLOR_RGB2BGR) for ele in images_list]
  598. except Exception:
  599. images_list = [np.asarray(ele) for ele in images_list]
  600. return upload_img_path_list, images_list
  601. def save_raw_image_without_segment_pdf(subject, datetime, raw_name, img_file, analysis_type):
  602. # 随机生成新的图片名,自定义路径。
  603. file_name = '{}_{}.{}'.format(raw_name, uuid.uuid4().hex[:10], 'jpg')
  604. raw_img = Image.open(img_file) # 读取上传的网络图像
  605. save_dir = os.path.join(settings.MEDIA_ROOT, analysis_type, subject, datetime)
  606. if not os.path.exists(save_dir):
  607. os.makedirs(save_dir)
  608. save_path = os.path.join(save_dir, file_name)
  609. channels = raw_img.split()
  610. if len(channels) > 3:
  611. img = Image.merge("RGB", (channels[1], channels[2], channels[3]))
  612. open_cv_image = np.array(img)
  613. resize_img = resize_by_percent(open_cv_image, 0.5)
  614. else:
  615. img = raw_img
  616. open_cv_image = np.array(img)
  617. resize_img = resize_by_percent(open_cv_image, 0.5)
  618. try:
  619. img.save(save_path)
  620. # write_single_img(resize_img, save_path.replace('.jpg', '_small.jpg'))
  621. except Exception as e:
  622. raise e
  623. url_path = os.path.join(settings.MEDIA_URL, analysis_type, subject, datetime, file_name).replace('\\', '/')
  624. return save_path, url_path, open_cv_image
  625. def get_exam_ocr_by_penguin(img_raw_name, raw_image, size, save_path, subject):
  626. status = 1
  627. error_info = ''
  628. words_list = []
  629. try:
  630. words_list = get_ocr_english_text(raw_image, size)
  631. except Exception as e:
  632. error_info = error_info + str(e)
  633. if len(words_list) < 1:
  634. logger.error('{}试卷: {} OCR解析失败: {}'.format(subject, img_raw_name, error_info), exc_info=True)
  635. status = 0
  636. else:
  637. try:
  638. txt_backup_path = save_path.replace('.jpg', '.txt')
  639. words_list = [line + '\n' for line in words_list]
  640. # # words_list.append(group_list)
  641. with open(txt_backup_path, 'w', encoding='utf-8') as writer:
  642. writer.writelines('subject:' + subject + '\n')
  643. writer.writelines('[\n')
  644. writer.writelines(words_list)
  645. writer.writelines(']\n')
  646. logger.info('{}试卷: {} 文本信息保存成功'.format(subject, img_raw_name))
  647. except Exception as e:
  648. logger.error('{}试卷: {} 文本信息保存失败: {}'.format(subject, img_raw_name, e), exc_info=True)
  649. info = {'img_name': img_raw_name, 'text': words_list}
  650. if error_info:
  651. info = {'img_name': img_raw_name, 'text': words_list, 'error': error_info}
  652. logger.info('{} done'.format(img_raw_name))
  653. return status, info