improve the OCR pipeline processing and outputs formatting

This commit is contained in:
2026-07-19 19:54:53 +02:00
parent d375db47c3
commit 1cf1c6eeab
30 changed files with 3838 additions and 3900 deletions

View File

@@ -33,7 +33,10 @@ class FigureDetector:
try:
import layoutparser as lp
self._predictor = lp.Detectron2LayoutModel(
model_class = getattr(lp, "Detectron2LayoutModel", None) or getattr(lp, "AutoLayoutModel", None)
if model_class is None:
raise RuntimeError("layoutparser has no compatible layout model backend; install Detectron2")
self._predictor = model_class(
config_path=settings.detectors.figures.model,
label_map={0: "Text", 1: "Title", 2: "List", 3: "Table", 4: "Figure"},
extra_config=[
@@ -67,7 +70,10 @@ class FigureDetector:
block.block.x_2,
block.block.y_2,
)
crop = image[int(y1) : int(y2), int(x1) : int(x2)]
height, width = image.shape[:2]
x1_i, x2_i = max(0, int(x1)), min(width, int(x2))
y1_i, y2_i = max(0, int(y1)), min(height, int(y2))
crop = image[y1_i:y2_i, x1_i:x2_i]
figures.append(
DetectedFigure(
bbox=[float(x1), float(y1), float(x2), float(y2)],
@@ -98,7 +104,10 @@ class CaptionExtractor:
try:
import layoutparser as lp
self._predictor = lp.Detectron2LayoutModel(
model_class = getattr(lp, "Detectron2LayoutModel", None) or getattr(lp, "AutoLayoutModel", None)
if model_class is None:
raise RuntimeError("layoutparser has no compatible layout model backend; install Detectron2")
self._predictor = model_class(
config_path=settings.detectors.captions.model,
label_map={0: "Text", 1: "Title", 2: "List", 3: "Table", 4: "Figure"},
extra_config=[
@@ -156,11 +165,14 @@ class CaptionExtractor:
return figures
def detect_figures(image: np.ndarray) -> list[DetectedFigure]:
detector = FigureDetector()
figures = detector.detect(image)
_figure_detector = FigureDetector()
_caption_extractor = CaptionExtractor()
captioner = CaptionExtractor()
def detect_figures(image: np.ndarray) -> list[DetectedFigure]:
figures = _figure_detector.detect(image)
captioner = _caption_extractor
figures = captioner.extract_captions(image, figures)
return figures

View File

@@ -59,6 +59,7 @@ class TableDetector:
try:
import torch
original_height, original_width = image.shape[:2]
pil_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
pil_image = cv2.resize(pil_image, (800, 800))
@@ -77,8 +78,12 @@ class TableDetector:
for score, _label, box in zip(
results["scores"], results["labels"], results["boxes"], strict=True
):
box = [float(x) for x in box]
resized_box = [float(x) for x in box]
scale_x, scale_y = original_width / 800, original_height / 800
box = [resized_box[0] * scale_x, resized_box[1] * scale_y, resized_box[2] * scale_x, resized_box[3] * scale_y]
x1, y1, x2, y2 = map(int, box)
x1, x2 = max(0, x1), min(original_width, x2)
y1, y2 = max(0, y1), min(original_height, y2)
crop = image[y1:y2, x1:x2]
tables.append(
DetectedTable(
@@ -122,6 +127,7 @@ class TableStructureRecognizer:
self._initialized = True
def recognize(self, table_crop: np.ndarray) -> tuple[list[dict[str, Any]] | None, str | None]:
self._init()
if self._model is None or self._processor is None:
return None, None
@@ -150,8 +156,9 @@ class TableStructureRecognizer:
}
)
markdown = self._structure_to_markdown(structure, table_crop.shape)
return structure, markdown
# Structure models locate rows/cells but do not provide cell text. Do not
# emit labels as fabricated table content; OCR must be associated separately.
return structure, None
except Exception as e:
logger.warning("table_structure_recognition_failed", error=str(e))
return None, None
@@ -185,17 +192,19 @@ class TableStructureRecognizer:
return None
_table_detector = TableDetector()
_table_structure_recognizer = TableStructureRecognizer()
def detect_tables(image: np.ndarray) -> list[DetectedTable]:
detector = TableDetector()
tables = detector.detect(image)
tables = _table_detector.detect(image)
if not tables:
return tables
recognizer = TableStructureRecognizer()
for table in tables:
if table.image_crop is not None:
structure, markdown = recognizer.recognize(table.image_crop)
structure, markdown = _table_structure_recognizer.recognize(table.image_crop)
table.structure = structure
table.markdown = markdown