ready for integration with pyinfra

This commit is contained in:
Isaac Riley 2022-06-13 12:59:00 +02:00
parent 01803d452a
commit c62ab08b98
38 changed files with 4160 additions and 359 deletions

View File

@ -23,5 +23,5 @@ deskew:
test_dummy: test_dummy test_dummy: test_dummy
visual_logging: visual_logging:
level: $LOGGING_LEVEL_ROOT|DEBUG level: $LOGGING_LEVEL_ROOT|INFO # NOTHNG > INFO > DEBUG > ALL
output_folder: /tmp/debug/ output_folder: /tmp/debug/

View File

@ -1,58 +0,0 @@
from cv_analysis.layout_parsing import annotate_layout_in_pdf
from cv_analysis.figure_detection import detect_figures
from cv_analysis.table_parsing import tables_in_image, parse_table
from cv_analysis.utils.draw import draw_rectangles
from cv_analysis.utils.display import show_mpl
from cv_analysis.utils.visual_logging import vizlogger
#from PIL import Image
def cut_out_content_structures(layout_rects, page):
large_rects = []
small_rects = []
for x, y, w, h in layout_rects:
rect = (x, y, w, h)
if w * h >= 75000:
cropped_page = page[y:(y + h), x:(x + w)]
large_rects.append([rect, cropped_page])
else:
cropped_page = page[y:(y + h), x:(x + w)]
small_rects.append([rect, cropped_page])
return large_rects, small_rects
def parse_content_structures(page, large_rects, small_rects):
for coordinates, cropped_image in large_rects:
figure_rects = detect_figures(cropped_image)
if len(figure_rects) == 0: # text
page = draw_rectangles(page, [coordinates], color=(0, 255, 0), annotate=True)
elif len(parse_table(cropped_image)) > 0:
#elif tables_in_image(cropped_image)[0]: # table
stats = parse_table(cropped_image)
cropped_image = draw_rectangles(cropped_image, stats, color=(255, 0, 0), annotate=True)
x,y,w,h = coordinates
page[y:y+h, x:x+w] = cropped_image
else: # figure
page = draw_rectangles(page, [coordinates], color=(0, 0, 255), annotate=True)
# for coordinates, cropped_image in small_rects:
# figure_rects = detect_figures(cropped_image)
# if len(figure_rects) == 0 and len(list(find_primary_text_regions(cropped_image))) > 0:
# page = draw_rectangles(page, [coordinates], color=(0, 255, 0), annotate=True)
# else:
# page = draw_rectangles(page, [coordinates], color=(0, 255, 255), annotate=True)
return page
def detect_figures_with_layout_parsing(pdf_path, page_index=1, show=False):
layout_rects, page = annotate_layout_in_pdf(pdf_path, page_index, return_rects=True)
big_structures, small_structures = cut_out_content_structures(layout_rects, page)
page = parse_content_structures(page, big_structures, small_structures)
vizlogger.debug(page, "figures03_final.png")
if show:
show_mpl(page)
else:
return page

View File

@ -1,7 +1,7 @@
import cv2 import cv2
import numpy as np import numpy as np
from pdf2image import pdf2image from pdf2image import pdf2image
import pandas as pd #import pandas as pd
from PIL import Image from PIL import Image
import timeit import timeit
from os import path from os import path
@ -11,6 +11,7 @@ from cv_analysis.utils.display import show_mpl
from cv_analysis.utils.draw import draw_rectangles from cv_analysis.utils.draw import draw_rectangles
from cv_analysis.utils.post_processing import remove_included from cv_analysis.utils.post_processing import remove_included
from cv_analysis.utils.filters import is_large_enough, has_acceptable_format from cv_analysis.utils.filters import is_large_enough, has_acceptable_format
from cv_analysis.utils.structures import Rectangle
from cv_analysis.utils.text import remove_primary_text_regions from cv_analysis.utils.text import remove_primary_text_regions
from cv_analysis.utils.visual_logging import vizlogger from cv_analysis.utils.visual_logging import vizlogger
@ -32,69 +33,4 @@ def detect_figures(image: np.array):
rects = map(cv2.boundingRect, cnts) rects = map(cv2.boundingRect, cnts)
rects = remove_included(rects) rects = remove_included(rects)
return list(rects) return list(map(Rectangle.from_xywh, rects))
def detect_figures_in_pdf(pdf_path, page_index=1, show=False):
page = pdf2image.convert_from_path(pdf_path, dpi=300, first_page=page_index + 1, last_page=page_index + 1)[0]
page = np.array(page)
redaction_contours = detect_figures(page)
page = draw_rectangles(page, redaction_contours)
vizlogger.debug(page, "figures03_final.png")
if show:
show_mpl(page)
return page
def detect_figures_in_test_files():
def save_as_pdf(pages):
p1, p = pages[0], pages[1:]
out_pdf_path = "/home/lillian/ocr_docs/output_files/fig_detection_pdf.pdf"
p1.save(
out_pdf_path, "PDF", resolution=150.0, save_all=True, append_images=p
)
path = "/home/lillian/ocr_docs/"
ex_pages = pd.read_csv(path+"/metadata/metadata2.csv")
pages_detected = []
t0 = timeit.default_timer()
for name, page_nr in zip(ex_pages.pdf_name, ex_pages.page):
page = pdf2image.convert_from_path(path + "/original/" + name, dpi=300, first_page=page_nr, last_page=page_nr)[0]
page = np.array(page)
redaction_contours = detect_figures(page)
page = draw_rectangles(page, redaction_contours)
pages_detected.append(Image.fromarray(page))
print(timeit.default_timer()-t0)
save_as_pdf(pages_detected)
def detect_figures_in_png(pdf_path, show=False):
page = Image.open(pdf_path)
page = np.array(page)
redaction_contours = detect_figures(page)
page = draw_rectangles(page, redaction_contours)
vizlogger.debug(page, "figures03_final.png")
if show:
show_mpl(page)
return page
def detect_figures_in_test_files_png():
file_name = pd.read_csv(METADATA_TESTFILES)
pages = []
t0 = timeit.default_timer()
for name in file_name.image_name:
page = detect_figures_in_png(path.join(PNG_FOR_TESTING, name+".png"))
pages.append(Image.fromarray(page))
t1 = timeit.default_timer()
print(t1-t0)
p1, p = pages[0], pages[1:]
out_pdf_path = path.join(PNG_FIGURES_DETECTED, "fig_detectes.pdf")
p1.save(
out_pdf_path, "PDF", resolution=300.0, save_all=True, append_images=p
)

View File

@ -4,10 +4,11 @@ from operator import __and__
import cv2 import cv2
import numpy as np import numpy as np
from pdf2image import pdf2image #from pdf2image import pdf2image
from cv_analysis.utils.display import show_mpl #from cv_analysis.utils.display import show_mpl
from cv_analysis.utils.draw import draw_rectangles #from cv_analysis.utils.draw import draw_rectangles
from cv_analysis.utils.structures import Rectangle
from cv_analysis.utils.post_processing import remove_overlapping, remove_included, has_no_parent from cv_analysis.utils.post_processing import remove_overlapping, remove_included, has_no_parent
from cv_analysis.utils.visual_logging import vizlogger from cv_analysis.utils.visual_logging import vizlogger
@ -36,17 +37,17 @@ def parse_layout(image: np.array):
if len(image_.shape) > 2: if len(image_.shape) > 2:
image_ = cv2.cvtColor(image_, cv2.COLOR_BGR2GRAY) image_ = cv2.cvtColor(image_, cv2.COLOR_BGR2GRAY)
#vizlogger.debug(image_, "layout01_start.png") vizlogger.debug(image_, "layout01_start.png")
image_ = cv2.GaussianBlur(image_, (7, 7), 0) image_ = cv2.GaussianBlur(image_, (7, 7), 0)
#vizlogger.debug(image_, "layout02_blur.png") vizlogger.debug(image_, "layout02_blur.png")
thresh = cv2.threshold(image_, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1] thresh = cv2.threshold(image_, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
vizlogger.debug(image_, "layout03_theshold.png") vizlogger.debug(image_, "layout03_theshold.png")
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5)) kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
#vizlogger.debug(kernel, "layout04_kernel.png") vizlogger.debug(kernel, "layout04_kernel.png")
dilate = cv2.dilate(thresh, kernel, iterations=4) dilate = cv2.dilate(thresh, kernel, iterations=4)
#vizlogger.debug(dilate, "layout05_dilate.png") vizlogger.debug(dilate, "layout05_dilate.png")
rects = list(find_segments(dilate)) rects = list(find_segments(dilate))
@ -55,16 +56,16 @@ def parse_layout(image: np.array):
x, y, w, h = rect x, y, w, h = rect
cv2.rectangle(image, (x, y), (x + w, y + h), (0, 0, 0), -1) cv2.rectangle(image, (x, y), (x + w, y + h), (0, 0, 0), -1)
cv2.rectangle(image, (x, y), (x + w, y + h), (255, 255, 255), 7) cv2.rectangle(image, (x, y), (x + w, y + h), (255, 255, 255), 7)
#vizlogger.debug(image, "layout06_rectangles.png") vizlogger.debug(image, "layout06_rectangles.png")
_, image = cv2.threshold(image, 254, 255, cv2.THRESH_BINARY) _, image = cv2.threshold(image, 254, 255, cv2.THRESH_BINARY)
#vizlogger.debug(image, "layout07_threshold.png") vizlogger.debug(image, "layout07_threshold.png")
image = ~image image = ~image
#vizlogger.debug(image, "layout08_inverse.png") vizlogger.debug(image, "layout08_inverse.png")
if len(image.shape) > 2: if len(image.shape) > 2:
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
#vizlogger.debug(image, "layout09_convertcolor.png") vizlogger.debug(image, "layout09_convertcolor.png")
rects = find_segments(image) rects = find_segments(image)
# <- End of meta detection # <- End of meta detection
@ -72,73 +73,23 @@ def parse_layout(image: np.array):
rects = remove_included(rects) rects = remove_included(rects)
rects = remove_overlapping(rects) rects = remove_overlapping(rects)
return list(rects) return list(map(Rectangle.from_xywh, rects))
def annotate_layout_in_pdf(pdf_path, page_index=1, return_rects=False, show=False): # def annotate_layout_in_pdf(page, return_rects=False, show=False):
page = pdf2image.convert_from_path(pdf_path, first_page=page_index + 1, last_page=page_index + 1)[0] # #page = pdf2image.convert_from_path(pdf_path, first_page=page_index + 1, last_page=page_index + 1)[0]
page = np.array(page) # #page = np.array(page)
rects = parse_layout(page) # rects = parse_layout(page)
if return_rects: # if return_rects:
return rects, page # return rects, page
elif show: # elif show:
page = draw_rectangles(page, rects) # page = draw_rectangles(page, rects)
vizlogger.debug(page, "layout10_output.png") # vizlogger.debug(page, "layout10_output.png")
show_mpl(page) # show_mpl(page)
else: # else:
page = draw_rectangles(page, rects) # page = draw_rectangles(page, rects)
return page # return page
"""
def find_layout_boxes(image: np.array):
if len(image.shape) > 2:
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
image = cv2.GaussianBlur(image, (5, 5), 1)
image = cv2.threshold(image, 253, 255, cv2.THRESH_BINARY)[1]
img_bin = ~image
line_min_width = 10
kernel_h = np.ones((10, line_min_width), np.uint8)
kernel_v = np.ones((line_min_width, 10), np.uint8)
img_bin_h = cv2.morphologyEx(img_bin, cv2.MORPH_OPEN, kernel_h)
img_bin_v = cv2.morphologyEx(img_bin, cv2.MORPH_OPEN, kernel_v)
img_bin_final = img_bin_h | img_bin_v
contours = cv2.findContours(img_bin_final, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = imutils.grab_contours(contours)
for c in contours:
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.04 * peri, True)
yield cv2.boundingRect(approx)
def annotate_layout_boxes(image, rects):
for rect in rects:
(x, y, w, h) = rect
cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)
return image
def annotate_layout_in_pdf(pdf_path, page_index=1):
page = pdf2image.convert_from_path(pdf_path, first_page=page_index + 1, last_page=page_index + 1)[0]
page = np.array(page)
layout_boxes = find_layout_boxes(page)
page = annotate_layout_boxes(page, layout_boxes)
fig, ax = plt.subplots(1, 1)
fig.set_size_inches(20, 20)
ax.imshow(page)
plt.show()
"""

