Skip to content

Commit ca7cfe9

Browse files
Sam-gsjguoshengjian
andauthored
[Function] Add automatic Table Structure Reordering Function. (#176)
* fix bug in PPOCRLabel.py * code style check * code style check * code style check * code style check * Add resort function * fix code style * fix code style * modify resort function * add keys info * modify resortBoxPosion to resortBoxPosition --------- Co-authored-by: guoshengjian <guoshengjian@MacBook-Pro.local>
1 parent 982f8bb commit ca7cfe9

File tree

6 files changed

+11850
-11743
lines changed

6 files changed

+11850
-11743
lines changed

PPOCRLabel.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,8 @@ def get_str(str_id):
349349
self.SaveButton.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
350350
self.DelButton = QToolButton()
351351
self.DelButton.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
352+
self.ResortButton = QToolButton()
353+
self.ResortButton.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
352354

353355
leftTopToolBox = QGridLayout()
354356
leftTopToolBox.addWidget(self.newButton, 0, 0, 1, 1)
@@ -438,6 +440,7 @@ def get_str(str_id):
438440
leftbtmtoolbox = QHBoxLayout()
439441
leftbtmtoolbox.addWidget(self.SaveButton)
440442
leftbtmtoolbox.addWidget(self.DelButton)
443+
leftbtmtoolbox.addWidget(self.ResortButton)
441444
leftbtmtoolboxcontainer = QWidget()
442445
leftbtmtoolboxcontainer.setLayout(leftbtmtoolbox)
443446
listLayout.addWidget(leftbtmtoolboxcontainer)
@@ -897,6 +900,14 @@ def get_str(str_id):
897900
get_str("expandBoxDetail"),
898901
enabled=False,
899902
)
903+
resort = action(
904+
get_str("resortposition"),
905+
self.resortBoxPosition,
906+
"Ctrl+B",
907+
"resort",
908+
get_str("resortpositiondetail"),
909+
enabled=True,
910+
)
900911

901912
self.editButton.setDefaultAction(edit)
902913
self.newButton.setDefaultAction(create)
@@ -906,6 +917,7 @@ def get_str(str_id):
906917
self.AutoRecognition.setDefaultAction(AutoRec)
907918
self.reRecogButton.setDefaultAction(reRec)
908919
self.tableRecButton.setDefaultAction(tableRec)
920+
self.ResortButton.setDefaultAction(resort)
909921
# self.preButton.setDefaultAction(openPrevImg)
910922
# self.nextButton.setDefaultAction(openNextImg)
911923

@@ -995,6 +1007,7 @@ def get_str(str_id):
9951007
lock=lock,
9961008
exportJSON=exportJSON,
9971009
expand=expand,
1010+
resort=resort,
9981011
fileMenuActions=(
9991012
opendir,
10001013
open_dataset_dir,
@@ -1012,6 +1025,7 @@ def get_str(str_id):
10121025
delete,
10131026
singleRere,
10141027
cellreRec,
1028+
resort,
10151029
None,
10161030
undo,
10171031
undoLastPoint,
@@ -3665,6 +3679,83 @@ def expandSelectedShape(self):
36653679
self.updateBoxlist()
36663680
self.setDirty()
36673681

3682+
def sort_rectangles(self, rectangles, row_height_threshold=0.5):
3683+
if not rectangles:
3684+
return []
3685+
3686+
def get_top_left(rect):
3687+
xs = [p[0] for p in rect]
3688+
ys = [p[1] for p in rect]
3689+
return (min(xs), min(ys))
3690+
3691+
avg_height = sum(
3692+
[max(p[1] for p in rect) - min(p[1] for p in rect) for rect in rectangles]
3693+
) / len(rectangles)
3694+
threshold = avg_height * row_height_threshold
3695+
indexed_rects = [(i, get_top_left(rect)) for i, rect in enumerate(rectangles)]
3696+
indexed_rects.sort(key=lambda x: x[1][1])
3697+
rows = []
3698+
current_row = []
3699+
last_y = indexed_rects[0][1][1]
3700+
for item in indexed_rects:
3701+
i, (x, y) = item
3702+
if abs(y - last_y) <= threshold:
3703+
current_row.append(item)
3704+
else:
3705+
rows.append(current_row)
3706+
current_row = [item]
3707+
last_y = y
3708+
if current_row:
3709+
rows.append(current_row)
3710+
sorted_rects = []
3711+
for row in rows:
3712+
row.sort(key=lambda x: x[1][0])
3713+
sorted_rects.extend([rectangles[i] for i, _ in row])
3714+
return sorted_rects
3715+
3716+
def resortBoxPosition(self):
3717+
# get original elements
3718+
items = []
3719+
for i in range(self.BoxList.count()):
3720+
item = self.BoxList.item(i)
3721+
items.append({"text": item.text(), "object": item})
3722+
# get coordinate points
3723+
rectangles = []
3724+
for item in items:
3725+
text = item["text"]
3726+
try:
3727+
rect = ast.literal_eval(text) # 转为列表
3728+
rectangles.append(rect)
3729+
except (ValueError, SyntaxError) as e:
3730+
logger.error(f"Error parsing text: {text}")
3731+
continue
3732+
# start resort
3733+
sorted_rectangles = self.sort_rectangles(rectangles, row_height_threshold=0.5)
3734+
# old_idx <--> new_idx
3735+
index_map = []
3736+
for sorted_rect in sorted_rectangles:
3737+
for old_idx, rect in enumerate(rectangles):
3738+
if rect == sorted_rect:
3739+
index_map.append(old_idx)
3740+
break
3741+
# resort BoxList labelList canvas.shapes
3742+
items = [self.BoxList.takeItem(0) for _ in range(self.BoxList.count())]
3743+
items_label = [
3744+
self.labelList.takeItem(0) for _ in range(self.labelList.count())
3745+
]
3746+
shapes = self.canvas.shapes
3747+
self.canvas.shapes = []
3748+
for new_idx in range(len(index_map)):
3749+
old_idx = index_map[new_idx]
3750+
self.BoxList.insertItem(new_idx, items[old_idx])
3751+
self.labelList.insertItem(new_idx, items_label[old_idx])
3752+
self.canvas.shapes.insert(new_idx, shapes[old_idx])
3753+
QMessageBox.information(
3754+
self,
3755+
"Information",
3756+
"resort success!",
3757+
)
3758+
36683759

36693760
def inverted(color):
36703761
return QColor(*[255 - v for v in color.getRgb()])

0 commit comments

Comments
 (0)