kleverocr / src /markdown.py
pmkhanh7890's picture
fix gradio app
555cf98
"""
Author: Khanh Phan
Date: 2023-11-01
"""
from pathlib import Path
import numpy as np
import pandas as pd
# from mdutils import Html
from mdutils.mdutils import MdUtils
from src.settings import (
MAX_CHAR,
TEXT_SCALE,
)
class Markdown:
def __init__(self, result: list = None, image: np.array = None) -> None:
"""
Put text into image
args:
result(list): recognition results
image(array): RGB image
"""
self.scale = TEXT_SCALE
"""
self.im_width = 1475
self.im_height = 1029
self.res = pd.read_csv("results.csv", sep='\t', encoding='utf-8')
"""
self.im_width, self.im_height = image.size # grayscale image
res = []
for line in result:
box_h = get_text_height(line)
row = (
box_h,
line[0][0][1],
line[0][0][0],
line[0][3][1],
line[0][1][0],
line[1][0],
line[1][1],
"left",
False,
)
res.append(row)
self.res = pd.DataFrame(
res,
columns=[
"box_h", # height of bbox
"top", # get top from top-left
"left", # get left from top-left
"bot", # get bot from bot-left
"right", # get right from top-right
"text", # recognized text
"score",
"align", # left. center, right
"ignore",
],
)
# self.res.to_csv("results.csv", sep="\t", encoding="utf-8")
def write(self, out_path: Path = Path(".")) -> None:
"""
Write markdown text to file
args:
out_path(Path): path to write md file
"""
self.check_same_line()
# TODO: add space between line
out_path = Path(out_path)
if not out_path.suffix == ".md":
out_path = out_path + ".out.md"
mdFile = MdUtils(
file_name=str(out_path),
# title="Markdown File Example",
)
for _, row in self.res.iterrows():
if row["ignore"]:
continue
align = self.edit_align(row["left"], row["right"])
if align == "right":
space = MAX_CHAR - len(row["text"])
row["text"] = " " * space + row["text"]
mdFile.new_paragraph(f"{row['text']}", align=align)
mdFile.create_md_file()
file = open(out_path, encoding="utf-8")
md = file.read()
file.close()
return md
def sort_text(self) -> None:
"""
Sort strings by their top coordinate (sort vertically)
args:
res(df): results
"""
self.res = self.res.sort_values("top")
self.res = self.res.reset_index(drop=True)
def check_same_line(self) -> None:
"""
Check if two strings can be connetted in the same line
"""
n = len(self.res)
self.same_line_pair = []
for i in range(n):
if self.res.iloc[i]["ignore"] is True:
continue
for j in range(min(i + 1, n), min(i + 3, n)):
if self.res.iloc[j]["ignore"] is True:
continue
if check_overlap(
self.res.iloc[i]["bot"],
self.res.iloc[i]["top"],
self.res.iloc[j]["bot"],
self.res.iloc[j]["top"],
):
if (
self.res.iloc[j]["left"] - self.res.iloc[i]["right"]
> -self.im_width / 100
):
space = calculate_space(
self.res.iloc[i]["box_h"],
self.res.iloc[i]["right"],
self.res.iloc[j]["left"],
)
self.res.at[i, "text"] = (
self.res.iloc[i]["text"]
+ " " * space
+ self.res.iloc[j]["text"]
)
self.res.at[j, "ignore"] = True
self.res.at[i, "right"] = self.res.iloc[j]["right"]
elif (
self.res.iloc[i]["left"] - self.res.iloc[j]["right"]
> -self.im_width / 100
):
space = calculate_space(
self.res.iloc[j]["box_h"],
self.res.iloc[j]["right"],
self.res.iloc[i]["left"],
)
self.res.at[j, "text"] = (
self.res.iloc[j]["text"]
+ " " * space
+ self.res.iloc[i]["text"]
)
self.res.at[i, "ignore"] = True
self.res.at[j, "right"] = self.res.iloc[i]["right"]
def edit_align(self, left: int, right: int) -> str:
"""
Find the best alignment from left & right margin
args:
left(int): left margin
right(int): right margin
return(text):
alignment
"""
align = "left"
left_margin = left
right_margin = self.im_width - right
if abs(left_margin + right_margin) > self.im_width * 2 / 3:
align = "center"
# in case of paragraph, it should be revise as left or right
if self.im_width / 2 < right_margin:
align = "left"
if self.im_width / 2 < left_margin:
align = "right"
return align
def calculate_space(height1: int, right1: int, left2: int) -> int:
"""
Calcualte spaces between 2 strings
args:
height1(int): height coord of string 1
right1(int): right coord of string 1
left1(int): left coord of string 2
return(int):
number of spaces
"""
distance = abs(left2 - right1)
spaces = distance / height1
return round(spaces)
def check_overlap(max1: int, min1: int, max2: int, min2: int) -> bool:
"""
Calcualte spaces between 2 strings
args:
max1(int): right coord of string 1
min1(int): left coord of string 1
max1(int): right coord of string 1
min1(int): left coord of string 1
return(bool):
Same line or not
"""
overlap = max(0, min(max1, max2) - max(min1, min2))
if overlap / (max1 - min1) > 0.5 or overlap / (max2 - min2) > 0.5:
return True
else:
return False
def get_text_height(line) -> int:
"""
Write markdown text to file
args:
line(array): recognition result
return(int):
height of bbox in pixels
"""
top = int(min(line[0][0][1], line[0][1][1]))
bottom = int(max(line[0][2][1], line[0][3][1]))
return bottom - top
if __name__ == "__main__":
md = Markdown()
md.write()