未验证 提交 7f6c9a7b 编写于 作者: E Evezerest 提交者: GitHub

Merge pull request #7782 from Evezerest/release2.6

[CP] new changes in PPOCRLabel
...@@ -2449,13 +2449,6 @@ class MainWindow(QMainWindow): ...@@ -2449,13 +2449,6 @@ class MainWindow(QMainWindow):
export PPLabel and CSV to JSON (PubTabNet) export PPLabel and CSV to JSON (PubTabNet)
''' '''
import pandas as pd import pandas as pd
from libs.dataPartitionDialog import DataPartitionDialog
# data partition user input
partitionDialog = DataPartitionDialog(parent=self)
partitionDialog.exec()
if partitionDialog.getStatus() == False:
return
# automatically save annotations # automatically save annotations
self.saveFilestate() self.saveFilestate()
...@@ -2478,28 +2471,19 @@ class MainWindow(QMainWindow): ...@@ -2478,28 +2471,19 @@ class MainWindow(QMainWindow):
labeldict[file] = eval(label) labeldict[file] = eval(label)
else: else:
labeldict[file] = [] labeldict[file] = []
# read table recognition output
TableRec_excel_dir = os.path.join(
self.lastOpenDir, 'tableRec_excel_output')
train_split, val_split, test_split = partitionDialog.getDataPartition() # save txt
# check validate fid = open(
if train_split + val_split + test_split > 100: "{}/gt.txt".format(self.lastOpenDir), "w", encoding='utf-8')
msg = "The sum of training, validation and testing data should be less than 100%"
QMessageBox.information(self, "Information", msg)
return
print(train_split, val_split, test_split)
train_split, val_split, test_split = float(train_split) / 100., float(val_split) / 100., float(test_split) / 100.
train_id = int(len(labeldict) * train_split)
val_id = int(len(labeldict) * (train_split + val_split))
print('Data partition: train:', train_id,
'validation:', val_id - train_id,
'test:', len(labeldict) - val_id)
TableRec_excel_dir = os.path.join(self.lastOpenDir, 'tableRec_excel_output')
json_results = []
imgid = 0
for image_path in labeldict.keys(): for image_path in labeldict.keys():
# load csv annotations # load csv annotations
filename, _ = os.path.splitext(os.path.basename(image_path)) filename, _ = os.path.splitext(os.path.basename(image_path))
csv_path = os.path.join(TableRec_excel_dir, filename + '.xlsx') csv_path = os.path.join(
TableRec_excel_dir, filename + '.xlsx')
if not os.path.exists(csv_path): if not os.path.exists(csv_path):
continue continue
...@@ -2518,28 +2502,31 @@ class MainWindow(QMainWindow): ...@@ -2518,28 +2502,31 @@ class MainWindow(QMainWindow):
cells = [] cells = []
for anno in labeldict[image_path]: for anno in labeldict[image_path]:
tokens = list(anno['transcription']) tokens = list(anno['transcription'])
obb = anno['points'] cells.append({
hbb = OBB2HBB(np.array(obb)).tolist() 'tokens': tokens,
cells.append({'tokens': tokens, 'bbox': hbb}) 'bbox': anno['points']
})
# data split
if imgid < train_id: # 构造标注信息
split = 'train' html = {
elif imgid < val_id: 'structure': {
split = 'val' 'tokens': token_list
else: },
split = 'test' 'cells': cells
}
# save dict d = {
html = {'structure': {'tokens': token_list}, 'cells': cells} 'filename': os.path.basename(image_path),
json_results.append({'filename': os.path.basename(image_path), 'split': split, 'imgid': imgid, 'html': html}) 'html': html
imgid += 1 }
# 重构HTML
# save json d['gt'] = rebuild_html_from_ppstructure_label(d)
with open("{}/annotation.json".format(self.lastOpenDir), "w", encoding='utf-8') as fid: fid.write('{}\n'.format(
fid.write(json.dumps(json_results, ensure_ascii=False)) json.dumps(
d, ensure_ascii=False)))
msg = 'JSON sucessfully saved in {}/annotation.json'.format(self.lastOpenDir)
# convert to PP-Structure label format
fid.close()
msg = 'JSON sucessfully saved in {}/gt.txt'.format(self.lastOpenDir)
QMessageBox.information(self, "Information", msg) QMessageBox.information(self, "Information", msg)
def autolcm(self): def autolcm(self):
...@@ -2728,6 +2715,9 @@ class MainWindow(QMainWindow): ...@@ -2728,6 +2715,9 @@ class MainWindow(QMainWindow):
self._update_shape_color(shape) self._update_shape_color(shape)
self.keyDialog.addLabelHistory(key_text) self.keyDialog.addLabelHistory(key_text)
# save changed shape
self.setDirty()
def undoShapeEdit(self): def undoShapeEdit(self):
self.canvas.restoreShape() self.canvas.restoreShape()
......
...@@ -105,9 +105,9 @@ python PPOCRLabel.py --kie True # [KIE mode] for [detection + recognition + keyw ...@@ -105,9 +105,9 @@ python PPOCRLabel.py --kie True # [KIE mode] for [detection + recognition + keyw
#### 1.2.3 Build and Install the Whl Package Locally #### 1.2.3 Build and Install the Whl Package Locally
Compile and install a new whl package, where 1.0.2 is the version number, you can specify the new version in 'setup.py'. Compile and install a new whl package, where 1.0.2 is the version number, you can specify the new version in 'setup.py'.
```bash ```bash
cd PaddleOCR/PPOCRLabel cd ./PPOCRLabel
python3 setup.py bdist_wheel python3 setup.py bdist_wheel
pip3 install dist/PPOCRLabel-1.0.2-py2.py3-none-any.whl pip3 install dist/PPOCRLabel-2.1.2-py2.py3-none-any.whl
``` ```
......
...@@ -104,9 +104,9 @@ python PPOCRLabel.py --lang ch ...@@ -104,9 +104,9 @@ python PPOCRLabel.py --lang ch
编译与安装新的whl包,其中1.0.2为版本号,可在 `setup.py` 中指定新版本。 编译与安装新的whl包,其中1.0.2为版本号,可在 `setup.py` 中指定新版本。
```bash ```bash
cd PaddleOCR/PPOCRLabel cd ./PPOCRLabel
python3 setup.py bdist_wheel python3 setup.py bdist_wheel
pip3 install dist/PPOCRLabel-1.0.2-py2.py3-none-any.whl -i https://mirror.baidu.com/pypi/simple pip3 install dist/PPOCRLabel-2.1.2-py2.py3-none-any.whl -i https://mirror.baidu.com/pypi/simple
``` ```
......
...@@ -611,8 +611,8 @@ class Canvas(QWidget): ...@@ -611,8 +611,8 @@ class Canvas(QWidget):
if self.drawing() and not self.prevPoint.isNull() and not self.outOfPixmap(self.prevPoint): if self.drawing() and not self.prevPoint.isNull() and not self.outOfPixmap(self.prevPoint):
p.setPen(QColor(0, 0, 0)) p.setPen(QColor(0, 0, 0))
p.drawLine(self.prevPoint.x(), 0, self.prevPoint.x(), self.pixmap.height()) p.drawLine(int(self.prevPoint.x()), 0, int(self.prevPoint.x()), self.pixmap.height())
p.drawLine(0, self.prevPoint.y(), self.pixmap.width(), self.prevPoint.y()) p.drawLine(0, int(self.prevPoint.y()), self.pixmap.width(), int(self.prevPoint.y()))
self.setAutoFillBackground(True) self.setAutoFillBackground(True)
if self.verified: if self.verified:
...@@ -909,4 +909,4 @@ class Canvas(QWidget): ...@@ -909,4 +909,4 @@ class Canvas(QWidget):
def updateShapeIndex(self): def updateShapeIndex(self):
for i in range(len(self.shapes)): for i in range(len(self.shapes)):
self.shapes[i].idx = i self.shapes[i].idx = i
self.update() self.update()
\ No newline at end of file
try:
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
except ImportError:
from PyQt4.QtGui import *
from PyQt4.QtCore import *
from libs.utils import newIcon
import time
import datetime
import json
import cv2
import numpy as np
BB = QDialogButtonBox
class DataPartitionDialog(QDialog):
def __init__(self, parent=None):
super().__init__()
self.parnet = parent
self.title = 'DATA PARTITION'
self.train_ratio = 70
self.val_ratio = 15
self.test_ratio = 15
self.initUI()
def initUI(self):
self.setWindowTitle(self.title)
self.setWindowModality(Qt.ApplicationModal)
self.flag_accept = True
if self.parnet.lang == 'ch':
msg = "导出JSON前请保存所有图像的标注且关闭EXCEL!"
else:
msg = "Please save all the annotations and close the EXCEL before exporting JSON!"
info_msg = QLabel(msg, self)
info_msg.setWordWrap(True)
info_msg.setStyleSheet("color: red")
info_msg.setFont(QFont('Arial', 12))
train_lbl = QLabel('Train split: ', self)
train_lbl.setFont(QFont('Arial', 15))
val_lbl = QLabel('Valid split: ', self)
val_lbl.setFont(QFont('Arial', 15))
test_lbl = QLabel('Test split: ', self)
test_lbl.setFont(QFont('Arial', 15))
self.train_input = QLineEdit(self)
self.train_input.setFont(QFont('Arial', 15))
self.val_input = QLineEdit(self)
self.val_input.setFont(QFont('Arial', 15))
self.test_input = QLineEdit(self)
self.test_input.setFont(QFont('Arial', 15))
self.train_input.setText(str(self.train_ratio))
self.val_input.setText(str(self.val_ratio))
self.test_input.setText(str(self.test_ratio))
validator = QIntValidator(0, 100)
self.train_input.setValidator(validator)
self.val_input.setValidator(validator)
self.test_input.setValidator(validator)
gridlayout = QGridLayout()
gridlayout.addWidget(info_msg, 0, 0, 1, 2)
gridlayout.addWidget(train_lbl, 1, 0)
gridlayout.addWidget(val_lbl, 2, 0)
gridlayout.addWidget(test_lbl, 3, 0)
gridlayout.addWidget(self.train_input, 1, 1)
gridlayout.addWidget(self.val_input, 2, 1)
gridlayout.addWidget(self.test_input, 3, 1)
bb = BB(BB.Ok | BB.Cancel, Qt.Horizontal, self)
bb.button(BB.Ok).setIcon(newIcon('done'))
bb.button(BB.Cancel).setIcon(newIcon('undo'))
bb.accepted.connect(self.validate)
bb.rejected.connect(self.cancel)
gridlayout.addWidget(bb, 4, 0, 1, 2)
self.setLayout(gridlayout)
self.show()
def validate(self):
self.flag_accept = True
self.accept()
def cancel(self):
self.flag_accept = False
self.reject()
def getStatus(self):
return self.flag_accept
def getDataPartition(self):
self.train_ratio = int(self.train_input.text())
self.val_ratio = int(self.val_input.text())
self.test_ratio = int(self.test_input.text())
return self.train_ratio, self.val_ratio, self.test_ratio
def closeEvent(self, event):
self.flag_accept = False
self.reject()
...@@ -176,18 +176,6 @@ def boxPad(box, imgShape, pad : int) -> np.array: ...@@ -176,18 +176,6 @@ def boxPad(box, imgShape, pad : int) -> np.array:
return box return box
def OBB2HBB(obb) -> np.array:
"""
Convert Oriented Bounding Box to Horizontal Bounding Box.
"""
hbb = np.zeros(4, dtype=np.int32)
hbb[0] = min(obb[:, 0])
hbb[1] = min(obb[:, 1])
hbb[2] = max(obb[:, 0])
hbb[3] = max(obb[:, 1])
return hbb
def expand_list(merged, html_list): def expand_list(merged, html_list):
''' '''
Fill blanks according to merged cells Fill blanks according to merged cells
...@@ -232,6 +220,26 @@ def convert_token(html_list): ...@@ -232,6 +220,26 @@ def convert_token(html_list):
return token_list return token_list
def rebuild_html_from_ppstructure_label(label_info):
from html import escape
html_code = label_info['html']['structure']['tokens'].copy()
to_insert = [
i for i, tag in enumerate(html_code) if tag in ('<td>', '>')
]
for i, cell in zip(to_insert[::-1], label_info['html']['cells'][::-1]):
if cell['tokens']:
cell = [
escape(token) if len(token) == 1 else token
for token in cell['tokens']
]
cell = ''.join(cell)
html_code.insert(i + 1, cell)
html_code = ''.join(html_code)
html_code = '<html><body><table>{}</table></body></html>'.format(
html_code)
return html_code
def stepsInfo(lang='en'): def stepsInfo(lang='en'):
if lang == 'ch': if lang == 'ch':
msg = "1. 安装与运行:使用上述命令安装与运行程序。\n" \ msg = "1. 安装与运行:使用上述命令安装与运行程序。\n" \
......
...@@ -113,4 +113,4 @@ keyDialogTip=Enter object label ...@@ -113,4 +113,4 @@ keyDialogTip=Enter object label
keyChange=Change Box Key keyChange=Change Box Key
TableRecognition=Table Recognition TableRecognition=Table Recognition
cellreRecognition=Cell Re-Recognition cellreRecognition=Cell Re-Recognition
exportJSON=Export Excel Label(PubTabNet) exportJSON=Export Table Label
...@@ -113,4 +113,4 @@ keyDialogTip=请输入类型名称 ...@@ -113,4 +113,4 @@ keyDialogTip=请输入类型名称
keyChange=更改Box关键字类别 keyChange=更改Box关键字类别
TableRecognition=表格识别 TableRecognition=表格识别
cellreRecognition=单元格重识别 cellreRecognition=单元格重识别
exportJSON=导出表格JSON标注 exportJSON=导出表格标注
\ No newline at end of file \ No newline at end of file
...@@ -33,7 +33,7 @@ setup( ...@@ -33,7 +33,7 @@ setup(
package_dir={'PPOCRLabel': ''}, package_dir={'PPOCRLabel': ''},
include_package_data=True, include_package_data=True,
entry_points={"console_scripts": ["PPOCRLabel= PPOCRLabel.PPOCRLabel:main"]}, entry_points={"console_scripts": ["PPOCRLabel= PPOCRLabel.PPOCRLabel:main"]},
version='2.1.1', version='2.1.2',
install_requires=requirements, install_requires=requirements,
license='Apache License 2.0', license='Apache License 2.0',
description='PPOCRLabel is a semi-automatic graphic annotation tool suitable for OCR field, with built-in PPOCR model to automatically detect and re-recognize data. It is written in python3 and pyqt5, supporting rectangular box annotation and four-point annotation modes. Annotations can be directly used for the training of PPOCR detection and recognition models', description='PPOCRLabel is a semi-automatic graphic annotation tool suitable for OCR field, with built-in PPOCR model to automatically detect and re-recognize data. It is written in python3 and pyqt5, supporting rectangular box annotation and four-point annotation modes. Annotations can be directly used for the training of PPOCR detection and recognition models',
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册