@@ -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
36693760def inverted (color ):
36703761 return QColor (* [255 - v for v in color .getRgb ()])
0 commit comments