|
|
|
@ -1,3 +1,17 @@
|
|
|
|
|
# copyright (c) 2022 PaddlePaddle Authors. All Rights Reserve.
|
|
|
|
|
#
|
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
|
# You may obtain a copy of the License at
|
|
|
|
|
#
|
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
#
|
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
|
# limitations under the License.
|
|
|
|
|
|
|
|
|
|
import sys
|
|
|
|
|
import tarfile
|
|
|
|
|
import os
|
|
|
|
@ -20,7 +34,6 @@ root = os.path.abspath(os.path.join(file, '../../'))
|
|
|
|
|
sys.path.append(file)
|
|
|
|
|
sys.path.insert(0, root)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from ppstructure.predict_system import StructureSystem, save_structure_res
|
|
|
|
|
from ppstructure.utility import parse_args, draw_structure_result
|
|
|
|
|
from ppocr.utils.network import download_with_progressbar
|
|
|
|
@ -32,13 +45,17 @@ __VERSION__ = "0.2.2"
|
|
|
|
|
|
|
|
|
|
URLs_EN = {
|
|
|
|
|
# 下载超英文轻量级PP-OCRv3模型的检测模型并解压
|
|
|
|
|
"en_PP-OCRv3_det_infer": "https://paddleocr.bj.bcebos.com/PP-OCRv3/english/en_PP-OCRv3_det_infer.tar",
|
|
|
|
|
"en_PP-OCRv3_det_infer":
|
|
|
|
|
"https://paddleocr.bj.bcebos.com/PP-OCRv3/english/en_PP-OCRv3_det_infer.tar",
|
|
|
|
|
# 下载英文轻量级PP-OCRv3模型的识别模型并解压
|
|
|
|
|
"en_PP-OCRv3_rec_infer": "https://paddleocr.bj.bcebos.com/PP-OCRv3/english/en_PP-OCRv3_rec_infer.tar",
|
|
|
|
|
"en_PP-OCRv3_rec_infer":
|
|
|
|
|
"https://paddleocr.bj.bcebos.com/PP-OCRv3/english/en_PP-OCRv3_rec_infer.tar",
|
|
|
|
|
# 下载超轻量级英文表格英文模型并解压
|
|
|
|
|
"en_ppstructure_mobile_v2.0_SLANet_infer": "https://paddleocr.bj.bcebos.com/ppstructure/models/slanet/en_ppstructure_mobile_v2.0_SLANet_infer.tar",
|
|
|
|
|
"en_ppstructure_mobile_v2.0_SLANet_infer":
|
|
|
|
|
"https://paddleocr.bj.bcebos.com/ppstructure/models/slanet/en_ppstructure_mobile_v2.0_SLANet_infer.tar",
|
|
|
|
|
# 英文版面分析模型
|
|
|
|
|
"picodet_lcnet_x1_0_fgd_layout_infer": "https://paddleocr.bj.bcebos.com/ppstructure/models/layout/picodet_lcnet_x1_0_fgd_layout_infer.tar",
|
|
|
|
|
"picodet_lcnet_x1_0_fgd_layout_infer":
|
|
|
|
|
"https://paddleocr.bj.bcebos.com/ppstructure/models/layout/picodet_lcnet_x1_0_fgd_layout_infer.tar",
|
|
|
|
|
}
|
|
|
|
|
DICT_EN = {
|
|
|
|
|
"rec_char_dict_path": "en_dict.txt",
|
|
|
|
@ -47,13 +64,17 @@ DICT_EN = {
|
|
|
|
|
|
|
|
|
|
URLs_CN = {
|
|
|
|
|
# 下载超中文轻量级PP-OCRv3模型的检测模型并解压
|
|
|
|
|
"cn_PP-OCRv3_det_infer": "https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_det_infer.tar",
|
|
|
|
|
"cn_PP-OCRv3_det_infer":
|
|
|
|
|
"https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_det_infer.tar",
|
|
|
|
|
# 下载中文轻量级PP-OCRv3模型的识别模型并解压
|
|
|
|
|
"cn_PP-OCRv3_rec_infer": "https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_rec_infer.tar",
|
|
|
|
|
"cn_PP-OCRv3_rec_infer":
|
|
|
|
|
"https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_rec_infer.tar",
|
|
|
|
|
# 下载超轻量级英文表格英文模型并解压
|
|
|
|
|
"cn_ppstructure_mobile_v2.0_SLANet_infer": "https://paddleocr.bj.bcebos.com/ppstructure/models/slanet/en_ppstructure_mobile_v2.0_SLANet_infer.tar",
|
|
|
|
|
"cn_ppstructure_mobile_v2.0_SLANet_infer":
|
|
|
|
|
"https://paddleocr.bj.bcebos.com/ppstructure/models/slanet/en_ppstructure_mobile_v2.0_SLANet_infer.tar",
|
|
|
|
|
# 中文版面分析模型
|
|
|
|
|
"picodet_lcnet_x1_0_fgd_layout_cdla_infer": "https://paddleocr.bj.bcebos.com/ppstructure/models/layout/picodet_lcnet_x1_0_fgd_layout_cdla_infer.tar",
|
|
|
|
|
"picodet_lcnet_x1_0_fgd_layout_cdla_infer":
|
|
|
|
|
"https://paddleocr.bj.bcebos.com/ppstructure/models/layout/picodet_lcnet_x1_0_fgd_layout_cdla_infer.tar",
|
|
|
|
|
}
|
|
|
|
|
DICT_CN = {
|
|
|
|
|
"rec_char_dict_path": "ppocr_keys_v1.txt",
|
|
|
|
@ -61,7 +82,6 @@ DICT_CN = {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def QImageToCvMat(incomingImage) -> np.array:
|
|
|
|
|
'''
|
|
|
|
|
Converts a QImage into an opencv MAT format
|
|
|
|
@ -167,8 +187,8 @@ class Worker(QThread):
|
|
|
|
|
try:
|
|
|
|
|
convert_info_docx(imgs, all_res, self.outputDir, img_name)
|
|
|
|
|
except Exception as ex:
|
|
|
|
|
print("error in layout recovery image:{}, err msg: {}".
|
|
|
|
|
format(img_name, ex))
|
|
|
|
|
print("error in layout recovery image:{}, err msg: {}".format(
|
|
|
|
|
img_name, ex))
|
|
|
|
|
print("Predict time : {:.3f}s".format(time_dict['all']))
|
|
|
|
|
print('result save to {}'.format(self.outputDir))
|
|
|
|
|
|
|
|
|
@ -185,10 +205,11 @@ class Worker(QThread):
|
|
|
|
|
and os.path.basename(image_file)[-3:] == 'pdf':
|
|
|
|
|
self.totalPageCnt += 1
|
|
|
|
|
self.progressBarRange.emit(self.totalPageCnt)
|
|
|
|
|
print('===============using use_pdf2docx_api===============')
|
|
|
|
|
print(
|
|
|
|
|
'===============using use_pdf2docx_api===============')
|
|
|
|
|
img_name = os.path.basename(image_file).split('.')[0]
|
|
|
|
|
docx_file = os.path.join(
|
|
|
|
|
self.outputDir, '{}.docx'.format(img_name))
|
|
|
|
|
docx_file = os.path.join(self.outputDir,
|
|
|
|
|
'{}.docx'.format(img_name))
|
|
|
|
|
cv = Converter(image_file)
|
|
|
|
|
cv.convert(docx_file)
|
|
|
|
|
cv.close()
|
|
|
|
@ -201,7 +222,8 @@ class Worker(QThread):
|
|
|
|
|
if len(imgs) == 0:
|
|
|
|
|
continue
|
|
|
|
|
img_name = os.path.basename(image_file).split('.')[0]
|
|
|
|
|
os.makedirs(os.path.join(self.outputDir, img_name), exist_ok=True)
|
|
|
|
|
os.makedirs(
|
|
|
|
|
os.path.join(self.outputDir, img_name), exist_ok=True)
|
|
|
|
|
self.ppocrPrecitor(imgs, img_name)
|
|
|
|
|
# file processed
|
|
|
|
|
self.endsignal.emit()
|
|
|
|
@ -222,8 +244,7 @@ class APP_Image2Doc(QWidget):
|
|
|
|
|
self.screenShot = None
|
|
|
|
|
self.save_pdf = False
|
|
|
|
|
self.output_dir = None
|
|
|
|
|
self.vis_font_path = os.path.join(root,
|
|
|
|
|
"doc", "fonts", "simfang.ttf")
|
|
|
|
|
self.vis_font_path = os.path.join(root, "doc", "fonts", "simfang.ttf")
|
|
|
|
|
self.use_pdf2docx_api = False
|
|
|
|
|
|
|
|
|
|
# ProgressBar
|
|
|
|
@ -245,8 +266,10 @@ class APP_Image2Doc(QWidget):
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 设置工作进程
|
|
|
|
|
self._thread = Worker(predictors, self.save_pdf, self.vis_font_path, self.use_pdf2docx_api)
|
|
|
|
|
self._thread.progressBarValue.connect(self.handleProgressBarUpdateSingal)
|
|
|
|
|
self._thread = Worker(predictors, self.save_pdf, self.vis_font_path,
|
|
|
|
|
self.use_pdf2docx_api)
|
|
|
|
|
self._thread.progressBarValue.connect(
|
|
|
|
|
self.handleProgressBarUpdateSingal)
|
|
|
|
|
self._thread.endsignal.connect(self.handleEndsignalSignal)
|
|
|
|
|
# self._thread.finished.connect(QObject.deleteLater)
|
|
|
|
|
self._thread.progressBarRange.connect(self.handleProgressBarRangeSingal)
|
|
|
|
@ -294,8 +317,7 @@ class APP_Image2Doc(QWidget):
|
|
|
|
|
# ProgressBar
|
|
|
|
|
layout.addWidget(self.pb, 2, 0, 1, 5)
|
|
|
|
|
# time estimate label
|
|
|
|
|
self.timeEstLabel = QLabel(
|
|
|
|
|
("Time Left: --"))
|
|
|
|
|
self.timeEstLabel = QLabel(("Time Left: --"))
|
|
|
|
|
layout.addWidget(self.timeEstLabel, 3, 0, 1, 5)
|
|
|
|
|
|
|
|
|
|
self.setLayout(layout)
|
|
|
|
@ -303,11 +325,8 @@ class APP_Image2Doc(QWidget):
|
|
|
|
|
def downloadModels(self, URLs):
|
|
|
|
|
# using custom model
|
|
|
|
|
tar_file_name_list = [
|
|
|
|
|
'inference.pdiparams',
|
|
|
|
|
'inference.pdiparams.info',
|
|
|
|
|
'inference.pdmodel',
|
|
|
|
|
'model.pdiparams',
|
|
|
|
|
'model.pdiparams.info',
|
|
|
|
|
'inference.pdiparams', 'inference.pdiparams.info',
|
|
|
|
|
'inference.pdmodel', 'model.pdiparams', 'model.pdiparams.info',
|
|
|
|
|
'model.pdmodel'
|
|
|
|
|
]
|
|
|
|
|
model_path = os.path.join(root, 'inference')
|
|
|
|
@ -325,7 +344,8 @@ class APP_Image2Doc(QWidget):
|
|
|
|
|
try:
|
|
|
|
|
download_with_progressbar(url, tarpath)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
print("Error occurred when downloading file, error message:")
|
|
|
|
|
print(
|
|
|
|
|
"Error occurred when downloading file, error message:")
|
|
|
|
|
print(e)
|
|
|
|
|
|
|
|
|
|
# unzip model tar
|
|
|
|
@ -341,8 +361,7 @@ class APP_Image2Doc(QWidget):
|
|
|
|
|
if filename is None:
|
|
|
|
|
continue
|
|
|
|
|
file = tarObj.extractfile(member)
|
|
|
|
|
with open(
|
|
|
|
|
os.path.join(storage_dir, filename),
|
|
|
|
|
with open(os.path.join(storage_dir, filename),
|
|
|
|
|
'wb') as f:
|
|
|
|
|
f.write(file.read())
|
|
|
|
|
except Exception as e:
|
|
|
|
@ -356,37 +375,40 @@ class APP_Image2Doc(QWidget):
|
|
|
|
|
args.ocr = True
|
|
|
|
|
args.recovery = True
|
|
|
|
|
args.save_pdf = self.save_pdf
|
|
|
|
|
args.table_char_dict_path = os.path.join(root,
|
|
|
|
|
"ppocr", "utils", "dict", "table_structure_dict.txt")
|
|
|
|
|
args.table_char_dict_path = os.path.join(root, "ppocr", "utils", "dict",
|
|
|
|
|
"table_structure_dict.txt")
|
|
|
|
|
if lang == 'EN':
|
|
|
|
|
args.det_model_dir = os.path.join(root, # 此处从这里找到模型存放位置
|
|
|
|
|
"inference", "en_PP-OCRv3_det_infer")
|
|
|
|
|
args.rec_model_dir = os.path.join(root,
|
|
|
|
|
"inference", "en_PP-OCRv3_rec_infer")
|
|
|
|
|
args.table_model_dir = os.path.join(root,
|
|
|
|
|
"inference", "en_ppstructure_mobile_v2.0_SLANet_infer")
|
|
|
|
|
args.det_model_dir = os.path.join(
|
|
|
|
|
root, # 此处从这里找到模型存放位置
|
|
|
|
|
"inference",
|
|
|
|
|
"en_PP-OCRv3_det_infer")
|
|
|
|
|
args.rec_model_dir = os.path.join(root, "inference",
|
|
|
|
|
"en_PP-OCRv3_rec_infer")
|
|
|
|
|
args.table_model_dir = os.path.join(
|
|
|
|
|
root, "inference", "en_ppstructure_mobile_v2.0_SLANet_infer")
|
|
|
|
|
args.output = os.path.join(root, "output") # 结果保存路径
|
|
|
|
|
args.layout_model_dir = os.path.join(root,
|
|
|
|
|
"inference", "picodet_lcnet_x1_0_fgd_layout_infer")
|
|
|
|
|
args.layout_model_dir = os.path.join(
|
|
|
|
|
root, "inference", "picodet_lcnet_x1_0_fgd_layout_infer")
|
|
|
|
|
lang_dict = DICT_EN
|
|
|
|
|
elif lang == 'CN':
|
|
|
|
|
args.det_model_dir = os.path.join(root, # 此处从这里找到模型存放位置
|
|
|
|
|
"inference", "cn_PP-OCRv3_det_infer")
|
|
|
|
|
args.rec_model_dir = os.path.join(root,
|
|
|
|
|
"inference", "cn_PP-OCRv3_rec_infer")
|
|
|
|
|
args.table_model_dir = os.path.join(root,
|
|
|
|
|
"inference", "cn_ppstructure_mobile_v2.0_SLANet_infer")
|
|
|
|
|
args.det_model_dir = os.path.join(
|
|
|
|
|
root, # 此处从这里找到模型存放位置
|
|
|
|
|
"inference",
|
|
|
|
|
"cn_PP-OCRv3_det_infer")
|
|
|
|
|
args.rec_model_dir = os.path.join(root, "inference",
|
|
|
|
|
"cn_PP-OCRv3_rec_infer")
|
|
|
|
|
args.table_model_dir = os.path.join(
|
|
|
|
|
root, "inference", "cn_ppstructure_mobile_v2.0_SLANet_infer")
|
|
|
|
|
args.output = os.path.join(root, "output") # 结果保存路径
|
|
|
|
|
args.layout_model_dir = os.path.join(root,
|
|
|
|
|
"inference", "picodet_lcnet_x1_0_fgd_layout_cdla_infer")
|
|
|
|
|
args.layout_model_dir = os.path.join(
|
|
|
|
|
root, "inference", "picodet_lcnet_x1_0_fgd_layout_cdla_infer")
|
|
|
|
|
lang_dict = DICT_CN
|
|
|
|
|
else:
|
|
|
|
|
raise ValueError("Unsupported language")
|
|
|
|
|
args.rec_char_dict_path = os.path.join(root,
|
|
|
|
|
"ppocr", "utils",
|
|
|
|
|
args.rec_char_dict_path = os.path.join(root, "ppocr", "utils",
|
|
|
|
|
lang_dict['rec_char_dict_path'])
|
|
|
|
|
args.layout_dict_path = os.path.join(root,
|
|
|
|
|
"ppocr", "utils", "dict", "layout_dict",
|
|
|
|
|
args.layout_dict_path = os.path.join(root, "ppocr", "utils", "dict",
|
|
|
|
|
"layout_dict",
|
|
|
|
|
lang_dict['layout_dict_path'])
|
|
|
|
|
# init predictor
|
|
|
|
|
return StructureSystem(args)
|
|
|
|
@ -395,8 +417,8 @@ class APP_Image2Doc(QWidget):
|
|
|
|
|
'''
|
|
|
|
|
可以多选图像文件
|
|
|
|
|
'''
|
|
|
|
|
selectedFiles = QFileDialog.getOpenFileNames(self,
|
|
|
|
|
"多文件选择", "/", "图片文件 (*.png *.jpeg *.jpg *.bmp *.pdf)")[0]
|
|
|
|
|
selectedFiles = QFileDialog.getOpenFileNames(
|
|
|
|
|
self, "多文件选择", "/", "图片文件 (*.png *.jpeg *.jpg *.bmp *.pdf)")[0]
|
|
|
|
|
if len(selectedFiles) > 0:
|
|
|
|
|
self.imagePaths = selectedFiles
|
|
|
|
|
self.screenShot = None # discard screenshot temp image
|
|
|
|
@ -416,17 +438,18 @@ class APP_Image2Doc(QWidget):
|
|
|
|
|
|
|
|
|
|
def handleStartSignal(self, lang='EN', pdfParser=False):
|
|
|
|
|
if self.screenShot: # for screenShot
|
|
|
|
|
img_name = 'screenshot_' + time.strftime("%Y%m%d%H%M%S", time.localtime())
|
|
|
|
|
img_name = 'screenshot_' + time.strftime("%Y%m%d%H%M%S",
|
|
|
|
|
time.localtime())
|
|
|
|
|
image = QImageToCvMat(self.screenShot)
|
|
|
|
|
self.predictAndSave(image, img_name, lang)
|
|
|
|
|
# update Progress Bar
|
|
|
|
|
self.pb.setValue(1)
|
|
|
|
|
QMessageBox.information(self,
|
|
|
|
|
u'Information', "文档提取完成")
|
|
|
|
|
QMessageBox.information(self, u'Information', "文档提取完成")
|
|
|
|
|
elif len(self.imagePaths) > 0: # for image file selection
|
|
|
|
|
# Must set image path list and language before start
|
|
|
|
|
self.output_dir = os.path.join(
|
|
|
|
|
os.path.dirname(self.imagePaths[0]), "output") # output_dir shold be same as imagepath
|
|
|
|
|
os.path.dirname(self.imagePaths[0]),
|
|
|
|
|
"output") # output_dir shold be same as imagepath
|
|
|
|
|
self._thread.setOutputDir(self.output_dir)
|
|
|
|
|
self._thread.setImagePath(self.imagePaths)
|
|
|
|
|
self._thread.setLang(lang)
|
|
|
|
@ -439,11 +462,9 @@ class APP_Image2Doc(QWidget):
|
|
|
|
|
# 启动工作进程
|
|
|
|
|
self._thread.start()
|
|
|
|
|
self.time_start = time.time() # log start time
|
|
|
|
|
QMessageBox.information(self,
|
|
|
|
|
u'Information', "开始转换")
|
|
|
|
|
QMessageBox.information(self, u'Information', "开始转换")
|
|
|
|
|
else:
|
|
|
|
|
QMessageBox.warning(self,
|
|
|
|
|
u'Information', "请选择要识别的文件或截图")
|
|
|
|
|
QMessageBox.warning(self, u'Information', "请选择要识别的文件或截图")
|
|
|
|
|
|
|
|
|
|
def handleShowResultSignal(self):
|
|
|
|
|
if self.output_dir is None:
|
|
|
|
@ -454,15 +475,16 @@ class APP_Image2Doc(QWidget):
|
|
|
|
|
else:
|
|
|
|
|
os.system('open ' + os.path.normpath(self.output_dir))
|
|
|
|
|
else:
|
|
|
|
|
QMessageBox.information(self,
|
|
|
|
|
u'Information', "输出文件不存在")
|
|
|
|
|
QMessageBox.information(self, u'Information', "输出文件不存在")
|
|
|
|
|
|
|
|
|
|
def handleProgressBarUpdateSingal(self, i):
|
|
|
|
|
self.pb.setValue(i)
|
|
|
|
|
# calculate time left of recognition
|
|
|
|
|
lenbar = self.pb.maximum()
|
|
|
|
|
avg_time = (time.time() - self.time_start) / i # Use average time to prevent time fluctuations
|
|
|
|
|
time_left = str(datetime.timedelta(seconds=avg_time * (lenbar - i))).split(".")[0] # Remove microseconds
|
|
|
|
|
avg_time = (time.time() - self.time_start
|
|
|
|
|
) / i # Use average time to prevent time fluctuations
|
|
|
|
|
time_left = str(datetime.timedelta(seconds=avg_time * (
|
|
|
|
|
lenbar - i))).split(".")[0] # Remove microseconds
|
|
|
|
|
self.timeEstLabel.setText(f"Time Left: {time_left}") # show time left
|
|
|
|
|
|
|
|
|
|
def handleProgressBarRangeSingal(self, max):
|
|
|
|
|