View File

@ -40,14 +40,14 @@ def find_redactions(image: np.array, min_normalized_area=200000):
return [] return []
def annotate_redactions_in_pdf(pdf_path, page_index=1, show=False): # def annotate_redactions_in_pdf(page, show=False):
page = pdf2image.convert_from_path(pdf_path, first_page=page_index + 1, last_page=page_index + 1)[0] # #page = pdf2image.convert_from_path(pdf_path, first_page=page_index + 1, last_page=page_index + 1)[0]
page = np.array(page) # #page = np.array(page)
redaction_contours = find_redactions(page) # redaction_contours = find_redactions(page)
page = draw_contours(page, redaction_contours) # page = draw_contours(page, redaction_contours)
vizlogger.debug(page, "redactions05_output.png") # vizlogger.debug(page, "redactions05_output.png")
if show: # if show:
show_mpl(page) # show_mpl(page)

View File

@ -2,19 +2,16 @@
from functools import partial from functools import partial
from itertools import chain, starmap from itertools import chain, starmap
from operator import attrgetter from operator import attrgetter
import cv2 import cv2
import numpy as np import numpy as np
from pdf2image import pdf2image #from pdf2image import pdf2image
#from cv_analysis.utils.display import show_mpl
#from cv_analysis.utils.draw import draw_rectangles
from cv_analysis.utils.display import show_mpl
from cv_analysis.utils.draw import draw_rectangles
from cv_analysis.utils.post_processing import xywh_to_vecs, xywh_to_vec_rect, adjacent1d from cv_analysis.utils.post_processing import xywh_to_vecs, xywh_to_vec_rect, adjacent1d
from cv_analysis.utils.deskew import deskew_histbased, deskew #from cv_analysis.utils.deskew import deskew_histbased, deskew
from cv_analysis.utils.filters import is_large_enough #from cv_analysis.utils.filters import is_large_enough
from cv_analysis.utils.structures import Rectangle
from cv_analysis.utils.visual_logging import vizlogger from cv_analysis.utils.visual_logging import vizlogger
from cv_analysis.layout_parsing import parse_layout from cv_analysis.layout_parsing import parse_layout
@ -138,7 +135,7 @@ def find_table_layout_boxes(image: np.array):
for box in layout_boxes: for box in layout_boxes:
(x, y, w, h) = box (x, y, w, h) = box
if w * h >= 100000: if w * h >= 100000:
table_boxes.append(box) table_boxes.append(Rectangle.from_xywh(box))
return table_boxes return table_boxes
@ -148,7 +145,7 @@ def preprocess(image: np.array):
return ~image return ~image
def parse_table(image: np.array, show=False): def parse_tables(image: np.array, show=False):
"""Runs the full table parsing process. """Runs the full table parsing process.
Args: Args:
@ -164,42 +161,33 @@ def parse_table(image: np.array, show=False):
image = preprocess(image) image = preprocess(image)
table_layout_boxes = find_table_layout_boxes(image) #table_layout_boxes = find_table_layout_boxes(image)
image = isolate_vertical_and_horizontal_components(image) image = isolate_vertical_and_horizontal_components(image)
# image = add_external_contours(image, image) # image = add_external_contours(image, image)
# vizlogger.debug(image, "external_contours_added.png") vizlogger.debug(image, "external_contours_added.png")
_, _, stats, _ = cv2.connectedComponentsWithStats(~image, connectivity=8, ltype=cv2.CV_32S) _, _, stats, _ = cv2.connectedComponentsWithStats(~image, connectivity=8, ltype=cv2.CV_32S)
stats = np.vstack(list(filter(is_large_enough, stats))) stats = np.vstack(list(filter(is_large_enough, stats)))
rects = stats[:, :-1][2:] rects = stats[:, :-1][2:]
return list(map(list, rects)) #print(rects)
return list(map(Rectangle.from_xywh, rects))
def annotate_tables_in_pdf(pdf_path, page_index=0, deskew=False, show=False): # def annotate_tables_in_pdf(page, page_index=0, deskew=False, show=False):
""" """ # """ """
page = pdf2image.convert_from_path(pdf_path, first_page=page_index + 1, last_page=page_index + 1)[0] # #page = pdf2image.convert_from_path(pdf_path, first_page=page_index + 1, last_page=page_index + 1)[0]
page = np.array(page) # #page = np.array(page)
if show: # if show:
show_mpl(page) # show_mpl(page)
if deskew: # if deskew:
page, _ = deskew_histbased(page) # page, _ = deskew_histbased(page)
stats = parse_table(page)
page = draw_rectangles(page, stats, annotate=True)
vizlogger.debug(page, "tables15_final_output.png")
if show:
show_mpl(page)
def tables_in_image(cropped_image):
table_rects = parse_table(cropped_image)
if len(table_rects) > 0:
return True, table_rects
else:
return False, None
# stats = parse_tables(page)
# page = draw_rectangles(page, stats, annotate=True)
# vizlogger.debug(page, "tables15_final_output.png")
# if show:
# show_mpl(page)

View File

@ -0,0 +1,54 @@
{
"images": [
{
"name": "test1.png",
"source_document": "Amended Residue analytical method for the determ.pdf",
"page": 7
},
{
"name": "test2.png",
"source_document": "Amended Residue analytical method for the determ.pdf",
"page": 39
},
{
"name": "test3.png",
"source_document": "VV-857853.pdf",
"page": 8
},
{
"name": "test4.png",
"source_document": "Sulphur_RAR_09_Volume_3CA_B-7_2021-04-09.pdf",
"page": 25
},
{
"name": "test5.png",
"source_document": "Sulphur_RAR_09_Volume_3CA_B-7_2021-04-09.pdf",
"page": 35
},
{
"name": "test6.png",
"source_document": "VV-128279.pdf",
"page": 49
},
{
"name": "test7.png",
"source_document": "VV-376573.pdf",
"page": 86
},
{
"name": "test8.png",
"source_document": "VV-377325.pdf",
"page": 218
},
{
"name": "test9.png",
"source_document": "VV-857853.pdf",
"page": 10
},
{
"name": "test10.png",
"source_document": "VV-334103.pdf",
"page": 28
}
]
}

View File

@ -1,62 +1,359 @@
{ {
"0": [ "pages": [
[211, 447, 367, 47], {
[581, 447, 417, 47], "page": 0,
[1001, 447, 406, 47], "pageWidth": 2346,
[211, 497, 367, 47], "pageHeight": 1663,
[580, 497, 418, 47], "cells": [
[1001, 497, 406, 47], {
[211, 547, 367, 47], "x": 211,
[580, 547, 418, 47], "y": 447,
[1001, 547, 406, 47], "width": 367,
[211, 597, 367, 47], "height": 47
[581, 597, 417, 47], },
[1001, 597, 406, 48], {
[212, 647, 366, 48], "x": 581,
[581, 647, 417, 48], "y": 447,
[1001, 647, 406, 48], "width": 417,
[581, 697, 417, 47], "height": 47
[1001, 697, 407, 48], },
[212, 698, 366, 47], {
[211, 747, 367, 48], "x": 1001,
[581, 747, 417, 48], "y": 447,
[1001, 748, 407, 47], "width": 406,
[211, 798, 367, 47], "height": 47
[581, 798, 417, 47], },
[1001, 798, 407, 47], {
[212, 848, 366, 47], "x": 211,
[581, 848, 417, 47], "y": 497,
[1001, 848, 407, 48], "width": 367,
[212, 898, 366, 48], "height": 47
[581, 898, 417, 48], },
[1001, 898, 407, 48], {
[462, 1195, 368, 48], "x": 580,
[833, 1195, 404, 48], "y": 497,
[462, 1245, 368, 48], "width": 418,
[833, 1245, 404, 47], "height": 47
[462, 1296, 368, 47], },
[833, 1296, 404, 47], {
[462, 1346, 368, 47], "x": 1001,
[833, 1346, 404, 47], "y": 497,
[462, 1396, 368, 47], "width": 406,
[834, 1396, 403, 47], "height": 47
[462, 1446, 368, 48], },
[833, 1446, 404, 48], {
[462, 1496, 368, 48], "x": 211,
[833, 1496, 404, 48], "y": 547,
[462, 1547, 368, 47], "width": 367,
[834, 1547, 403, 47], "height": 47
[462, 1597, 368, 48], },
[834, 1597, 403, 47], {
[462, 1647, 368, 48], "x": 580,
[833, 1647, 404, 48], "y": 547,
[462, 1698, 368, 47], "width": 418,
[833, 1698, 404, 47], "height": 47
[462, 1748, 368, 47], },
[834, 1748, 403, 47], {
[462, 1798, 368, 47], "x": 1001,
[834, 1798, 403, 47], "y": 547,
[462, 1848, 368, 48], "width": 406,
[834, 1848, 403, 48] "height": 47
},
{
"x": 211,
"y": 597,
"width": 367,
"height": 47
},
{
"x": 581,
"y": 597,
"width": 417,
"height": 47
},
{
"x": 1001,
"y": 597,
"width": 406,
"height": 48
},
{
"x": 212,
"y": 647,
"width": 366,
"height": 48
},
{
"x": 581,
"y": 647,
"width": 417,
"height": 48
},
{
"x": 1001,
"y": 647,
"width": 406,
"height": 48
},
{
"x": 581,
"y": 697,
"width": 417,
"height": 47
},
{
"x": 1001,
"y": 697,
"width": 407,
"height": 48
},
{
"x": 212,
"y": 698,
"width": 366,
"height": 47
},
{
"x": 211,
"y": 747,
"width": 367,
"height": 48
},
{
"x": 581,
"y": 747,
"width": 417,
"height": 48
},
{
"x": 1001,
"y": 748,
"width": 407,
"height": 47
},
{
"x": 211,
"y": 798,
"width": 367,
"height": 47
},
{
"x": 581,
"y": 798,
"width": 417,
"height": 47
},
{
"x": 1001,
"y": 798,
"width": 407,
"height": 47
},
{
"x": 212,
"y": 848,
"width": 366,
"height": 47
},
{
"x": 581,
"y": 848,
"width": 417,
"height": 47
},
{
"x": 1001,
"y": 848,
"width": 407,
"height": 48
},
{
"x": 212,
"y": 898,
"width": 366,
"height": 48
},
{
"x": 581,
"y": 898,
"width": 417,
"height": 48
},
{
"x": 1001,
"y": 898,
"width": 407,
"height": 48
},
{
"x": 462,
"y": 1195,
"width": 368,
"height": 48
},
{
"x": 833,
"y": 1195,
"width": 404,
"height": 48
},
{
"x": 462,
"y": 1245,
"width": 368,
"height": 48
},
{
"x": 833,
"y": 1245,
"width": 404,
"height": 47
},
{
"x": 462,
"y": 1296,
"width": 368,
"height": 47
},
{
"x": 833,
"y": 1296,
"width": 404,
"height": 47
},
{
"x": 462,
"y": 1346,
"width": 368,
"height": 47
},
{
"x": 833,
"y": 1346,
"width": 404,
"height": 47
},
{
"x": 462,
"y": 1396,
"width": 368,
"height": 47
},
{
"x": 834,
"y": 1396,
"width": 403,
"height": 47
},
{
"x": 462,
"y": 1446,
"width": 368,
"height": 48
},
{
"x": 833,
"y": 1446,
"width": 404,
"height": 48
},
{
"x": 462,
"y": 1496,
"width": 368,
"height": 48
},
{
"x": 833,
"y": 1496,
"width": 404,
"height": 48
},
{
"x": 462,
"y": 1547,
"width": 368,
"height": 47
},
{
"x": 834,
"y": 1547,
"width": 403,
"height": 47
},
{
"x": 462,
"y": 1597,
"width": 368,
"height": 48
},
{
"x": 834,
"y": 1597,
"width": 403,
"height": 47
},
{
"x": 462,
"y": 1647,
"width": 368,
"height": 48
},
{
"x": 833,
"y": 1647,
"width": 404,
"height": 48
},
{
"x": 462,
"y": 1698,
"width": 368,
"height": 47
},
{
"x": 833,
"y": 1698,
"width": 404,
"height": 47
},
{
"x": 462,
"y": 1748,
"width": 368,
"height": 47
},
{
"x": 834,
"y": 1748,
"width": 403,
"height": 47
},
{
"x": 462,
"y": 1798,
"width": 368,
"height": 47
},
{
"x": 834,
"y": 1798,
"width": 403,
"height": 47
},
{
"x": 462,
"y": 1848,
"width": 368,
"height": 48
},
{
"x": 834,
"y": 1848,
"width": 403,
"height": 48
}
]
}
] ]
} }

