parse_pdf()
This repository implements computer vision based approaches for detecting and parsing visual features such as tables or
previous redactions in documents.

{
  "targetFilePath": {
    "pdf": "absolute file path",
    "vlp_output": "absolute file path"
  },
  "responseFilePath": "absolute file path",
  "operation": "table_image_inference"
}

Response is uploaded to the storage as specified in the responseFilePath field. The structure is as follows:

{
  ...,
  "data": [
    {
      'pageNum': 0,
      'bbox': {
        'x1': 55.3407,
        'y1': 247.0246,
        'x2': 558.5602,
        'y2': 598.0585
      },
      'uuid': '2b10c1a2-393c-4fca-b9e3-0ad5b774ac84',
      'label': 'table',
      'tableLines': [
        {
          'x1': 0,
          'y1': 16,
          'x2': 1399,
          'y2': 16
        },
        ...
      ],
      'imageInfo': {
        'height': 693,
        'width': 1414
      }
    },
    ...
  ]
}

git clone ssh://git@git.iqser.com:2222/rr/cv-analysis.git
cd cv-analysis

python -m venv env
source env/bin/activate

pip install -e .
pip install -r requirements.txt

dvc pull

The module provided functions for the individual tasks that all return some kind of collection of points, depending on
the specific task.

The below snippet shows hot to find the outlines of previous redactions.

from cv_analysis.redaction_detection import find_redactions
import pdf2image
import numpy as np

pdf_path = ...
page_index = ...

page = pdf2image.convert_from_path(pdf_path, first_page=page_index, last_page=page_index)[0]
page = np.array(page)

redaction_contours = find_redactions(page)

The tables parsing utility detects and segments tables into individual cells.

The below image shows a parsed table, where each table cell has been detected individually.

The redaction detection utility detects previous redactions in PDFs (filled black rectangles).

The below image shows the detected redactions with green outlines.

The layout parsing utility detects elements such as paragraphs, tables and figures.

The figure detection utility detects figures specifically, which can be missed by the generic layout parsing utility.

docker build -f Dockerfile -t cv-analysis . --build-arg BASE_ROOT=""

Keyword Extraction Service documentation master file, created by
sphinx-quickstart on Mon Sep 12 12:04:24 2022.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.

If you'd like to change the looks of things 👉 https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html

detect_figures() (in module cv_analysis.figure_detection.figure_detection)

is_likely_figure() (in module cv_analysis.figure_detection.figure_detection)

is_likely_figure(min_area, max_area, max_width_to_height_ratio, cnts)

detect_large_coherent_structures() (in module cv_analysis.figure_detection.figures)

Detects large coherent structures on an image.
Expects an image with binary color space (e.g. threshold applied).

apply_threshold_to_image() (in module cv_analysis.figure_detection.text)

is_likely_primary_text_segment() (in module cv_analysis.figure_detection.text)

remove_primary_text_regions() (in module cv_analysis.figure_detection.text)

Removes regions of primary text, meaning no figure descriptions for example, but main text body paragraphs.

filter_array(array: ~numpy.ndarray, sum_filter: ~numpy.ndarray | None, padding: ~numpy.ndarray | None = None, pad_value_function: ~typing.Callable[[~numpy.ndarray], float] = <function <lambda>>) -> ~numpy.ndarray

(array: ~numpy.ndarray, sum_filter: ~numpy.ndarray | None, padding: ~numpy.ndarray | None = None, pad_value_function: ~typing.Callable[[~numpy.ndarray], float] = <function <lambda>>)

array: ~numpy.ndarray, sum_filter: ~numpy.ndarray | None, padding: ~numpy.ndarray | None = None, pad_value_function: ~typing.Callable[[~numpy.ndarray], float] = <function <lambda>>

filter_fp_col_lines(line_list: list[int], filt_sums: ~numpy.ndarray) -> list[int]

get_lines_either(table_array: ~numpy.ndarray, horizontal=True) -> list[int]

infer_lines(img: ~numpy.ndarray) -> dict[str, dict[str, int] | list[dict[str, int]]]

make_gaussian_kernel(kernel_size: int, sd: float) -> ~numpy.ndarray

make_gaussian_nonpositive_kernel() (in module cv_analysis.table_inference)

make_gaussian_nonpositive_kernel(kernel_size: int, sd: float) -> ~numpy.ndarray

make_quadratic_kernel(kernel_size: int, ratio: float) -> ~numpy.ndarray

min_avg_for_interval(filtered: ~numpy.ndarray, interval: int) -> tuple[float, int]

