{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport json\nfrom collections import Counter\nfrom tqdm import tqdm\n# define directories\nIMAGE_DIR = '/kaggle/input/benetech-making-graphs-accessible/train/images'\nANNOTATIONS_DIR = '/kaggle/input/benetech-making-graphs-accessible/train/annotations'\n# get the list of images\nimage_filenames = os.listdir(IMAGE_DIR)","metadata":{"tags":[],"execution":{"iopub.status.busy":"2023-06-20T09:35:51.587058Z","iopub.execute_input":"2023-06-20T09:35:51.587586Z","iopub.status.idle":"2023-06-20T09:35:52.049147Z","shell.execute_reply.started":"2023-06-20T09:35:51.587542Z","shell.execute_reply":"2023-06-20T09:35:52.047846Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Convert polygon to bbox\ndef convert_to_bbox(polygon):\n    return [polygon['x0'], polygon['y0'], polygon['x1'], polygon['y1'],polygon['x2'],polygon['y2'],polygon['x3'],polygon['y3']]","metadata":{"tags":[],"execution":{"iopub.status.busy":"2023-06-20T09:35:52.051376Z","iopub.execute_input":"2023-06-20T09:35:52.052470Z","iopub.status.idle":"2023-06-20T09:35:52.060188Z","shell.execute_reply.started":"2023-06-20T09:35:52.052422Z","shell.execute_reply":"2023-06-20T09:35:52.058968Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import re\n\n#Check if a string is number\ndef is_number(s: str):\n    s = re.sub('[,$% ]', '', s)\n    try:\n        float(s)\n        return True\n    except ValueError:\n        return False\n\n#Get number from string\ndef get_number(s):\n    if type(s)==str:\n        return float(re.sub('[,$% ]', '', s))\n    else:\n        return float(s)\n#Given ticks, and data-series, find the co-ordinates of data points on the image\ndef translate_dataseries_to_chart(dataseries, x_tickinfo, y_tickinfo,ctype):\n    x_labels_numerical = all(is_number(label) for label in x_tickinfo.keys())\n    y_labels_numerical = all(is_number(label) for label in y_tickinfo.keys())\n\n    if x_labels_numerical:\n        # Convert y_tickinfo keys to float for comparison\n        x_ticks = {get_number(k): v for k, v in x_tickinfo.items()}\n\n        # Sort the y_ticks dictionary by key\n        x_ticks = dict(sorted(x_ticks.items()))\n\n        # List of y_ticks keys and values for interpolation\n        x_values = list(x_ticks.keys())\n        x_coords = list(x_ticks.values())\n    else:\n        # Create a mapping from x labels to their coordinates\n        x_mapping = {label: info['x'] for label, info in x_tickinfo.items()}\n\n    if y_labels_numerical:\n        # Convert y_tickinfo keys to float for comparison\n        y_ticks = {get_number(k): v for k, v in y_tickinfo.items()}\n\n        # Sort the y_ticks dictionary by key\n        y_ticks = dict(sorted(y_ticks.items()))\n\n        # List of y_ticks keys and values for interpolation\n        y_values = list(y_ticks.keys())\n        y_coords = list(y_ticks.values())\n    else:\n        # Create a mapping from y labels to their coordinates\n        y_mapping = {label: info['y'] for label, info in y_tickinfo.items()}\n\n    result = []\n    for point in dataseries:\n        x_val = point['x']\n        y_val = point['y']\n\n        if x_labels_numerical:\n            x_val = get_number(x_val)\n            # Find the two y_ticks that y_val falls between\n            for i in range(len(x_values) - 1):\n                if x_values[i] <= x_val <= x_values[i + 1]:\n                    # Linear interpolation of x_val to y_coord\n                    ratio = (x_val - x_values[i]) / (x_values[i + 1] - x_values[i])\n                    x_coord = x_coords[i]['x'] + ratio * (x_coords[i + 1]['x'] - x_coords[i]['x'])\n                    break\n            else:  # y_val >= maximum y_values[i]\n                ratio = (x_val - x_values[0]) / (x_values[-1] - x_values[0])\n                x_coord = x_coords[0]['x'] + ratio * (x_coords[-1]['x'] - x_coords[0]['x'])\n        else:\n            x_coord = x_mapping[x_val]\n\n        if y_labels_numerical:\n            y_val = get_number(y_val)\n\n            # Find the two y_ticks that y_val falls between\n            for i in range(len(y_values) - 1):\n                if y_values[i] <= y_val <= y_values[i + 1]:\n                    # Linear interpolation of y_val to y_coord\n                    ratio = (y_val - y_values[i]) / (y_values[i + 1] - y_values[i])\n                    y_coord = y_coords[i]['y'] + ratio * (y_coords[i + 1]['y'] - y_coords[i]['y'])\n                    break\n            else:  # y_val >= maximum y_values[i]\n                ratio = (y_val - y_values[0]) / (y_values[-1] - y_values[0])\n                y_coord = y_coords[0]['y'] + ratio * (y_coords[-1]['y'] - y_coords[0]['y'])\n\n        else:\n            # For non-numerical data, find the closest y tick\n#             closest_y_label = min(y_mapping.keys(), key=lambda label: abs(float(label) - y_val))\n            y_coord = y_mapping[y_val]\n\n        # Append (x_coord, y_coord) to result\n        result.append((x_coord, y_coord))\n\n    return result\n","metadata":{"tags":[],"execution":{"iopub.status.busy":"2023-06-20T09:35:52.523472Z","iopub.execute_input":"2023-06-20T09:35:52.523931Z","iopub.status.idle":"2023-06-20T09:35:52.548634Z","shell.execute_reply.started":"2023-06-20T09:35:52.523895Z","shell.execute_reply":"2023-06-20T09:35:52.547642Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_id(texts,i):\n    for k in texts:\n        if i==k[\"id\"]:\n            return k\n\n#Convert a point to square\ndef create_square(point, k=10):\n    if type(point)==dict:\n        x,y = point[\"x\"],point[\"y\"]\n    else:\n        x,y =point\n    half_k = k / 2.0\n\n    # Define the corners of the square\n    corners = [x - half_k, y - half_k,x + half_k, y - half_k,x + half_k, y + half_k,x - half_k, y + half_k]\n    return corners\n\ndef polygon_to_bbox(polygon):\n    # Create list of x and y coordinates\n    x_coords = polygon[0::2]\n    y_coords = polygon[1::2]\n\n    # Compute minimum and maximum coordinates\n    x_min, x_max = min(x_coords), max(x_coords)\n    y_min, y_max = min(y_coords), max(y_coords)\n\n    # Calculate the center of the bounding box\n    x_center = (x_min + x_max) / 2.0\n    y_center = (y_min + y_max) / 2.0\n\n    # Calculate the width and height of the bounding box\n    width = x_max - x_min\n    height = y_max - y_min\n\n    # Return the bounding box in the format [x, y, width, height]\n    return [x_center, y_center, width, height]\n\n\ndef get_line_bboxes(v,ctype=None):\n    texts = v[\"text\"]\n    polygon_info = []\n    point_info = []\n    x_tickinfo = {}\n    y_tickinfo = {}\n\n    for tinf in v[\"axes\"][\"x-axis\"][\"ticks\"]:\n        bbox_label = convert_to_bbox(get_id(texts,tinf[\"id\"])[\"polygon\"])\n        polygon_info.append([0]+bbox_label)\n        x_tickinfo[get_id(texts,tinf[\"id\"])[\"text\"]] = tinf[\"tick_pt\"]\n\n    for tinf in v[\"axes\"][\"y-axis\"][\"ticks\"]:\n        bbox_label = convert_to_bbox(get_id(texts,tinf[\"id\"])[\"polygon\"])\n        polygon_info.append([1]+bbox_label)\n        y_tickinfo[get_id(texts,tinf[\"id\"])[\"text\"]] = tinf[\"tick_pt\"]\n    if ctype==\"horizontal_bar\":\n        x_tickinfo, y_tickinfo = y_tickinfo, x_tickinfo\n    for (x,y) in translate_dataseries_to_chart(v['data-series'],x_tickinfo, y_tickinfo,ctype):\n        point_info.append([2]+create_square([x,y]))\n    \n    return [[p[0]]+polygon_to_bbox(p[1:]) for p in polygon_info+point_info]\n","metadata":{"tags":[],"execution":{"iopub.status.busy":"2023-06-20T09:35:52.863952Z","iopub.execute_input":"2023-06-20T09:35:52.865012Z","iopub.status.idle":"2023-06-20T09:35:52.881128Z","shell.execute_reply.started":"2023-06-20T09:35:52.864974Z","shell.execute_reply":"2023-06-20T09:35:52.879576Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import cv2\nimport matplotlib.pyplot as plt\nimport random\n\n# define 8 different colors for the 8 classes\n\ndef draw_boxes(image_path, data_file_path):\n    # load image\n    colors = [(random.randint(0,255), random.randint(0,255), random.randint(0,255)) for _ in range(8)]\n    image = cv2.imread(image_path)\n    image_height, image_width = image.shape[:2]\n    plt.figure(figsize=(10,10))\n    with open(data_file_path, 'r') as file:\n        lines = file.readlines()\n        for line in lines:\n            data = line.strip().split()\n            object_class, x_center, y_center, width, height = map(float, data)\n            object_class = int(object_class)\n\n            # denormalize coordinates and dimensions\n            x_center *= image_width\n            y_center *= image_height\n            width *= image_width\n            height *= image_height\n\n            # calculate the top left and bottom right points\n            x1 = int(x_center-width/2)\n            y1 = int(y_center-height/2)\n            x2 = int(x_center + width/2)\n            y2 = int(y_center + height/2)\n\n            # draw the bounding box on the image\n            cv2.rectangle(image, (x1, y1), (x2, y2), colors[object_class], 2)\n\n    # convert the image from BGR color space to RGB\n    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n    \n    # display the image\n    plt.imshow(image)\n    plt.show()","metadata":{"tags":[],"execution":{"iopub.status.busy":"2023-06-20T09:35:53.187221Z","iopub.execute_input":"2023-06-20T09:35:53.187674Z","iopub.status.idle":"2023-06-20T09:35:53.398963Z","shell.execute_reply.started":"2023-06-20T09:35:53.187639Z","shell.execute_reply":"2023-06-20T09:35:53.397596Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"os.makedirs(\"./dataset/train/images\",exist_ok=True)\nos.makedirs(\"./dataset/train/labels\",exist_ok=True)","metadata":{"tags":[],"execution":{"iopub.status.busy":"2023-06-20T09:35:53.572218Z","iopub.execute_input":"2023-06-20T09:35:53.572592Z","iopub.status.idle":"2023-06-20T09:35:53.579167Z","shell.execute_reply.started":"2023-06-20T09:35:53.572564Z","shell.execute_reply":"2023-06-20T09:35:53.578176Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import shutil\nimport numpy as np\n\nCINDEX={'line': 0, 'dot': 1, 'vertical_bar': 2, 'scatter': 3, 'horizontal_bar': 4}\nfailed=0\nTTH=10/len(image_filenames)\nfor img in  tqdm(image_filenames):\n    try:\n        k = img.split(\".\")[0]\n        v = json.load(open(os.path.join(ANNOTATIONS_DIR,k+\".json\")))\n        imgpth=os.path.join(IMAGE_DIR,img)\n        height,width=cv2.imread(imgpth).shape[:2]\n        polygon = get_line_bboxes(v, v['chart-type'])\n        h,w,x,y = list(v[\"plot-bb\"].values())\n        x = x+w/2\n        y = y+h/2\n        polygon.append([3+CINDEX[v['chart-type']],x,y,w,h])\n        for i in range(len(polygon)):\n            polygon[i][0] = str(polygon[i][0])\n            x,y,w,h = polygon[i][1:]\n            polygon[i][1] = str(x/width)\n            polygon[i][3] = str(w/width)\n            polygon[i][2] = str(y/height)\n            polygon[i][4] = str(h/height)\n\n        with open(f\"./dataset/train/labels/{k}.txt\", \"w\") as f:    \n            f.write(\"\\n\".join([\" \".join(p) for p in polygon]))\n        shutil.copy(imgpth,\"./dataset/train/images\")\n        if np.random.rand()<TTH:\n            draw_boxes(imgpth, f\"./dataset/train/labels/{k}.txt\")\n    except Exception as e:\n        print(e)\n        failed+=1\nprint(\"failed: \",failed)\n","metadata":{"tags":[],"execution":{"iopub.status.busy":"2023-06-20T09:35:54.095785Z","iopub.execute_input":"2023-06-20T09:35:54.096790Z","iopub.status.idle":"2023-06-20T09:38:03.498602Z","shell.execute_reply.started":"2023-06-20T09:35:54.096756Z","shell.execute_reply":"2023-06-20T09:38:03.497058Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# ! rm -rf ./dataset\n#uncomment the above line to get the dataset","metadata":{"execution":{"iopub.status.busy":"2023-06-20T09:38:03.499429Z","iopub.status.idle":"2023-06-20T09:38:03.499878Z","shell.execute_reply.started":"2023-06-20T09:38:03.499666Z","shell.execute_reply":"2023-06-20T09:38:03.499698Z"},"trusted":true},"execution_count":null,"outputs":[]}]}