|
|
@@ -116,6 +116,175 @@ class _TableRecognitionPipelineV2(BasePipeline):
|
|
|
# ...existing code...
|
|
|
````
|
|
|
|
|
|
+## BeautifulSoup 生成HTML表格
|
|
|
+正在收集工作区信息正在筛选到最相关的信息基于你的想法,使用 BeautifulSoup 生成表格树然后填充内容确实是一个很好的改进方案。让我比较一下两种方式:
|
|
|
+
|
|
|
+## 现有 get_html_result 的问题
|
|
|
+
|
|
|
+1. **字符串拼接**:逐个拼接 HTML 标签,容易出错
|
|
|
+2. **索引对齐复杂**:需要手动维护 `td_global`、`row_idx`、`col_idx` 等指针
|
|
|
+3. **结构不一致时易崩溃**:当检测列数与结构列数不匹配时需要复杂的回退逻辑
|
|
|
+4. **难以处理合并单元格**:如果后续需要支持 `colspan`/`rowspan` 会很困难
|
|
|
+
|
|
|
+## BeautifulSoup 方案的优势
|
|
|
+
|
|
|
+1. **结构清晰**:直接基于检测到的单元格坐标生成规整的表格结构
|
|
|
+2. **索引简单**:通过行列坐标直接定位单元格,无需复杂的指针推进
|
|
|
+3. **易于扩展**:天然支持合并单元格、样式添加等高级功能
|
|
|
+4. **更稳定**:不依赖于结构识别模型的输出质量
|
|
|
+
|
|
|
+## 推荐的 BeautifulSoup 实现
|
|
|
+
|
|
|
+````python
|
|
|
+def generate_table_from_cells(table_cells_result, ocr_texts_res, table_cells_flag):
|
|
|
+ """
|
|
|
+ 基于检测到的单元格坐标生成 BeautifulSoup 表格树并填充内容
|
|
|
+ """
|
|
|
+ from bs4 import BeautifulSoup
|
|
|
+
|
|
|
+ # 计算表格行列数
|
|
|
+ num_rows = len(table_cells_flag) - 1
|
|
|
+ max_cols = max(table_cells_flag[i+1] - table_cells_flag[i] for i in range(num_rows)) if num_rows > 0 else 0
|
|
|
+
|
|
|
+ # 创建基础表格结构
|
|
|
+ html_template = f"""
|
|
|
+ <html>
|
|
|
+ <body>
|
|
|
+ <table>
|
|
|
+ {''.join(f'<tr>{"<td></td>" * max_cols}</tr>' for _ in range(num_rows))}
|
|
|
+ </table>
|
|
|
+ </body>
|
|
|
+ </html>
|
|
|
+ """
|
|
|
+
|
|
|
+ soup = BeautifulSoup(html_template, 'html.parser')
|
|
|
+ table = soup.find('table')
|
|
|
+ rows = table.find_all('tr')
|
|
|
+
|
|
|
+ # 填充单元格内容
|
|
|
+ for row_idx in range(num_rows):
|
|
|
+ row = rows[row_idx]
|
|
|
+ cells = row.find_all('td')
|
|
|
+
|
|
|
+ # 获取当前行的单元格范围
|
|
|
+ start_cell = table_cells_flag[row_idx]
|
|
|
+ end_cell = table_cells_flag[row_idx + 1]
|
|
|
+
|
|
|
+ for col_idx in range(end_cell - start_cell):
|
|
|
+ if col_idx < len(cells):
|
|
|
+ cell_global_idx = start_cell + col_idx
|
|
|
+
|
|
|
+ # 查找匹配的 OCR 内容
|
|
|
+ cell_content = ""
|
|
|
+ if cell_global_idx < len(ocr_texts_res):
|
|
|
+ cell_content = ocr_texts_res[cell_global_idx] or ""
|
|
|
+
|
|
|
+ cells[col_idx].string = cell_content
|
|
|
+
|
|
|
+ return str(soup)
|
|
|
+````
|
|
|
+
|
|
|
+## 更优化的实现方案
|
|
|
+
|
|
|
+````python
|
|
|
+# ...existing code...
|
|
|
+
|
|
|
+def generate_table_with_beautifulsoup(
|
|
|
+ table_cells_result: list,
|
|
|
+ ocr_texts_res: list,
|
|
|
+ matched_index: dict,
|
|
|
+ table_cells_flag: list
|
|
|
+) -> str:
|
|
|
+ """
|
|
|
+ 使用 BeautifulSoup 生成表格并填充 OCR 内容
|
|
|
+
|
|
|
+ Args:
|
|
|
+ table_cells_result: 单元格坐标列表
|
|
|
+ ocr_texts_res: OCR 识别文本列表
|
|
|
+ matched_index: 单元格与 OCR 的匹配关系
|
|
|
+ table_cells_flag: 行边界标记
|
|
|
+
|
|
|
+ Returns:
|
|
|
+ str: 生成的 HTML 表格字符串
|
|
|
+ """
|
|
|
+ try:
|
|
|
+ from bs4 import BeautifulSoup, Tag
|
|
|
+ except ImportError:
|
|
|
+ # 如果没有 BeautifulSoup,回退到原方法
|
|
|
+ return get_html_result_fallback(matched_index, ocr_texts_res, table_cells_flag)
|
|
|
+
|
|
|
+ # 计算表格维度
|
|
|
+ num_rows = len(table_cells_flag) - 1
|
|
|
+ if num_rows <= 0:
|
|
|
+ return "<html><body><table></table></body></html>"
|
|
|
+
|
|
|
+ # 创建表格结构
|
|
|
+ soup = BeautifulSoup("<html><body><table></table></body></html>", 'html.parser')
|
|
|
+ table = soup.find('table')
|
|
|
+
|
|
|
+ # 为每行添加单元格
|
|
|
+ for row_idx in range(num_rows):
|
|
|
+ tr = soup.new_tag('tr')
|
|
|
+ table.append(tr)
|
|
|
+
|
|
|
+ # 当前行的单元格数量
|
|
|
+ num_cols = table_cells_flag[row_idx + 1] - table_cells_flag[row_idx]
|
|
|
+
|
|
|
+ for col_idx in range(num_cols):
|
|
|
+ td = soup.new_tag('td')
|
|
|
+ tr.append(td)
|
|
|
+
|
|
|
+ # 填充单元格内容
|
|
|
+ if row_idx < len(matched_index) and col_idx in matched_index[row_idx]:
|
|
|
+ content_parts = []
|
|
|
+ for ocr_idx in matched_index[row_idx][col_idx]:
|
|
|
+ if ocr_idx < len(ocr_texts_res):
|
|
|
+ content = ocr_texts_res[ocr_idx].strip()
|
|
|
+ if content:
|
|
|
+ content_parts.append(content)
|
|
|
+
|
|
|
+ # 合并多个 OCR 结果
|
|
|
+ if content_parts:
|
|
|
+ td.string = " ".join(content_parts)
|
|
|
+
|
|
|
+ return str(soup)
|
|
|
+
|
|
|
+def get_table_recognition_res(
|
|
|
+ table_box: list,
|
|
|
+ table_structure_result: list,
|
|
|
+ table_cells_result: list,
|
|
|
+ overall_ocr_res: OCRResult,
|
|
|
+ table_ocr_pred: dict,
|
|
|
+ cells_texts_list: list,
|
|
|
+ use_table_cells_ocr_results: bool,
|
|
|
+ use_table_cells_split_ocr: bool,
|
|
|
+) -> SingleTableRecognitionResult:
|
|
|
+ # ...existing code above...
|
|
|
+
|
|
|
+ # 使用 BeautifulSoup 生成表格(推荐)
|
|
|
+ pred_html = generate_table_with_beautifulsoup(
|
|
|
+ table_cells_result, ocr_texts_res, matched_index, table_cells_flag
|
|
|
+ )
|
|
|
+
|
|
|
+ # ...existing code below...
|
|
|
+````
|
|
|
+
|
|
|
+## 结论
|
|
|
+
|
|
|
+**推荐使用 BeautifulSoup 方案**,原因:
|
|
|
+
|
|
|
+1. **更稳定**:不受结构识别模型输出质量影响
|
|
|
+2. **更简洁**:代码逻辑更清晰,易于维护
|
|
|
+3. **更灵活**:容易扩展支持合并单元格、样式等功能
|
|
|
+4. **更可靠**:避免了复杂的指针对齐问题
|
|
|
+
|
|
|
+但需要:
|
|
|
+- 添加 BeautifulSoup 依赖检查
|
|
|
+- 保留原方法作为回退方案
|
|
|
+- 充分测试确保兼容性
|
|
|
+
|
|
|
+这种方案特别适合**有线表格**场景,因为单元格检测通常很准确,可以直接基于检测结果构建表格结构。
|
|
|
+
|
|
|
## 单元格内文字丢失
|
|
|
上期发生额”ocr后的文字bbox是在表格检测单元框内,为什么没有显示出来
|
|
|
**还需查找原因**
|