Explorar o código

feat: Add rotation adjustment feature to the adjustment section, enabling fine-tuning of image skew and automatic analysis trigger after adjustments

zhch158_admin hai 22 horas
pai
achega
4f888dc393

+ 49 - 2
table_line_generator/editor/adjustments.py

@@ -22,7 +22,7 @@ def create_adjustment_section(structure):
     # 行操作, 列操作
     adjustment_action = st.radio(
         "行&列操作",
-        ["调整横线", "添加横线", "删除横线", "调整竖线", "添加竖线", "删除竖线"],
+        ["调整横线", "添加横线", "删除横线", "调整竖线", "添加竖线", "删除竖线", "微调旋转"],
         horizontal=True,
         index=None,
         label_visibility="collapsed",
@@ -132,7 +132,6 @@ def create_adjustment_section(structure):
             if idx not in structure['modified_v_lines']:
                 structure['modified_v_lines'].append(idx)
             _update_column_intervals(structure)
-            _update_column_intervals(structure)
             clear_table_image_cache()
             adjusted = True
             st.success(f"✅ 新增竖线 X={new_v_x}")
@@ -153,6 +152,54 @@ def create_adjustment_section(structure):
             adjusted = True
             st.success(f"✅ 已删除 {len(to_delete)} 条竖线")
 
+    elif adjustment_action == "微调旋转":
+        st.info("📐 微调图片的旋转角度 (基于当前角度), 正值逆时针旋转,负值顺时针旋转")
+        
+        if 'generator' in st.session_state:
+            generator = st.session_state.generator
+            current_skew = generator.ocr_data.get('skew_angle', 0.0)
+            original_skew = generator.ocr_data.get('original_skew_angle', 0.0)
+            
+            st.markdown(f"""
+            **当前总倾斜校正:** `{current_skew:.2f}°`  --   *(原始文件读取: `{original_skew:.2f}°`)*
+            """)
+            
+            col1, col2 = st.columns([1, 1], width=300, gap="small")
+            with col1:
+                delta_angle = st.number_input(
+                    "旋转偏移量 (度)",
+                    min_value=-10.0,
+                    max_value=10.0,
+                    value=0.0,
+                    step=0.01,
+                    format="%.2f",
+                    help="正值逆时针旋转,负值顺时针旋转",
+                    label_visibility="collapsed",
+                    key="rotate_delta_input"
+                )
+            with col2:
+                if st.button("🔄 应用", key="apply_rotate_btn"):
+                    if delta_angle != 0:
+                        # 更新 skew_angle
+                        generator.ocr_data['skew_angle'] = current_skew + delta_angle
+                        
+                        with st.spinner("正在重新校正图片..."):
+                            # 强制重新校正
+                            corrected_image, _ = generator.correct_skew(force=True)
+                            st.session_state.image = corrected_image
+                            
+                            # 清除缓存
+                            clear_table_image_cache()
+                            adjusted = True
+                            
+                            # 标记需要重新分析结构
+                            st.session_state.need_reanalysis = True
+                            
+                            st.success(f"✅ 已应用旋转 {delta_angle}°")
+                            st.rerun()
+        else:
+            st.warning("⚠️ 无法获取 TableLineGenerator 实例")
+
     return adjusted
 
 

+ 13 - 22
table_line_generator/editor/analysis_controls.py

@@ -19,35 +19,26 @@ def create_analysis_section(generator, tool: str = "ppstructv3") -> Optional[Dic
     """
     st.sidebar.subheader("🔍 表格结构分析")
     
+    # 检查是否需要自动触发分析(例如旋转微调后)
+    auto_analyze = st.session_state.get('need_reanalysis', False)
+    if auto_analyze:
+        st.session_state.need_reanalysis = False
+    
     # 🔑 根据工具类型显示不同的参数
     if tool.lower() == "mineru":
         st.sidebar.info("📋 MinerU 格式:直接使用 table_cells 生成结构")
         
-        if st.sidebar.button("🚀 生成表格结构", type="primary"):
+        if st.sidebar.button("🚀 生成表格结构", type="primary") or auto_analyze:
             with st.spinner("正在分析表格结构..."):
                 try:
-                    # 🔑 MinerU 格式:从原始 JSON 重新解析
-                    current_catalog = st.session_state.get('current_catalog', [])
-                    current_index = st.session_state.get('current_catalog_index', 0)
-                    
-                    if not current_catalog or current_index >= len(current_catalog):
-                        st.error("❌ 未找到当前文件")
-                        return None
-                    
-                    entry = current_catalog[current_index]
-                    
-                    # 加载原始 JSON
-                    with open(entry["json"], "r", encoding="utf-8") as fp:
-                        raw = json.load(fp)
-                    
-                    # 重新解析获取完整结构
-                    from .data_processor import get_structure_from_ocr
-                    
-                    table_bbox, structure = get_structure_from_ocr(raw, tool)
+                    # 🔑 使用 generator 分析 (支持旋转后的坐标)
+                    structure = generator.analyze_table_structure(method="mineru")
                     
                     # 保存到 session_state
                     st.session_state.structure = structure
-                    st.session_state.table_bbox = table_bbox
+                    if 'table_bbox' in structure:
+                        st.session_state.table_bbox = structure['table_bbox']
+                    
                     st.session_state.undo_stack = []
                     st.session_state.redo_stack = []
                     
@@ -57,7 +48,7 @@ def create_analysis_section(generator, tool: str = "ppstructv3") -> Optional[Dic
                     
                     st.success(
                         f"✅ 表格结构生成成功!\n\n"
-                        f"检测到 {structure['total_rows']} 行,{structure['total_cols']} 列"
+                        f"检测到 {len(structure.get('rows', []))} 行,{len(structure.get('columns', []))} 列"
                     )
                     return structure
                     
@@ -93,7 +84,7 @@ def create_analysis_section(generator, tool: str = "ppstructv3") -> Optional[Dic
             help="行高小于此值的将被过滤"
         )
         
-        if st.sidebar.button("🚀 分析表格结构", type="primary"):
+        if st.sidebar.button("🚀 分析表格结构", type="primary") or auto_analyze:
             with st.spinner("正在分析表格结构..."):
                 try:
                     structure = generator.analyze_table_structure(

+ 13 - 0
table_line_generator/editor/mode_setup.py

@@ -36,6 +36,19 @@ def setup_new_annotation_mode(
     # 初始化生成器
     if 'generator' not in st.session_state:
         st.session_state.generator = TableLineGenerator(image, ocr_data)
+        
+        # 🆕 自动校正倾斜和旋转
+        corrected_image, angle = st.session_state.generator.correct_skew()
+        
+        # 获取角度信息
+        ocr_data_dict = st.session_state.generator.ocr_data
+        image_rotation_angle = ocr_data_dict.get('image_rotation_angle', 0.0) if isinstance(ocr_data_dict, dict) else 0.0
+        skew_angle = ocr_data_dict.get('skew_angle', 0.0) if isinstance(ocr_data_dict, dict) else 0.0
+        
+        if abs(skew_angle) > 0.1 or image_rotation_angle != 0:
+            st.info(f"🔄 自动校正: 旋转={image_rotation_angle}°, 倾斜={skew_angle:.2f}°")
+            # 更新 session_state 中的图片
+            st.session_state.image = corrected_image
     
     # 分析控件
     structure = create_analysis_section(