save_lines(img: ~numpy.ndarray, lines: list[dict[str, int]]) -> None

save_plot(arr: ~numpy.ndarray, name: str, title: str = '') -> None

search_intervals(filtered: ~numpy.ndarray, min_interval: int, max_interval: int)

show_multiple(arrs: ~typing.Tuple[~numpy.ndarray], title: str = '')

annotate_pdf(pdf: str | bytes | ~pathlib.Path, annotations, output_path: str | ~pathlib.Path | None = None)

pdf: str | bytes | ~pathlib.Path, annotations, output_path: str | ~pathlib.Path | None = None

connect_related_rects() (in module cv_analysis.utils.connect_rects)

connect_related_rects2() (in module cv_analysis.utils.connect_rects)

find_related_rects() (in module cv_analysis.utils.connect_rects)

has_correct_position1() (in module cv_analysis.utils.connect_rects)

rects_not_the_same() (in module cv_analysis.utils.connect_rects)

PageInfo(page_num: int, rotation_matrix: ~fitz.Matrix, transformation_matrix: ~fitz.Matrix, dpi: int, width: int | float, height: int | float, image_width: int | float, image_height: int | float, rotation: int) -> None

page_num: int, rotation_matrix: ~fitz.Matrix, transformation_matrix: ~fitz.Matrix, dpi: int, width: int | float, height: int | float, image_width: int | float, image_height: int | float, rotation: int

image_height (cv_analysis.utils.image_extraction.PageInfo attribute)

image_width (cv_analysis.utils.image_extraction.PageInfo attribute)

page_num (cv_analysis.utils.image_extraction.PageInfo attribute)

rotation (cv_analysis.utils.image_extraction.PageInfo attribute)

rotation_matrix (cv_analysis.utils.image_extraction.PageInfo attribute)

transformation_matrix (cv_analysis.utils.image_extraction.PageInfo attribute)

extract_images_from_pdf() (in module cv_analysis.utils.image_extraction)

extract_images_from_pdf(pdf_bytes: bytes, vlp_output: dict, dpi: int = 200) -> tuple[list[~numpy.ndarray], list[dict], list[~cv_analysis.utils.image_extraction.PageInfo]]

rescale_to_pdf(bbox: tuple[int | float, int | float, int | float, int | float], page_info: ~cv_analysis.utils.image_extraction.PageInfo) -> tuple[float, float, float, float]

bbox: tuple[int | float, int | float, int | float, int | float], page_info: ~cv_analysis.utils.image_extraction.PageInfo

transform_image_coordinates_to_pdf_coordinates() (in module cv_analysis.utils.image_extraction)

transform_image_coordinates_to_pdf_coordinates(bbox: tuple[int | float, int | float, int | float, int | float], rotation_matrix: ~fitz.Matrix, transformation_matrix: ~fitz.Matrix, dpi: int | None = None) -> ~typing.Tuple

bbox: tuple[int | float, int | float, int | float, int | float], rotation_matrix: ~fitz.Matrix, transformation_matrix: ~fitz.Matrix, dpi: int | None = None

transform_table_lines_by_page_info() (in module cv_analysis.utils.image_extraction)

transform_table_lines_by_page_info(bboxes: dict, offsets: tuple, page_info: ~cv_analysis.utils.image_extraction.PageInfo) -> dict

bboxes: dict, offsets: tuple, page_info: ~cv_analysis.utils.image_extraction.PageInfo

remove_overlapping() (in module cv_analysis.utils.postprocessing)

preprocess_page_array() (in module cv_analysis.utils.preprocessing)

Rectangle(x1=None, y1=None, w=None, h=None, x2=None, y2=None, indent=4, format='xywh', discrete=True)

x1=None, y1=None, w=None, h=None, x2=None, y2=None, indent=4, format='xywh', discrete=True

Rectangle.adjacent(rect2: ~cv_analysis.utils.structures.Rectangle, tolerance=7)

from_dict_xywh() (cv_analysis.utils.structures.Rectangle class method)

from_xywh() (cv_analysis.utils.structures.Rectangle class method)

from_xyxy() (cv_analysis.utils.structures.Rectangle class method)

Rectangle.includes(other: ~cv_analysis.utils.structures.Rectangle, tol=3)

compute_document_score() (in module cv_analysis.utils.test_metrics)

box: ~cv_analysis.utils.structures.Rectangle, box_list: ~typing.Iterable[~cv_analysis.utils.structures.Rectangle]

copy_and_normalize_channels() (in module cv_analysis.utils.utils)