|
| 1 | +Whitespace-Projection Columns (Borderless Tables) |
| 2 | +================================================= |
| 3 | + |
| 4 | +``ocr/structure`` detects tables only when *every* row's cell-left-x matches within a |
| 5 | +tolerance — it collapses on ragged or borderless tables, right-aligned numeric columns, or |
| 6 | +any row with a missing cell. ``edge_lines.find_grid`` needs ruling lines, so a table drawn |
| 7 | +purely with whitespace has no grid at all. ``column_layout`` finds columns the robust way the |
| 8 | +layout-analysis literature uses: by the *gaps*. It projects the OCR boxes onto the x-axis (an |
| 9 | +ink-density profile), reads off the persistent empty vertical bands as column gutters, assigns |
| 10 | +each box a column index, and buckets rows by vertical spacing to emit a borderless table. |
| 11 | + |
| 12 | +Pure-stdlib over plain box dicts (a difference-array projection — no numpy), so it is fully |
| 13 | +unit-testable with no image and no OCR engine. Reuses ``table_grid_fill``'s box-bounds reader. |
| 14 | +Imports no ``PySide6``. |
| 15 | + |
| 16 | +Headless API |
| 17 | +------------ |
| 18 | + |
| 19 | +.. code-block:: python |
| 20 | +
|
| 21 | + from je_auto_control import (detect_borderless_table, column_gutters, |
| 22 | + assign_columns, vertical_projection) |
| 23 | +
|
| 24 | + table = detect_borderless_table(ocr_boxes) |
| 25 | + # {"n_rows": 3, "n_cols": 2, "rows": [["Name","Age"],["Ann","30"],["Bob","25"]], |
| 26 | + # "columns": [{"start": 70, "end": 120, "width": 50}]} |
| 27 | +
|
| 28 | + gutters = column_gutters(ocr_boxes, min_gap=8) # empty vertical bands |
| 29 | + tagged = assign_columns(ocr_boxes) # each box + "column" index |
| 30 | + profile = vertical_projection(ocr_boxes) # ink density per x |
| 31 | +
|
| 32 | +``vertical_projection`` returns the per-x ink-density profile; ``column_gutters`` returns the |
| 33 | +interior empty bands ``[{start, end, width}]`` at least ``min_gap`` wide; ``assign_columns`` |
| 34 | +tags every box with a 0-based ``column``; ``detect_borderless_table`` combines columns (from |
| 35 | +gutters) with rows (from vertical spacing) into ``{n_rows, n_cols, rows, columns}``, or |
| 36 | +``None`` when fewer than ``min_cols`` columns / ``min_rows`` rows are found. Boxes accept |
| 37 | +``{x, y, width, height}`` or ``{left, top, right, bottom}`` plus an optional ``text``. |
| 38 | + |
| 39 | +Executor commands |
| 40 | +----------------- |
| 41 | + |
| 42 | +``AC_detect_borderless_table`` (``boxes`` / ``page_width`` / ``min_gap`` / ``min_cols`` / |
| 43 | +``min_rows`` → ``{found, table}``) and ``AC_column_gutters`` (``boxes`` / ``page_width`` / |
| 44 | +``min_gap`` → ``{count, gutters}``). They are exposed as the MCP tools |
| 45 | +``ac_detect_borderless_table`` / ``ac_column_gutters`` (read-only) and as the Script Builder |
| 46 | +commands **Detect Borderless Table** / **Column Gutters (whitespace)** under **OCR**. |
0 commit comments