View File

@ -0,0 +1,191 @@
{
"pages": [
{
"page": 0,
"pageWidth": 2481,
"pageHeight": 3509,
"cells": [
{
"x": 604,
"y": 400,
"width": 399,
"height": 142
},
{
"x": 1006,
"y": 400,
"width": 49,
"height": 142
},
{
"x": 1058,
"y": 400,
"width": 1215,
"height": 142
},
{
"x": 604,
"y": 545,
"width": 399,
"height": 83
},
{
"x": 1006,
"y": 545,
"width": 49,
"height": 83
},
{
"x": 1058,
"y": 545,
"width": 1215,
"height": 83
},
{
"x": 604,
"y": 631,
"width": 399,
"height": 84
},
{
"x": 1006,
"y": 631,
"width": 49,
"height": 84
},
{
"x": 1058,
"y": 631,
"width": 1215,
"height": 84
},
{
"x": 604,
"y": 718,
"width": 399,
"height": 84
},
{
"x": 1006,
"y": 718,
"width": 49,
"height": 84
},
{
"x": 1058,
"y": 718,
"width": 1215,
"height": 84
},
{
"x": 604,
"y": 805,
"width": 399,
"height": 804
},
{
"x": 1006,
"y": 805,
"width": 49,
"height": 804
},
{
"x": 1058,
"y": 805,
"width": 1215,
"height": 804
},
{
"x": 604,
"y": 1724,
"width": 399,
"height": 84
},
{
"x": 1006,
"y": 1724,
"width": 49,
"height": 84
},
{
"x": 1058,
"y": 1724,
"width": 1215,
"height": 84
},
{
"x": 604,
"y": 1811,
"width": 399,
"height": 83
},
{
"x": 1006,
"y": 1811,
"width": 49,
"height": 83
},
{
"x": 1058,
"y": 1811,
"width": 1215,
"height": 83
},
{
"x": 604,
"y": 1897,
"width": 399,
"height": 84
},
{
"x": 1006,
"y": 1897,
"width": 49,
"height": 84
},
{
"x": 1058,
"y": 1897,
"width": 1215,
"height": 84
},
{
"x": 604,
"y": 1984,
"width": 399,
"height": 84
},
{
"x": 1006,
"y": 1984,
"width": 49,
"height": 84
},
{
"x": 1058,
"y": 1984,
"width": 1215,
"height": 84
},
{
"x": 604,
"y": 2071,
"width": 399,
"height": 813
},
{
"x": 1006,
"y": 2071,
"width": 49,
"height": 813
},
{
"x": 1058,
"y": 2071,
"width": 1215,
"height": 813
}
]
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 KiB

View File

@ -0,0 +1,851 @@
{
"pages": [
{
"page": 0,
"pageWidth": 2480,
"pageHeight": 3509,
"cells": [
{
"x": 1828,
"y": 1667,
"width": 382,
"height": 55
},
{
"x": 1477,
"y": 1670,
"width": 349,
"height": 55
},
{
"x": 1126,
"y": 1673,
"width": 349,
"height": 54
},
{
"x": 776,
"y": 1676,
"width": 348,
"height": 54
},
{
"x": 425,
"y": 1678,
"width": 348,
"height": 54
},
{
"x": 1828,
"y": 1722,
"width": 382,
"height": 55
},
{
"x": 1477,
"y": 1725,
"width": 349,
"height": 55
},
{
"x": 1126,
"y": 1728,
"width": 349,
"height": 54
},
{
"x": 776,
"y": 1730,
"width": 348,
"height": 55
},
{
"x": 425,
"y": 1733,
"width": 349,
"height": 54
},
{
"x": 1828,
"y": 1777,
"width": 382,
"height": 54
},
{
"x": 1478,
"y": 1780,
"width": 348,
"height": 54
},
{
"x": 1126,
"y": 1783,
"width": 349,
"height": 53
},
{
"x": 776,
"y": 1786,
"width": 348,
"height": 53
},
{
"x": 426,
"y": 1788,
"width": 348,
"height": 53
},
{
"x": 1828,
"y": 1832,
"width": 382,
"height": 54
},
{
"x": 1478,
"y": 1835,
"width": 348,
"height": 54
},
{
"x": 1126,
"y": 1837,
"width": 349,
"height": 55
},
{
"x": 776,
"y": 1840,
"width": 348,
"height": 54
},
{
"x": 426,
"y": 1843,
"width": 348,
"height": 53
},
{
"x": 1829,
"y": 1887,
"width": 381,
"height": 54
},
{
"x": 1478,
"y": 1890,
"width": 348,
"height": 53
},
{
"x": 1126,
"y": 1892,
"width": 349,
"height": 54
},
{
"x": 776,
"y": 1895,
"width": 348,
"height": 53
},
{
"x": 426,
"y": 1898,
"width": 348,
"height": 53
},
{
"x": 1829,
"y": 1941,
"width": 381,
"height": 54
},
{
"x": 1478,
"y": 1944,
"width": 348,
"height": 54
},
{
"x": 1126,
"y": 1947,
"width": 349,
"height": 53
},
{
"x": 776,
"y": 1949,
"width": 348,
"height": 54
},
{
"x": 426,
"y": 1952,
"width": 348,
"height": 53
},
{
"x": 1829,
"y": 1995,
"width": 381,
"height": 55
},
{
"x": 1478,
"y": 1999,
"width": 348,
"height": 53
},
{
"x": 1127,
"y": 2001,
"width": 348,
"height": 54
},
{
"x": 776,
"y": 2004,
"width": 348,
"height": 53
},
{
"x": 426,
"y": 2006,
"width": 348,
"height": 54
},
{
"x": 1829,
"y": 2050,
"width": 382,
"height": 54
},
{
"x": 1478,
"y": 2053,
"width": 348,
"height": 54
},
{
"x": 1127,
"y": 2056,
"width": 349,
"height": 54
},
{
"x": 776,
"y": 2058,
"width": 348,
"height": 54
},
{
"x": 426,
"y": 2061,
"width": 348,
"height": 54
},
{
"x": 1829,
"y": 2105,
"width": 382,
"height": 54
},
{
"x": 1478,
"y": 2108,
"width": 349,
"height": 54
},
{
"x": 1127,
"y": 2110,
"width": 349,
"height": 54
},
{
"x": 776,
"y": 2113,
"width": 348,
"height": 54
},
{
"x": 426,
"y": 2116,
"width": 348,
"height": 54
},
{
"x": 1829,
"y": 2159,
"width": 382,
"height": 55
},
{
"x": 1478,
"y": 2164,
"width": 349,
"height": 52
},
{
"x": 1127,
"y": 2166,
"width": 349,
"height": 53
},
{
"x": 776,
"y": 2169,
"width": 348,
"height": 53
},
{
"x": 426,
"y": 2172,
"width": 348,
"height": 52
},
{
"x": 1829,
"y": 2215,
"width": 382,
"height": 55
},
{
"x": 1478,
"y": 2218,
"width": 349,
"height": 54
},
{
"x": 1127,
"y": 2221,
"width": 349,
"height": 54
},
{
"x": 776,
"y": 2224,
"width": 348,
"height": 53
},
{
"x": 426,
"y": 2226,
"width": 348,
"height": 54
},
{
"x": 1830,
"y": 2271,
"width": 381,
"height": 50
},
{
"x": 1479,
"y": 2274,
"width": 348,
"height": 49
},
{
"x": 1127,
"y": 2276,
"width": 349,
"height": 50
},
{
"x": 776,
"y": 2279,
"width": 348,
"height": 49
},
{
"x": 426,
"y": 2282,
"width": 348,
"height": 49
},
{
"x": 1830,
"y": 2322,
"width": 383,
"height": 53
},
{
"x": 1480,
"y": 2325,
"width": 348,
"height": 53
},
{
"x": 1127,
"y": 2328,
"width": 350,
"height": 52
},
{
"x": 776,
"y": 2330,
"width": 348,
"height": 53
},
{
"x": 426,
"y": 2333,
"width": 348,
"height": 52
},
{
"x": 1831,
"y": 2377,
"width": 382,
"height": 52
},
{
"x": 1480,
"y": 2380,
"width": 348,
"height": 52
},
{
"x": 1127,
"y": 2382,
"width": 350,
"height": 52
},
{
"x": 776,
"y": 2385,
"width": 348,
"height": 51
},
{
"x": 426,
"y": 2388,
"width": 348,
"height": 51
},
{
"x": 1831,
"y": 2430,
"width": 382,
"height": 53
},
{
"x": 1480,
"y": 2433,
"width": 348,
"height": 53
},
{
"x": 1127,
"y": 2436,
"width": 350,
"height": 53
},
{
"x": 777,
"y": 2438,
"width": 348,
"height": 53
},
{
"x": 426,
"y": 2441,
"width": 348,
"height": 52
},
{
"x": 1831,
"y": 2485,
"width": 383,
"height": 53
},
{
"x": 1480,
"y": 2488,
"width": 348,
"height": 52
},
{
"x": 1127,
"y": 2490,
"width": 350,
"height": 53
},
{
"x": 777,
"y": 2493,
"width": 348,
"height": 52
},
{
"x": 427,
"y": 2495,
"width": 348,
"height": 53
},
{
"x": 1831,
"y": 2539,
"width": 383,
"height": 53
},
{
"x": 1480,
"y": 2542,
"width": 349,
"height": 53
},
{
"x": 1127,
"y": 2545,
"width": 350,
"height": 52
},
{
"x": 777,
"y": 2547,
"width": 348,
"height": 53
},
{
"x": 427,
"y": 2550,
"width": 348,
"height": 52
},
{
"x": 1831,
"y": 2593,
"width": 383,
"height": 54
},
{
"x": 1480,
"y": 2596,
"width": 349,
"height": 54
},
{
"x": 1127,
"y": 2599,
"width": 351,
"height": 53
},
{
"x": 777,
"y": 2601,
"width": 348,
"height": 54
},
{
"x": 427,
"y": 2604,
"width": 348,
"height": 53
},
{
"x": 1831,
"y": 2649,
"width": 383,
"height": 53
},
{
"x": 1480,
"y": 2652,
"width": 349,
"height": 52
},
{
"x": 1128,
"y": 2654,
"width": 350,
"height": 53
},
{
"x": 777,
"y": 2657,
"width": 348,
"height": 52
},
{
"x": 427,
"y": 2659,
"width": 348,
"height": 53
},
{
"x": 1832,
"y": 2703,
"width": 382,
"height": 54
},
{
"x": 1480,
"y": 2706,
"width": 349,
"height": 53
},
{
"x": 1128,
"y": 2709,
"width": 350,
"height": 53
},
{
"x": 778,
"y": 2711,
"width": 347,
"height": 53
},
{
"x": 427,
"y": 2714,
"width": 348,
"height": 53
},
{
"x": 1832,
"y": 2758,
"width": 382,
"height": 53
},
{
"x": 1481,
"y": 2761,
"width": 348,
"height": 53
},
{
"x": 1128,
"y": 2764,
"width": 350,
"height": 52
},
{
"x": 778,
"y": 2766,
"width": 348,
"height": 53
},
{
"x": 427,
"y": 2769,
"width": 348,
"height": 52
},
{
"x": 1832,
"y": 2812,
"width": 382,
"height": 55
},
{
"x": 1481,
"y": 2816,
"width": 349,
"height": 53
},
{
"x": 1128,
"y": 2818,
"width": 351,
"height": 54
},
{
"x": 778,
"y": 2820,
"width": 348,
"height": 54
},
{
"x": 428,
"y": 2823,
"width": 347,
"height": 53
},
{
"x": 1832,
"y": 2868,
"width": 382,
"height": 54
},
{
"x": 1481,
"y": 2871,
"width": 349,
"height": 53
},
{
"x": 1128,
"y": 2873,
"width": 351,
"height": 54
},
{
"x": 778,
"y": 2876,
"width": 348,
"height": 53
},
{
"x": 428,
"y": 2878,
"width": 348,
"height": 53
},
{
"x": 1832,
"y": 2923,
"width": 382,
"height": 53
},
{
"x": 1481,
"y": 2926,
"width": 349,
"height": 52
},
{
"x": 1128,
"y": 2928,
"width": 351,
"height": 53
},
{
"x": 778,
"y": 2931,
"width": 348,
"height": 52
},
{
"x": 428,
"y": 2933,
"width": 348,
"height": 52
},
{
"x": 1832,
"y": 2978,
"width": 382,
"height": 53
},
{
"x": 1481,
"y": 2980,
"width": 349,
"height": 53
},
{
"x": 1129,
"y": 2983,
"width": 350,
"height": 53
},
{
"x": 778,
"y": 2985,
"width": 348,
"height": 53
},
{
"x": 428,
"y": 2987,
"width": 348,
"height": 53
},
{
"x": 1832,
"y": 3032,
"width": 382,
"height": 53
},
{
"x": 1481,
"y": 3035,
"width": 349,
"height": 52
},
{
"x": 1129,
"y": 3038,
"width": 350,
"height": 52
},
{
"x": 779,
"y": 3040,
"width": 348,
"height": 52
},
{
"x": 428,
"y": 3042,
"width": 349,
"height": 53
},
{
"x": 1832,
"y": 3086,
"width": 382,
"height": 55
},
{
"x": 1481,
"y": 3089,
"width": 349,
"height": 54
},
{
"x": 1129,
"y": 3092,
"width": 350,
"height": 54
},
{
"x": 779,
"y": 3094,
"width": 348,
"height": 54
},
{
"x": 429,
"y": 3097,
"width": 348,
"height": 53
},
{
"x": 1832,
"y": 3141,
"width": 382,
"height": 55
},
{
"x": 1481,
"y": 3144,
"width": 349,
"height": 55
},
{
"x": 1129,
"y": 3147,
"width": 350,
"height": 54
},
{
"x": 779,
"y": 3149,
"width": 349,
"height": 55
},
{
"x": 429,
"y": 3152,
"width": 348,
"height": 54
}
]
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 316 KiB

View File

@ -0,0 +1,839 @@
{
"pages": [
{
"page": 0,
"pageWidth": 2481,
"pageHeight": 3509,
"cells": [
{
"x": 327,
"y": 609,
"width": 353,
"height": 161
},
{
"x": 683,
"y": 609,
"width": 311,
"height": 161
},
{
"x": 997,
"y": 609,
"width": 531,
"height": 161
},
{
"x": 1531,
"y": 609,
"width": 247,
"height": 161
},
{
"x": 1781,
"y": 609,
"width": 246,
"height": 161
},
{
"x": 2030,
"y": 609,
"width": 246,
"height": 161
},
{
"x": 327,
"y": 773,
"width": 353,
"height": 272
},
{
"x": 683,
"y": 773,
"width": 311,
"height": 65
},
{
"x": 997,
"y": 773,
"width": 531,
"height": 65
},
{
"x": 1531,
"y": 773,
"width": 247,
"height": 65
},
{
"x": 1781,
"y": 773,
"width": 246,
"height": 65
},
{
"x": 2030,
"y": 773,
"width": 246,
"height": 65
},
{
"x": 683,
"y": 841,
"width": 311,
"height": 66
},
{
"x": 997,
"y": 841,
"width": 531,
"height": 66
},
{
"x": 1531,
"y": 841,
"width": 247,
"height": 66
},
{
"x": 1781,
"y": 841,
"width": 246,
"height": 66
},
{
"x": 2030,
"y": 841,
"width": 246,
"height": 66
},
{
"x": 683,
"y": 910,
"width": 311,
"height": 66
},
{
"x": 997,
"y": 910,
"width": 531,
"height": 66
},
{
"x": 1531,
"y": 910,
"width": 247,
"height": 66
},
{
"x": 1781,
"y": 910,
"width": 246,
"height": 66
},
{
"x": 2030,
"y": 910,
"width": 246,
"height": 66
},
{
"x": 683,
"y": 979,
"width": 311,
"height": 66
},
{
"x": 997,
"y": 979,
"width": 531,
"height": 66
},
{
"x": 1531,
"y": 979,
"width": 247,
"height": 66
},
{
"x": 1781,
"y": 979,
"width": 246,
"height": 66
},
{
"x": 2030,
"y": 979,
"width": 246,
"height": 66
},
{
"x": 327,
"y": 1047,
"width": 353,
"height": 273
},
{
"x": 683,
"y": 1048,
"width": 311,
"height": 65
},
{
"x": 997,
"y": 1048,
"width": 531,
"height": 65
},
{
"x": 1531,
"y": 1048,
"width": 247,
"height": 65
},
{
"x": 1781,
"y": 1048,
"width": 246,
"height": 65
},
{
"x": 2030,
"y": 1048,
"width": 246,
"height": 65
},
{
"x": 683,
"y": 1116,
"width": 311,
"height": 66
},
{
"x": 997,
"y": 1116,
"width": 531,
"height": 66
},
{
"x": 1531,
"y": 1116,
"width": 247,
"height": 66
},
{
"x": 1781,
"y": 1116,
"width": 246,
"height": 66
},
{
"x": 2030,
"y": 1116,
"width": 246,
"height": 66
},
{
"x": 683,
"y": 1185,
"width": 311,
"height": 66
},
{
"x": 997,
"y": 1185,
"width": 531,
"height": 66
},
{
"x": 1531,
"y": 1185,
"width": 247,
"height": 66
},
{
"x": 1781,
"y": 1185,
"width": 246,
"height": 66
},
{
"x": 2030,
"y": 1185,
"width": 246,
"height": 66
},
{
"x": 683,
"y": 1254,
"width": 311,
"height": 66
},
{
"x": 997,
"y": 1254,
"width": 531,
"height": 66
},
{
"x": 1531,
"y": 1254,
"width": 247,
"height": 66
},
{
"x": 1781,
"y": 1254,
"width": 246,
"height": 66
},
{
"x": 2030,
"y": 1254,
"width": 246,
"height": 66
},
{
"x": 327,
"y": 1322,
"width": 353,
"height": 273
},
{
"x": 683,
"y": 1323,
"width": 311,
"height": 66
},
{
"x": 997,
"y": 1323,
"width": 531,
"height": 66
},
{
"x": 1531,
"y": 1323,
"width": 247,
"height": 66
},
{
"x": 1781,
"y": 1323,
"width": 246,
"height": 66
},
{
"x": 2030,
"y": 1323,
"width": 246,
"height": 66
},
{
"x": 683,
"y": 1392,
"width": 311,
"height": 65
},
{
"x": 997,
"y": 1392,
"width": 531,
"height": 65
},
{
"x": 1531,
"y": 1392,
"width": 247,
"height": 65
},
{
"x": 1781,
"y": 1392,
"width": 246,
"height": 65
},
{
"x": 2030,
"y": 1392,
"width": 246,
"height": 65
},
{
"x": 683,
"y": 1460,
"width": 311,
"height": 66
},
{
"x": 997,
"y": 1460,
"width": 531,
"height": 66
},
{
"x": 1531,
"y": 1460,
"width": 247,
"height": 66
},
{
"x": 1781,
"y": 1460,
"width": 246,
"height": 66
},
{
"x": 2030,
"y": 1460,
"width": 246,
"height": 66
},
{
"x": 683,
"y": 1529,
"width": 311,
"height": 66
},
{
"x": 997,
"y": 1529,
"width": 531,
"height": 66
},
{
"x": 1531,
"y": 1529,
"width": 247,
"height": 66
},
{
"x": 1781,
"y": 1529,
"width": 246,
"height": 66
},
{
"x": 2030,
"y": 1529,
"width": 246,
"height": 66
},
{
"x": 327,
"y": 1849,
"width": 353,
"height": 161
},
{
"x": 683,
"y": 1849,
"width": 311,
"height": 161
},
{
"x": 997,
"y": 1849,
"width": 531,
"height": 161
},
{
"x": 1531,
"y": 1849,
"width": 247,
"height": 161
},
{
"x": 1781,
"y": 1849,
"width": 246,
"height": 161
},
{
"x": 2030,
"y": 1849,
"width": 246,
"height": 161
},
{
"x": 327,
"y": 2013,
"width": 353,
"height": 272
},
{
"x": 683,
"y": 2013,
"width": 311,
"height": 66
},
{
"x": 997,
"y": 2013,
"width": 531,
"height": 66
},
{
"x": 1531,
"y": 2013,
"width": 247,
"height": 66
},
{
"x": 1781,
"y": 2013,
"width": 246,
"height": 66
},
{
"x": 2030,
"y": 2013,
"width": 246,
"height": 66
},
{
"x": 683,
"y": 2082,
"width": 311,
"height": 65
},
{
"x": 997,
"y": 2082,
"width": 531,
"height": 65
},
{
"x": 1531,
"y": 2082,
"width": 247,
"height": 65
},
{
"x": 1781,
"y": 2082,
"width": 246,
"height": 65
},
{
"x": 2030,
"y": 2082,
"width": 246,
"height": 65
},
{
"x": 683,
"y": 2150,
"width": 311,
"height": 66
},
{
"x": 997,
"y": 2150,
"width": 531,
"height": 66
},
{
"x": 1531,
"y": 2150,
"width": 247,
"height": 66
},
{
"x": 1781,
"y": 2150,
"width": 246,
"height": 66
},
{
"x": 2030,
"y": 2150,
"width": 246,
"height": 66
},
{
"x": 683,
"y": 2219,
"width": 311,
"height": 66
},
{
"x": 997,
"y": 2219,
"width": 531,
"height": 66
},
{
"x": 1531,
"y": 2219,
"width": 247,
"height": 66
},
{
"x": 1781,
"y": 2219,
"width": 246,
"height": 66
},
{
"x": 2030,
"y": 2219,
"width": 246,
"height": 66
},
{
"x": 327,
"y": 2287,
"width": 353,
"height": 273
},
{
"x": 683,
"y": 2288,
"width": 311,
"height": 66
},
{
"x": 997,
"y": 2288,
"width": 531,
"height": 66
},
{
"x": 1531,
"y": 2288,
"width": 247,
"height": 66
},
{
"x": 1781,
"y": 2288,
"width": 246,
"height": 66
},
{
"x": 2030,
"y": 2288,
"width": 246,
"height": 66
},
{
"x": 683,
"y": 2357,
"width": 311,
"height": 65
},
{
"x": 997,
"y": 2357,
"width": 531,
"height": 65
},
{
"x": 1531,
"y": 2357,
"width": 247,
"height": 65
},
{
"x": 1781,
"y": 2357,
"width": 246,
"height": 65
},
{
"x": 2030,
"y": 2357,
"width": 246,
"height": 65
},
{
"x": 683,
"y": 2425,
"width": 311,
"height": 66
},
{
"x": 997,
"y": 2425,
"width": 531,
"height": 66
},
{
"x": 1531,
"y": 2425,
"width": 247,
"height": 66
},
{
"x": 1781,
"y": 2425,
"width": 246,
"height": 66
},
{
"x": 2030,
"y": 2425,
"width": 246,
"height": 66
},
{
"x": 683,
"y": 2494,
"width": 311,
"height": 66
},
{
"x": 997,
"y": 2494,
"width": 531,
"height": 66
},
{
"x": 1531,
"y": 2494,
"width": 247,
"height": 66
},
{
"x": 1781,
"y": 2494,
"width": 246,
"height": 66
},
{
"x": 2030,
"y": 2494,
"width": 246,
"height": 66
},
{
"x": 327,
"y": 2562,
"width": 353,
"height": 273
},
{
"x": 683,
"y": 2563,
"width": 311,
"height": 66
},
{
"x": 997,
"y": 2563,
"width": 531,
"height": 66
},
{
"x": 1531,
"y": 2563,
"width": 247,
"height": 66
},
{
"x": 1781,
"y": 2563,
"width": 246,
"height": 66
},
{
"x": 2030,
"y": 2563,
"width": 246,
"height": 66
},
{
"x": 683,
"y": 2632,
"width": 311,
"height": 65
},
{
"x": 997,
"y": 2632,
"width": 531,
"height": 65
},
{
"x": 1531,
"y": 2632,
"width": 247,
"height": 65
},
{
"x": 1781,
"y": 2632,
"width": 246,
"height": 65
},
{
"x": 2030,
"y": 2632,
"width": 246,
"height": 65
},
{
"x": 683,
"y": 2700,
"width": 311,
"height": 66
},
{
"x": 997,
"y": 2700,
"width": 531,
"height": 66
},
{
"x": 1531,
"y": 2700,
"width": 247,
"height": 66
},
{
"x": 1781,
"y": 2700,
"width": 246,
"height": 66
},
{
"x": 2030,
"y": 2700,
"width": 246,
"height": 66
},
{
"x": 683,
"y": 2769,
"width": 311,
"height": 66
},
{
"x": 997,
"y": 2769,
"width": 531,
"height": 66
},
{
"x": 1531,
"y": 2769,
"width": 247,
"height": 66
},
{
"x": 1781,
"y": 2769,
"width": 246,
"height": 66
},
{
"x": 2030,
"y": 2769,
"width": 246,
"height": 66
}
]
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 KiB

View File

@ -0,0 +1,233 @@
{
"pages": [
{
"page": 0,
"pageWidth": 2481,
"pageHeight": 3506,
"cells": [
{
"x": 195,
"y": 1519,
"width": 2091,
"height": 84
},
{
"x": 195,
"y": 1604,
"width": 583,
"height": 123
},
{
"x": 783,
"y": 1605,
"width": 1503,
"height": 124
},
{
"x": 195,
"y": 1730,
"width": 583,
"height": 65
},
{
"x": 783,
"y": 1731,
"width": 1502,
"height": 66
},
{
"x": 195,
"y": 1798,
"width": 583,
"height": 65
},
{
"x": 783,
"y": 1799,
"width": 1502,
"height": 66
},
{
"x": 195,
"y": 1866,
"width": 583,
"height": 65
},
{
"x": 782,
"y": 1867,
"width": 1503,
"height": 66
},
{
"x": 195,
"y": 1934,
"width": 583,
"height": 65
},
{
"x": 782,
"y": 1935,
"width": 1503,
"height": 66
},
{
"x": 194,
"y": 2003,
"width": 584,
"height": 64
},
{
"x": 782,
"y": 2003,
"width": 535,
"height": 66
},
{
"x": 1321,
"y": 2005,
"width": 455,
"height": 64
},
{
"x": 1780,
"y": 2005,
"width": 505,
"height": 65
},
{
"x": 193,
"y": 2071,
"width": 585,
"height": 65
},
{
"x": 782,
"y": 2071,
"width": 535,
"height": 66
},
{
"x": 1321,
"y": 2073,
"width": 455,
"height": 64
},
{
"x": 1780,
"y": 2073,
"width": 505,
"height": 65
},
{
"x": 193,
"y": 2139,
"width": 585,
"height": 65
},
{
"x": 782,
"y": 2140,
"width": 535,
"height": 65
},
{
"x": 1321,
"y": 2141,
"width": 455,
"height": 64
},
{
"x": 1780,
"y": 2141,
"width": 505,
"height": 65
},
{
"x": 193,
"y": 2207,
"width": 585,
"height": 65
},
{
"x": 782,
"y": 2208,
"width": 535,
"height": 65
},
{
"x": 1321,
"y": 2209,
"width": 455,
"height": 64
},
{
"x": 1780,
"y": 2210,
"width": 505,
"height": 64
},
{
"x": 193,
"y": 2275,
"width": 585,
"height": 66
},
{
"x": 782,
"y": 2276,
"width": 535,
"height": 65
},
{
"x": 1321,
"y": 2277,
"width": 455,
"height": 65
},
{
"x": 1780,
"y": 2278,
"width": 505,
"height": 65
},
{
"x": 193,
"y": 2343,
"width": 584,
"height": 66
},
{
"x": 782,
"y": 2344,
"width": 1503,
"height": 67
},
{
"x": 193,
"y": 2412,
"width": 584,
"height": 65
},
{
"x": 781,
"y": 2413,
"width": 1504,
"height": 66
},
{
"x": 193,
"y": 2480,
"width": 584,
"height": 65
},
{
"x": 781,
"y": 2481,
"width": 1504,
"height": 66
}
]
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 278 KiB

View File

@ -0,0 +1,203 @@
{
"pages": [
{
"page": 0,
"pageWidth": 3508,
"pageHeight": 2481,
"cells": [
{
"x": 299,
"y": 761,
"width": 232,
"height": 354
},
{
"x": 533,
"y": 761,
"width": 235,
"height": 354
},
{
"x": 770,
"y": 761,
"width": 205,
"height": 354
},
{
"x": 977,
"y": 761,
"width": 211,
"height": 354
},
{
"x": 1190,
"y": 761,
"width": 425,
"height": 138
},
{
"x": 1617,
"y": 761,
"width": 195,
"height": 354
},
{
"x": 1814,
"y": 761,
"width": 168,
"height": 354
},
{
"x": 1984,
"y": 761,
"width": 184,
"height": 354
},
{
"x": 2170,
"y": 761,
"width": 191,
"height": 354
},
{
"x": 2363,
"y": 761,
"width": 274,
"height": 138
},
{
"x": 2639,
"y": 761,
"width": 159,
"height": 354
},
{
"x": 2800,
"y": 761,
"width": 466,
"height": 354
},
{
"x": 1190,
"y": 901,
"width": 141,
"height": 214
},
{
"x": 1333,
"y": 901,
"width": 123,
"height": 214
},
{
"x": 1458,
"y": 901,
"width": 157,
"height": 214
},
{
"x": 2363,
"y": 901,
"width": 130,
"height": 214
},
{
"x": 2495,
"y": 901,
"width": 142,
"height": 214
},
{
"x": 299,
"y": 1121,
"width": 232,
"height": 581
},
{
"x": 533,
"y": 1121,
"width": 235,
"height": 581
},
{
"x": 770,
"y": 1121,
"width": 205,
"height": 581
},
{
"x": 977,
"y": 1121,
"width": 211,
"height": 581
},
{
"x": 1190,
"y": 1121,
"width": 141,
"height": 581
},
{
"x": 1333,
"y": 1121,
"width": 123,
"height": 581
},
{
"x": 1458,
"y": 1121,
"width": 157,
"height": 581
},
{
"x": 1617,
"y": 1121,
"width": 195,
"height": 581
},
{
"x": 1814,
"y": 1121,
"width": 168,
"height": 581
},
{
"x": 1984,
"y": 1121,
"width": 184,
"height": 581
},
{
"x": 2170,
"y": 1121,
"width": 191,
"height": 581
},
{
"x": 2363,
"y": 1121,
"width": 130,
"height": 581
},
{
"x": 2495,
"y": 1121,
"width": 142,
"height": 581
},
{
"x": 2639,
"y": 1121,
"width": 159,
"height": 581
},
{
"x": 2800,
"y": 1121,
"width": 466,
"height": 581
}
]
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 345 KiB

View File

@ -0,0 +1,563 @@
{
"pages": [
{
"page": 0,
"pageWidth": 2481,
"pageHeight": 3508,
"cells": [
{
"x": 299,
"y": 706,
"width": 154,
"height": 411
},
{
"x": 455,
"y": 706,
"width": 239,
"height": 411
},
{
"x": 696,
"y": 706,
"width": 210,
"height": 411
},
{
"x": 908,
"y": 706,
"width": 818,
"height": 56
},
{
"x": 1728,
"y": 706,
"width": 376,
"height": 56
},
{
"x": 2106,
"y": 706,
"width": 138,
"height": 411
},
{
"x": 908,
"y": 764,
"width": 200,
"height": 353
},
{
"x": 1110,
"y": 764,
"width": 214,
"height": 353
},
{
"x": 1326,
"y": 764,
"width": 167,
"height": 353
},
{
"x": 1495,
"y": 764,
"width": 231,
"height": 353
},
{
"x": 1728,
"y": 764,
"width": 230,
"height": 353
},
{
"x": 1960,
"y": 764,
"width": 144,
"height": 353
},
{
"x": 299,
"y": 1123,
"width": 154,
"height": 283
},
{
"x": 455,
"y": 1123,
"width": 239,
"height": 283
},
{
"x": 696,
"y": 1123,
"width": 210,
"height": 283
},
{
"x": 908,
"y": 1123,
"width": 200,
"height": 283
},
{
"x": 1110,
"y": 1123,
"width": 214,
"height": 283
},
{
"x": 1326,
"y": 1123,
"width": 167,
"height": 283
},
{
"x": 1495,
"y": 1123,
"width": 231,
"height": 283
},
{
"x": 1728,
"y": 1123,
"width": 230,
"height": 283
},
{
"x": 1960,
"y": 1123,
"width": 144,
"height": 283
},
{
"x": 2106,
"y": 1123,
"width": 138,
"height": 283
},
{
"x": 299,
"y": 1408,
"width": 154,
"height": 284
},
{
"x": 455,
"y": 1408,
"width": 239,
"height": 284
},
{
"x": 696,
"y": 1408,
"width": 210,
"height": 284
},
{
"x": 908,
"y": 1408,
"width": 200,
"height": 284
},
{
"x": 1110,
"y": 1408,
"width": 214,
"height": 284
},
{
"x": 1326,
"y": 1408,
"width": 167,
"height": 284
},
{
"x": 1495,
"y": 1408,
"width": 231,
"height": 284
},
{
"x": 1728,
"y": 1408,
"width": 230,
"height": 284
},
{
"x": 1960,
"y": 1408,
"width": 144,
"height": 284
},
{
"x": 2106,
"y": 1408,
"width": 138,
"height": 284
},
{
"x": 299,
"y": 2090,
"width": 169,
"height": 211
},
{
"x": 470,
"y": 2090,
"width": 253,
"height": 211
},
{
"x": 725,
"y": 2090,
"width": 229,
"height": 211
},
{
"x": 956,
"y": 2090,
"width": 516,
"height": 57
},
{
"x": 1474,
"y": 2090,
"width": 496,
"height": 57
},
{
"x": 1972,
"y": 2090,
"width": 272,
"height": 211
},
{
"x": 956,
"y": 2149,
"width": 184,
"height": 152
},
{
"x": 1142,
"y": 2149,
"width": 158,
"height": 152
},
{
"x": 1302,
"y": 2149,
"width": 170,
"height": 152
},
{
"x": 1474,
"y": 2149,
"width": 262,
"height": 152
},
{
"x": 1738,
"y": 2149,
"width": 232,
"height": 152
},
{
"x": 299,
"y": 2303,
"width": 169,
"height": 56
},
{
"x": 470,
"y": 2303,
"width": 253,
"height": 56
},
{
"x": 725,
"y": 2303,
"width": 229,
"height": 56
},
{
"x": 956,
"y": 2303,
"width": 184,
"height": 56
},
{
"x": 1142,
"y": 2303,
"width": 158,
"height": 56
},
{
"x": 1302,
"y": 2303,
"width": 170,
"height": 56
},
{
"x": 1474,
"y": 2303,
"width": 262,
"height": 56
},
{
"x": 1738,
"y": 2303,
"width": 232,
"height": 56
},
{
"x": 1972,
"y": 2303,
"width": 272,
"height": 56
},
{
"x": 299,
"y": 2361,
"width": 169,
"height": 204
},
{
"x": 470,
"y": 2361,
"width": 253,
"height": 204
},
{
"x": 725,
"y": 2361,
"width": 229,
"height": 97
},
{
"x": 956,
"y": 2361,
"width": 184,
"height": 97
},
{
"x": 1142,
"y": 2361,
"width": 158,
"height": 204
},
{
"x": 1302,
"y": 2361,
"width": 170,
"height": 204
},
{
"x": 1474,
"y": 2361,
"width": 262,
"height": 97
},
{
"x": 1738,
"y": 2361,
"width": 232,
"height": 97
},
{
"x": 1972,
"y": 2361,
"width": 272,
"height": 204
},
{
"x": 725,
"y": 2460,
"width": 229,
"height": 105
},
{
"x": 956,
"y": 2460,
"width": 184,
"height": 105
},
{
"x": 1474,
"y": 2460,
"width": 262,
"height": 105
},
{
"x": 1738,
"y": 2460,
"width": 232,
"height": 105
},
{
"x": 299,
"y": 2567,
"width": 169,
"height": 205
},
{
"x": 470,
"y": 2567,
"width": 253,
"height": 205
},
{
"x": 725,
"y": 2567,
"width": 229,
"height": 205
},
{
"x": 956,
"y": 2567,
"width": 184,
"height": 205
},
{
"x": 1142,
"y": 2567,
"width": 158,
"height": 205
},
{
"x": 1302,
"y": 2567,
"width": 170,
"height": 205
},
{
"x": 1474,
"y": 2567,
"width": 262,
"height": 205
},
{
"x": 1738,
"y": 2567,
"width": 232,
"height": 205
},
{
"x": 1972,
"y": 2567,
"width": 272,
"height": 205
},
{
"x": 299,
"y": 2774,
"width": 169,
"height": 56
},
{
"x": 470,
"y": 2774,
"width": 253,
"height": 56
},
{
"x": 725,
"y": 2774,
"width": 229,
"height": 56
},
{
"x": 956,
"y": 2774,
"width": 184,
"height": 56
},
{
"x": 1142,
"y": 2774,
"width": 158,
"height": 56
},
{
"x": 1302,
"y": 2774,
"width": 170,
"height": 56
},
{
"x": 1474,
"y": 2774,
"width": 262,
"height": 56
},
{
"x": 1738,
"y": 2774,
"width": 232,
"height": 56
},
{
"x": 1972,
"y": 2774,
"width": 272,
"height": 56
},
{
"x": 299,
"y": 2832,
"width": 169,
"height": 205
},
{
"x": 470,
"y": 2832,
"width": 253,
"height": 205
},
{
"x": 725,
"y": 2832,
"width": 229,
"height": 205
},
{
"x": 956,
"y": 2832,
"width": 184,
"height": 205
},
{
"x": 1142,
"y": 2832,
"width": 158,
"height": 205
},
{
"x": 1302,
"y": 2832,
"width": 170,
"height": 205
},
{
"x": 1474,
"y": 2832,
"width": 262,
"height": 205
},
{
"x": 1738,
"y": 2832,
"width": 232,
"height": 205
},
{
"x": 1972,
"y": 2832,
"width": 272,
"height": 205
}
]
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 557 KiB

View File

@ -0,0 +1,53 @@
{
"pages": [
{
"page": 0,
"pageWidth": 2480,
"pageHeight": 3509,
"cells": [
{
"x": 494,
"y": 960,
"width": 562,
"height": 453
},
{
"x": 1059,
"y": 962,
"width": 1065,
"height": 224
},
{
"x": 1060,
"y": 1190,
"width": 1066,
"height": 225
},
{
"x": 500,
"y": 1419,
"width": 559,
"height": 521
},
{
"x": 1060,
"y": 1420,
"width": 1070,
"height": 521
},
{
"x": 506,
"y": 1945,
"width": 553,
"height": 222
},
{
"x": 1063,
"y": 1946,
"width": 1070,
"height": 223
}
]
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

View File

@ -0,0 +1,29 @@
{
"pages": [
{
"page": 0,
"pageWidth": 2471,
"pageHeight": 3505,
"cells": [
{
"x": 572,
"y": 725,
"width": 451,
"height": 1785
},
{
"x": 1025,
"y": 725,
"width": 505,
"height": 1785
},
{
"x": 1533,
"y": 724,
"width": 454,
"height": 1786
}
]
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

View File

@ -0,0 +1,179 @@
{
"pages": [
{
"page": 0,
"pageWidth": 2471,
"pageHeight": 3505,
"cells": [
{
"x": 1292,
"y": 1009,
"width": 264,
"height": 132
},
{
"x": 538,
"y": 1015,
"width": 254,
"height": 124
},
{
"x": 797,
"y": 1016,
"width": 253,
"height": 124
},
{
"x": 1056,
"y": 1017,
"width": 230,
"height": 123
},
{
"x": 538,
"y": 1144,
"width": 253,
"height": 81
},
{
"x": 797,
"y": 1145,
"width": 253,
"height": 82
},
{
"x": 1056,
"y": 1146,
"width": 230,
"height": 81
},
{
"x": 1292,
"y": 1146,
"width": 257,
"height": 81
},
{
"x": 538,
"y": 1231,
"width": 253,
"height": 39
},
{
"x": 797,
"y": 1232,
"width": 253,
"height": 39
},
{
"x": 1055,
"y": 1233,
"width": 230,
"height": 38
},
{
"x": 1291,
"y": 1233,
"width": 258,
"height": 38
},
{
"x": 538,
"y": 1277,
"width": 253,
"height": 80
},
{
"x": 797,
"y": 1277,
"width": 252,
"height": 80
},
{
"x": 1055,
"y": 1278,
"width": 230,
"height": 80
},
{
"x": 1291,
"y": 1278,
"width": 258,
"height": 80
},
{
"x": 538,
"y": 1362,
"width": 253,
"height": 40
},
{
"x": 797,
"y": 1363,
"width": 253,
"height": 40
},
{
"x": 1055,
"y": 1363,
"width": 230,
"height": 40
},
{
"x": 1291,
"y": 1363,
"width": 258,
"height": 40
},
{
"x": 538,
"y": 1407,
"width": 253,
"height": 82
},
{
"x": 797,
"y": 1408,
"width": 253,
"height": 81
},
{
"x": 1055,
"y": 1408,
"width": 231,
"height": 82
},
{
"x": 1291,
"y": 1409,
"width": 258,
"height": 81
},
{
"x": 538,
"y": 1494,
"width": 254,
"height": 209
},
{
"x": 797,
"y": 1494,
"width": 253,
"height": 209
},
{
"x": 1055,
"y": 1495,
"width": 231,
"height": 209
},
{
"x": 1291,
"y": 1495,
"width": 265,
"height": 214
}
]
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

View File

@ -0,0 +1,335 @@
{
"pages": [
{
"page": 0,
"pageWidth": 2481,
"pageHeight": 3506,
"cells": [
{
"x": 1913,
"y": 602,
"width": 56,
"height": 670
},
{
"x": 1973,
"y": 602,
"width": 56,
"height": 670
},
{
"x": 2032,
"y": 603,
"width": 57,
"height": 669
},
{
"x": 605,
"y": 647,
"width": 389,
"height": 430
},
{
"x": 997,
"y": 646,
"width": 210,
"height": 432
},
{
"x": 1211,
"y": 647,
"width": 210,
"height": 432
},
{
"x": 1425,
"y": 647,
"width": 66,
"height": 432
},
{
"x": 1496,
"y": 647,
"width": 65,
"height": 432
},
{
"x": 605,
"y": 1083,
"width": 388,
"height": 350
},
{
"x": 997,
"y": 1083,
"width": 209,
"height": 352
},
{
"x": 1210,
"y": 1083,
"width": 211,
"height": 352
},
{
"x": 1424,
"y": 1083,
"width": 67,
"height": 352
},
{
"x": 1495,
"y": 1083,
"width": 66,
"height": 352
},
{
"x": 1912,
"y": 1275,
"width": 57,
"height": 669
},
{
"x": 1972,
"y": 1275,
"width": 57,
"height": 670
},
{
"x": 2032,
"y": 1276,
"width": 57,
"height": 669
},
{
"x": 604,
"y": 1439,
"width": 389,
"height": 498
},
{
"x": 996,
"y": 1439,
"width": 67,
"height": 499
},
{
"x": 1067,
"y": 1439,
"width": 67,
"height": 499
},
{
"x": 1138,
"y": 1439,
"width": 68,
"height": 500
},
{
"x": 1210,
"y": 1439,
"width": 67,
"height": 500
},
{
"x": 1280,
"y": 1439,
"width": 67,
"height": 500
},
{
"x": 1351,
"y": 1439,
"width": 69,
"height": 500
},
{
"x": 1424,
"y": 1439,
"width": 67,
"height": 500
},
{
"x": 1495,
"y": 1439,
"width": 65,
"height": 500
},
{
"x": 603,
"y": 1943,
"width": 389,
"height": 291
},
{
"x": 996,
"y": 1943,
"width": 209,
"height": 292
},
{
"x": 1209,
"y": 1943,
"width": 210,
"height": 292
},
{
"x": 1424,
"y": 1943,
"width": 67,
"height": 292
},
{
"x": 1494,
"y": 1943,
"width": 66,
"height": 293
},
{
"x": 1911,
"y": 1948,
"width": 56,
"height": 669
},
{
"x": 1971,
"y": 1948,
"width": 56,
"height": 669
},
{
"x": 2030,
"y": 1949,
"width": 57,
"height": 669
},
{
"x": 603,
"y": 2239,
"width": 388,
"height": 304
},
{
"x": 995,
"y": 2239,
"width": 67,
"height": 305
},
{
"x": 1066,
"y": 2239,
"width": 67,
"height": 306
},
{
"x": 1137,
"y": 2239,
"width": 68,
"height": 306
},
{
"x": 1209,
"y": 2239,
"width": 66,
"height": 306
},
{
"x": 1280,
"y": 2240,
"width": 67,
"height": 305
},
{
"x": 1351,
"y": 2240,
"width": 68,
"height": 305
},
{
"x": 1423,
"y": 2240,
"width": 67,
"height": 305
},
{
"x": 1494,
"y": 2240,
"width": 65,
"height": 305
},
{
"x": 601,
"y": 2548,
"width": 390,
"height": 783
},
{
"x": 995,
"y": 2548,
"width": 66,
"height": 783
},
{
"x": 1065,
"y": 2548,
"width": 68,
"height": 783
},
{
"x": 1137,
"y": 2549,
"width": 68,
"height": 782
},
{
"x": 1209,
"y": 2549,
"width": 66,
"height": 782
},
{
"x": 1279,
"y": 2549,
"width": 67,
"height": 782
},
{
"x": 1350,
"y": 2549,
"width": 69,
"height": 782
},
{
"x": 1423,
"y": 2549,
"width": 67,
"height": 782
},
{
"x": 1493,
"y": 2549,
"width": 66,
"height": 782
},
{
"x": 1910,
"y": 2622,
"width": 57,
"height": 666
},
{
"x": 1970,
"y": 2622,
"width": 57,
"height": 667
},
{
"x": 2030,
"y": 2622,
"width": 56,
"height": 667
}
]
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 334 KiB

View File

@ -1,7 +1,7 @@
from os.path import join from os.path import join
import json import json
from cv_analysis.table_parsing import parse_table from cv_analysis.table_parsing import parse_tables
from cv_analysis.locations import TEST_DATA_DIR from cv_analysis.locations import TEST_DATA_DIR
from cv_analysis.test.config import TEST_CONFIG from cv_analysis.test.config import TEST_CONFIG
from cv_analysis.utils.test_metrics import compute_document_score from cv_analysis.utils.test_metrics import compute_document_score
@ -9,13 +9,37 @@ from cv_analysis.utils.preprocessing import open_pdf
def test_table_parsing(): def test_table_parsing():
img_path = join(TEST_DATA_DIR, "table.jpg") for i in range(1, 11):
json_path = join(TEST_DATA_DIR, "table.json")
pages = open_pdf(img_path)[0] img_path = join(TEST_DATA_DIR, f"test{i}.png")
result = {} json_path = join(TEST_DATA_DIR, f"test{i}.json")
pages = open_pdf(img_path)
result = {"pages": []}
for i, page in enumerate(pages): for i, page in enumerate(pages):
result.update({str(i): parse_table(page)}) result["pages"].append({"page": str(i), "cells": [x.json_xywh() for x in parse_tables(page)]})
with open(json_path) as f: with open(json_path) as f:
annotation = json.load(f) annotation = json.load(f)
score = compute_document_score(result, annotation) score = compute_document_score(result, annotation)
assert round(score, 3) >= TEST_CONFIG.table_score_threshold
"""
def test_table_parsing():
img_path = join(TEST_DATA_DIR, "table.jpg")
json_path = join(TEST_DATA_DIR, "table.json")
pages = open_pdf(img_path)
result = {"pages": []}
for i, page in enumerate(pages):
result["pages"].append({"page": str(i), "cells": [x.xywh() for x in parse_tables(page)]})
with open(json_path) as f:
annotation = json.load(f)
score = compute_document_score(result, annotation)
assert score >= TEST_CONFIG.table_score_threshold assert score >= TEST_CONFIG.table_score_threshold
"""

View File

@ -3,7 +3,7 @@ import cv2
from cv_analysis.utils import copy_and_normalize_channels from cv_analysis.utils import copy_and_normalize_channels
def draw_contours(image, contours): def draw_contours(image, contours, color=None, annotate=False):
image = copy_and_normalize_channels(image) image = copy_and_normalize_channels(image)
@ -25,7 +25,6 @@ def draw_rectangles(image, rectangles, color=None, annotate=False):
for rect in rectangles: for rect in rectangles:
x, y, w, h = rect x, y, w, h = rect
cv2.rectangle(image, (x, y), (x + w, y + h), color, 2) cv2.rectangle(image, (x, y), (x + w, y + h), color, 2)
if annotate: if annotate:
annotate_rect(x, y, w, h) annotate_rect(x, y, w, h)

View File

@ -3,29 +3,29 @@ import pdf2image
from PIL import Image from PIL import Image
import cv2 import cv2
from cv_analysis.utils.deskew import deskew
def preprocess_pdf_image(page): def preprocess_pdf_image(page):
if len(page.shape) > 2: if len(page.shape) > 2:
page = cv2.cvtColor(page, cv2.COLOR_BGR2GRAY) page = cv2.cvtColor(page, cv2.COLOR_BGR2GRAY)
page = cv2.fastNlMeansDenoising(page, h=3) page = cv2.fastNlMeansDenoising(page, h=3)
return deskew(page) return page
def open_pdf(pdf, first_page=0, last_page=None): def open_pdf(pdf, first_page=0, last_page=None):
first_page += 1 first_page += 1
last_page = None if last_page is None else last_page + 1 last_page = None if last_page is None else last_page + 1
if type(pdf) == str: if type(pdf) == str:
if pdf.endswith(".jpg") or pdf.endswith(".png"): if pdf.lower().endswith((".png", ".jpg", ".jpeg")):
pages = [Image.open(pdf)] pages = [Image.open(pdf)]
# assume pdf as default file type for a path argument else: # assume pdf as default file type for a path argument
else:
pages = pdf2image.convert_from_path(pdf, first_page=first_page, last_page=last_page) pages = pdf2image.convert_from_path(pdf, first_page=first_page, last_page=last_page)
elif type(pdf) == bytes: elif type(pdf) == bytes:
pages = pdf2image.convert_from_bytes(pdf, first_page=first_page, last_page=last_page) pages = pdf2image.convert_from_bytes(pdf, first_page=first_page, last_page=last_page)
elif type(pdf) in {list, ndarray}: elif type(pdf) in {list, ndarray}:
return pdf return pdf
pages = [preprocess_pdf_image(array(p)) for p in pages] pages = [preprocess_pdf_image(array(p)) for p in pages]
pages, angles = list(zip(*pages))
return pages, angles return pages

View File

@ -0,0 +1,70 @@
from json import dumps
class Rectangle:
def __init__(self, x1=None, y1=None, w=None, h=None, x2=None, y2=None, indent=4, format="xywh"):
try:
self.x1 = x1
self.y1 = y1
self.w = w if w else x2 - x1
self.h = h if h else y2 - y1
self.x2 = x2 if x2 else x1 + w
self.y2 = y2 if y2 else y1 + h
assert (self.x1 + self.w) == self.x2
assert (self.y1 + self.h) == self.y2
self.indent = indent
self.format = format
except:
raise Exception("x1, y1, (w|x2), and (h|y2) must be defined.")
def json_xywh(self):
return {"x": self.x1, "y": self.y1, "width": self.w, "height": self.h}
def json_xyxy(self):
return {"x1": self.x1, "y1": self.y1, "x2": self.x2, "y2": self.y2}
def json_full(self):
return {"x1": self.x1, "y1": self.y1, "x2": self.x2, "y2": self.y2, "width": self.w, "height": self.h}
def json(self):
json_func = {"xywh": self.json_xywh, "xyxy": self.json_xyxy}.get(self.format, self.json_full)
return json_func()
def xyxy(self):
return self.x1, self.y1, self.x2, self.y2
def xywh(self):
return self.x1, self.y1, self.w, self.h
@classmethod
def from_xyxy(cls, xyxy_tuple):
x1, y1, x2, y2 = xyxy_tuple
return cls(x1=x1, y1=y1, x2=x2, y2=y2)
@classmethod
def from_xywh(cls, xywh_tuple):
x, y, w, h = xywh_tuple
return cls(x1=x, y1=y, w=w, h=h)
def __str__(self):
return dumps(self.json(), indent=self.indent)
def __repr__(self):
return str(self.json())
def __iter__(self):
return list(self.json().values()).__iter__()
"""
boxes = [[30,40,5,6],[56,78,23,19],[5,100,45,35],[34,34,67,67]]
rectangles = list(map(Rectangle.from_xywh, boxes))
rectangles
r = rectangles[1]
"""
class Contour:
def __init__(self):
pass

View File

@ -1,12 +1,41 @@
import numpy as np import numpy as np
from cv_analysis.utils.structures import Rectangle
def compute_iou_from_boxes(box1, box2): def xyxy_from_object(box_object):
try:
x1, y1, x2, y2 = box_object.xyxy()
except:
try:
x1 = box_object["x"]
y1 = box_object["y"]
x2 = x1 + box_object["width"]
y2 = y1 + box_object["height"]
except:
x1, y1, x2, y2 = box_object
return x1, y1, x2, y2
def xywh_from_object(box_object):
try:
x, y, w, h = box_object.xywh()
except:
try:
x = box_object["x"]
y = box_object["y"]
w = box_object["width"]
h = box_object["height"]
except:
x, y, w, h = box_object
return x, y, w, h
def compute_iou_from_boxes(box1: Rectangle, box2: list):
""" """
Each box of the form (x1, y1, delx, dely) Each box of the form (x1, y1, delx, dely)
""" """
ax1, ay1, aw, ah = box1 ax1, ay1, aw, ah = xywh_from_object(box1)
bx1, by1, bw, bh = box2 bx1, by1, bw, bh = xywh_from_object(box2)
ax2, ay2, bx2, by2 = ax1 + aw, ay1 + ah, bx1 + bw, by1 + bh ax2, ay2, bx2, by2 = ax1 + aw, ay1 + ah, bx1 + bw, by1 + bh
if (ax1 > bx2) or (bx1 > ax2) or (ay1 > by2) or (by1 > ay2): if (ax1 > bx2) or (bx1 > ax2) or (ay1 > by2) or (by1 > ay2):
return 0 return 0
@ -40,15 +69,15 @@ def compute_page_iou(results_box_list, gt_box_list):
def compute_document_score(results_dict, annotation_dict): def compute_document_score(results_dict, annotation_dict):
page_weights = np.array([len(v) for v in annotation_dict.values()])
page_weights = np.array([len(page["cells"]) for page in annotation_dict["pages"]])
page_weights = page_weights / sum(page_weights) page_weights = page_weights / sum(page_weights)
scores = [] scores = []
for key in annotation_dict: for i in range(len(annotation_dict["pages"])):
scores.append(compute_page_iou(results_dict[key], annotation_dict[key])) scores.append(compute_page_iou(results_dict["pages"][i]["cells"], annotation_dict["pages"][i]["cells"]))
scores = np.array(scores) scores = np.array(scores)
doc_score = np.average(scores, weights=page_weights) doc_score = np.average(scores, weights=page_weights)
return doc_score return doc_score
def compute_document_score_tables(results_dict, annotation_dict):
pass

View File

@ -10,13 +10,30 @@ class VisualLogger:
if not os.path.exists(self.output_folder): if not os.path.exists(self.output_folder):
os.mkdir(self.output_folder) os.mkdir(self.output_folder)
def debug(self, img, name): def _save(self, img, name):
if self.level_is_debug():
output_path = os.path.join(self.output_folder, name) output_path = os.path.join(self.output_folder, name)
save_mpl(img, output_path) save_mpl(img, output_path)
def level_is_debug(self): def info(self, img, name):
return self.level == "DEBUG" if self._level_is_info():
self._save(img, name)
def debug(self, img, name):
if self._level_is_debug():
self._save(img, name)
def all(self, img, name):
if self._level_is_debug():
self._save(img, name)
def _level_is_info(self):
return self.level in {"INFO", "DEBUG", "ALL"}
def _level_is_debug(self):
return self.level in {"DEBUG", "ALL"}
def _level_is_all(self):
return self.level == "ALL"
vizlogger = VisualLogger(CONFIG.visual_logging.level, CONFIG.visual_logging.output_folder) vizlogger = VisualLogger(CONFIG.visual_logging.level, CONFIG.visual_logging.output_folder)

View File

@ -1,30 +1,48 @@
"""
Usage:
python scripts/annotate.py /home/iriley/Documents/pdf/scanned/10.pdf 5 --type table --show
python scripts/annotate.py /home/iriley/Documents/pdf/scanned/10.pdf 5 --type redaction --show
python scripts/annotate.py /home/iriley/Documents/pdf/scanned/10.pdf 5 --type layout --show
python scripts/annotate.py /home/iriley/Documents/pdf/scanned/10.pdf 5 --type figure --show
"""
import argparse import argparse
from cv_analysis.table_parsing import annotate_tables_in_pdf from cv_analysis.utils.display import show_mpl
from cv_analysis.redaction_detection import annotate_redactions_in_pdf from cv_analysis.utils.draw import draw_contours, draw_rectangles
from cv_analysis.layout_parsing import annotate_layout_in_pdf from cv_analysis.utils.preprocessing import open_pdf
from cv_analysis.figure_detection import detect_figures_in_pdf from cv_analysis.utils.visual_logging import vizlogger
def parse_args(): def parse_args():
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument("pdf_path") parser.add_argument("pdf_path")
parser.add_argument("page_index", type=int) parser.add_argument("--page_index", type=int, default=0)
parser.add_argument("--type", choices=["table", "redaction", "layout", "figure", "figures"]) parser.add_argument("--type", choices=["table", "redaction", "layout", "figure"], default="table")
parser.add_argument("--show", action="store_true", default=False) parser.add_argument("--show", action="store_true", default=False)
args = parser.parse_args() args = parser.parse_args()
return args return args
def annotate_page(page_image, analysis_function, drawing_function, name="tmp.png", show=True):
result = analysis_function(page_image)
page_image = drawing_function(page_image, result)
vizlogger.debug(page_image, "redactions05_output.png")
show_mpl(page_image)
if __name__ == "__main__": if __name__ == "__main__":
args = parse_args() args = parse_args()
page = open_pdf(args.pdf_path, first_page=args.page_index, last_page=args.page_index)[0]
name = f"{args.type}_final_result.png"
draw = draw_rectangles
if args.type == "table": if args.type == "table":
annotate_tables_in_pdf(args.pdf_path, page_index=args.page_index, show=args.show) from cv_analysis.table_parsing import parse_tables as analyze
elif args.type == "redaction": elif args.type == "redaction":
annotate_redactions_in_pdf(args.pdf_path, page_index=args.page_index, show=args.show) from cv_analysis.redaction_detection import find_redactions as analyze
draw = draw_contours
elif args.type == "layout": elif args.type == "layout":
annotate_layout_in_pdf(args.pdf_path, page_index=args.page_index, show=args.show) from cv_analysis.layout_parsing import parse_layout as analyze
elif args.type == "figure": elif args.type == "figure":
detect_figures_in_pdf(args.pdf_path, page_index=args.page_index, show=True) from cv_analysis.figure_detection import detect_figures as analyze
annotate_page(page, analyze, draw, name=name, show=args.show)

View File

@ -7,7 +7,7 @@ from PIL import Image
from cv_analysis.utils.deskew import deskew_histbased # , deskew_linebased from cv_analysis.utils.deskew import deskew_histbased # , deskew_linebased
from cv_analysis.utils.display import show_mpl from cv_analysis.utils.display import show_mpl
from cv_analysis.utils.draw import draw_stats from cv_analysis.utils.draw import draw_stats
from cv_analysis.table_parsing import parse_table from cv_analysis.table_parsing import parse_tables
def parse_args(): def parse_args():
@ -37,10 +37,10 @@ if __name__ == "__main__":
page_corr_ = Image.fromarray(page_corr).convert("RGB") page_corr_ = Image.fromarray(page_corr).convert("RGB")
page_corr_.save(args.save_path.replace(".pdf", "_corrected.pdf")) page_corr_.save(args.save_path.replace(".pdf", "_corrected.pdf"))
# annotate_tables_in_pdf(args.pdf_path, page_index=args.page_index) # annotate_tables_in_pdf(args.pdf_path, page_index=args.page_index)
stats = parse_table(page) stats = parse_tables(page)
page = draw_stats(page, stats) page = draw_stats(page, stats)
show_mpl(page) show_mpl(page)
stats_corr = parse_table(page_corr) stats_corr = parse_tables(page_corr)
page_corr = draw_stats(page_corr, stats_corr) page_corr = draw_stats(page_corr, stats_corr)
show_mpl(page_corr) show_mpl(page_corr)
if args.save_path: if args.save_path:

View File

@ -8,12 +8,14 @@ from prometheus_flask_exporter import PrometheusMetrics
from waitress import serve from waitress import serve
from cv_analysis.utils import npconvert from cv_analysis.utils import npconvert
from cv_analysis.table_parsing import parse_table from cv_analysis.table_parsing import parse_tables
from cv_analysis.redaction_detection import find_redactions from cv_analysis.redaction_detection import find_redactions
from cv_analysis.layout_parsing import parse_layout from cv_analysis.layout_parsing import parse_layout
from cv_analysis.figure_detection import detect_figures from cv_analysis.figure_detection import detect_figures
from cv_analysis.utils.logging import logger from cv_analysis.utils.logging import logger
from cv_analysis.utils.post_processing import Rectangle
from cv_analysis.utils.preprocessing import open_pdf from cv_analysis.utils.preprocessing import open_pdf
from cv_analysis.utils.structures import Rectangle
from cv_analysis.config import CONFIG from cv_analysis.config import CONFIG
@ -42,7 +44,7 @@ def main():
@metrics.summary("tables_request_time_seconds", "Time spent processing tables request") @metrics.summary("tables_request_time_seconds", "Time spent processing tables request")
def get_tables(): def get_tables():
start_monitoring() start_monitoring()
tables = annotate(parse_table) tables = annotate(parse_tables)
return tables return tables
@app.route("/redactions", methods=["POST"]) @app.route("/redactions", methods=["POST"])
@ -86,7 +88,7 @@ def make_annotations(pdf, annotation_function):
results = [] results = []
for i, page in enumerate(pdf): for i, page in enumerate(pdf):
boxes = annotation_function(page) boxes = annotation_function(page)
cells = [{"x": x, "y": y, "width": w, "height": h} for x, y, w, h in boxes] cells = list(map(lambda x: x.json_xywh(), boxes))
results.append({"page": i, "pageWidth": page.shape[1], "pageHeight": page.shape[0], "cells": cells}) results.append({"page": i, "pageWidth": page.shape[1], "pageHeight": page.shape[0], "cells": cells})
output_dict = {"pages": results} output_dict = {"pages": results}
return jsonify(json.dumps(output_dict, default=npconvert)) return jsonify(json.dumps(output_dict, default=npconvert))
@ -101,10 +103,8 @@ def annotate(annotation_function):
data = request.data data = request.data
logger.info(f"Received data.") logger.info(f"Received data.")
logger.info(f"Processing data.") logger.info(f"Processing data.")
pdf, angles = open_pdf(data) pdf = open_pdf(data)
annotations = make_annotations(pdf, annotation_function) annotations = make_annotations(pdf, annotation_function)
# if CONFIG.deskew.function != "identity":
# annotations.update({"deskew_angles": angles})
return annotations return annotations
try: try: