CoolFace
Apppublic

EuroPython2022/latr-vqa

sourceHugging Faceunknownupdated 4y agoView on Hugging Face
2likes
dataset.py151 linesDownload Raw Back to root
1import os2import json3import numpy as np4import pytesseract5from PIL import Image, ImageDraw6 7PAD_TOKEN_BOX = [0, 0, 0, 0]8max_seq_len = 5129 10## Function: 111## Purpose: Resize and align the bounding box for the different sized image12 13def resize_align_bbox(bbox, orig_w, orig_h, target_w, target_h):14    x_scale = target_w / orig_w15    y_scale = target_h / orig_h16    orig_left, orig_top, orig_right, orig_bottom = bbox17    x = int(np.round(orig_left * x_scale))18    y = int(np.round(orig_top * y_scale))19    xmax = int(np.round(orig_right * x_scale))20    ymax = int(np.round(orig_bottom * y_scale))21    return [x, y, xmax, ymax]22 23## Function: 224## Purpose: Reading the json file from the path and return the dictionary25 26def load_json_file(file_path):27  with open(file_path, 'r') as f:28    data = json.load(f)29  return data30 31## Function: 332## Purpose: Getting the address of specific file type, eg: .pdf, .tif, so and so33 34def get_specific_file(path, last_entry = 'tif'):35  base_path = path36  for i in os.listdir(path):37    if i.endswith(last_entry):38      return os.path.join(base_path, i)39 40  return '-1'41 42 43## Function: 444 45 46def get_tokens_with_boxes(unnormalized_word_boxes, list_of_words, tokenizer, pad_token_id = 0, pad_token_box = [0, 0, 0, 0], max_seq_len = 512):47    48    '''49    This function returns two items:50    1. unnormalized_token_boxes -> a list of len = max_seq_len, containing the boxes corresponding to the tokenized words, 51                                    one box might repeat as per the tokenization procedure52    2. tokenized_words -> tokenized words corresponding to the tokenizer and the list_of_words53    '''54 55    assert len(unnormalized_word_boxes) == len(list_of_words), "Bounding box length!= total words length"56    57    length_of_box = len(unnormalized_word_boxes)58    unnormalized_token_boxes = []59    tokenized_words = []60 61    for box, word in zip(unnormalized_word_boxes, list_of_words):62      current_tokens = tokenizer(word, add_special_tokens = False).input_ids63      unnormalized_token_boxes.extend([box]*len(current_tokens))64      tokenized_words.extend(current_tokens)65 66    if len(unnormalized_token_boxes)<max_seq_len:67        unnormalized_token_boxes.extend([pad_token_box] * (max_seq_len-len(unnormalized_token_boxes)))68        69    if len(tokenized_words)< max_seq_len:70        tokenized_words.extend([pad_token_id]* (max_seq_len-len(tokenized_words)))71        72    return unnormalized_token_boxes[:max_seq_len], tokenized_words[:max_seq_len]73 74## Function: 575## Function, which would only be used when the below function is used76 77def get_topleft_bottomright_coordinates(df_row):78    left, top, width, height = df_row["left"], df_row["top"], df_row["width"], df_row["height"]79    return [left, top, left + width, top + height]80 81## Function: 682## If the OCR is not provided, this function would help in extracting OCR83 84 85def apply_ocr(tif_path):86    """87    Returns words and its bounding boxes from an image88    """89    img = Image.open(tif_path).convert("RGB")90 91    ocr_df = pytesseract.image_to_data(img, output_type="data.frame")92    ocr_df = ocr_df.dropna().reset_index(drop=True)93    float_cols = ocr_df.select_dtypes("float").columns94    ocr_df[float_cols] = ocr_df[float_cols].round(0).astype(int)95    ocr_df = ocr_df.replace(r"^\s*$", np.nan, regex=True)96    ocr_df = ocr_df.dropna().reset_index(drop=True)97    words = list(ocr_df.text.apply(lambda x: str(x).strip()))98    actual_bboxes = ocr_df.apply(get_topleft_bottomright_coordinates, axis=1).values.tolist()99 100    # add as extra columns101    assert len(words) == len(actual_bboxes)102    return {"words": words, "bbox": actual_bboxes}103 104 105## Function: 7106## Merging all the above functions, for the purpose of extracting the image, bounding box and the tokens (sentence wise)107 108 109def create_features(110    image_path,111    tokenizer,112    target_size = (1000, 1000),113    max_seq_length=512,114    use_ocr = False,115    bounding_box = None,116    words = None117    ):118  119  '''120  We assume that the bounding box provided are given as per the image scale (i.e not normalized), so that we just need to scale it as per the ratio121  '''122 123 124  img = Image.open(image_path).convert("RGB")125  width_old, height_old = img.size126  img = img.resize(target_size)127  width, height = img.size128  129  ## Rescaling the bounding box as per the image size130  131 132  if (use_ocr == False) and (bounding_box == None or words == None):133    raise Exception('Please provide the bounding box and words or pass the argument "use_ocr" = True')134 135  if use_ocr == True:136    entries = apply_ocr(image_path)137    bounding_box = entries["bbox"]138    words = entries["words"]139  140  bounding_box = list(map(lambda x: resize_align_bbox(x,width_old,height_old, width, height), bounding_box))141  boxes, tokenized_words = get_tokens_with_boxes(unnormalized_word_boxes = bounding_box,142                                               list_of_words = words, 143                                               tokenizer = tokenizer,144                                               pad_token_id = 0,145                                               pad_token_box = PAD_TOKEN_BOX,146                                               max_seq_len = max_seq_length147                                               )148 149 150  return img, boxes, tokenized_words151