{"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 pandas as pd\nfrom PIL import Image\nimport matplotlib.pyplot as plt\nimport random","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-05-18T11:20:30.823856Z","iopub.execute_input":"2022-05-18T11:20:30.824134Z","iopub.status.idle":"2022-05-18T11:20:30.829268Z","shell.execute_reply.started":"2022-05-18T11:20:30.824104Z","shell.execute_reply":"2022-05-18T11:20:30.828189Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"SIZE = (512, 512)\nIN_DIR  = '/kaggle/input/hotel-id-to-combat-human-trafficking-2022-fgvc9/train_images/'\nOUT_DIR = '/kaggle/working/train_images/'","metadata":{"execution":{"iopub.status.busy":"2022-05-18T11:20:31.046188Z","iopub.execute_input":"2022-05-18T11:20:31.046752Z","iopub.status.idle":"2022-05-18T11:20:31.050943Z","shell.execute_reply.started":"2022-05-18T11:20:31.046716Z","shell.execute_reply":"2022-05-18T11:20:31.049998Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"os.makedirs(OUT_DIR, exist_ok=True)","metadata":{"execution":{"iopub.status.busy":"2022-05-18T11:20:31.263902Z","iopub.execute_input":"2022-05-18T11:20:31.264188Z","iopub.status.idle":"2022-05-18T11:20:31.268913Z","shell.execute_reply.started":"2022-05-18T11:20:31.264155Z","shell.execute_reply":"2022-05-18T11:20:31.267813Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"crops_per_chain = []\nfor dirname, _, filenames in os.walk(IN_DIR):\n    if len(filenames) == 0:\n        continue\n    \n    num_hotels = len(filenames)\n    max_crops  = num_hotels * 3\n    crops_per_chain.append(max_crops)\n\navg_max_crops_per_chain = sum(crops_per_chain) / len(crops_per_chain)\navg_max_crops_per_chain","metadata":{"execution":{"iopub.status.busy":"2022-05-18T11:20:31.472263Z","iopub.execute_input":"2022-05-18T11:20:31.473036Z","iopub.status.idle":"2022-05-18T11:20:34.947024Z","shell.execute_reply.started":"2022-05-18T11:20:31.472991Z","shell.execute_reply":"2022-05-18T11:20:34.946298Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"crops_per_chain.sort()\nplt.plot(crops_per_chain)","metadata":{"execution":{"iopub.status.busy":"2022-05-18T11:20:34.948382Z","iopub.execute_input":"2022-05-18T11:20:34.948732Z","iopub.status.idle":"2022-05-18T11:20:35.146425Z","shell.execute_reply.started":"2022-05-18T11:20:34.948699Z","shell.execute_reply":"2022-05-18T11:20:35.145709Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.plot(crops_per_chain[:3000])","metadata":{"execution":{"iopub.status.busy":"2022-05-18T11:20:35.147406Z","iopub.execute_input":"2022-05-18T11:20:35.148015Z","iopub.status.idle":"2022-05-18T11:20:35.344954Z","shell.execute_reply.started":"2022-05-18T11:20:35.147978Z","shell.execute_reply":"2022-05-18T11:20:35.344060Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.plot(crops_per_chain[-25:])","metadata":{"execution":{"iopub.status.busy":"2022-05-18T11:20:35.346855Z","iopub.execute_input":"2022-05-18T11:20:35.347166Z","iopub.status.idle":"2022-05-18T11:20:35.545003Z","shell.execute_reply.started":"2022-05-18T11:20:35.347133Z","shell.execute_reply":"2022-05-18T11:20:35.544146Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_distribution(y, z, scale):\n    '''\n    Parameters\n    ----------\n    y : int\n        Number of images for this hotal chain\n    z : int\n        Average of maximum number of crops for all chains\n    '''\n    chance = 3 / 2 - z / (2 * y)\n    chance = max(0, min(1, chance))\n    comp   = min(1, z / y)\n    pct    = max(1, 1 + (1 - z / y) * scale) * comp\n    return chance, pct","metadata":{"execution":{"iopub.status.busy":"2022-05-18T11:20:35.546278Z","iopub.execute_input":"2022-05-18T11:20:35.546794Z","iopub.status.idle":"2022-05-18T11:20:35.553479Z","shell.execute_reply.started":"2022-05-18T11:20:35.546750Z","shell.execute_reply":"2022-05-18T11:20:35.552896Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def clamp01(x):\n    return max(0, min(1, x))\n\ndef get_distribution_total(y, z, scale):\n    '''\n    Parameters\n    ----------\n    y : int\n        Number of images for this hotal chain\n    z : int\n        Average of maximum number of crops for all chains\n    '''\n    chance = 3 / 2 - z / (2 * y)\n    chance = clamp01(chance)\n    comp   = min(1, z / y)\n    pct    = max(1, 1 + (1 - z / y) * scale) * comp\n    \n    total = chance * y + (1 - chance) * y * 3\n    return pct * total","metadata":{"execution":{"iopub.status.busy":"2022-05-18T11:20:35.554469Z","iopub.execute_input":"2022-05-18T11:20:35.555172Z","iopub.status.idle":"2022-05-18T11:20:35.567054Z","shell.execute_reply.started":"2022-05-18T11:20:35.555128Z","shell.execute_reply":"2022-05-18T11:20:35.566350Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dist = [get_distribution_total(max_crops, avg_max_crops_per_chain, 5) for max_crops in crops_per_chain]\nplt.plot(dist)","metadata":{"execution":{"iopub.status.busy":"2022-05-18T11:20:35.569422Z","iopub.execute_input":"2022-05-18T11:20:35.569795Z","iopub.status.idle":"2022-05-18T11:20:35.778389Z","shell.execute_reply.started":"2022-05-18T11:20:35.569750Z","shell.execute_reply":"2022-05-18T11:20:35.777609Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def generate_images(df, imgs, dirname, avg_max_crops_per_chain):\n    num_images = len(imgs)\n    one_crop_pct, pct = get_distribution(num_images, avg_max_crops_per_chain, 5)\n    \n    for idx, (im, filename) in enumerate(imgs):\n        t = idx / num_images\n        im = Image.open(dirname + '/' + filename)\n\n        w, h = im.size\n        if w > h:\n            # Image is in landscape mode\n            pad = int((w - h) / 2)\n            crops = [\n                im.crop((0, 0, h, h)),         # Left\n                im.crop((pad, 0, w - pad, h)), # Center\n                im.crop((w - h, 0, w, h)),     # Right\n            ]\n        else:\n            # Image is in portait mode\n            pad = int((h - w) / 2)\n            crops = [\n                im.crop((0, 0, w, w)),         # Top\n                im.crop((0, pad, w, h - pad)), # Center\n                im.crop((0, h - w, w, h)),     # Bottom\n            ]\n        \n        if t < one_crop_pct:\n            # Only keep center crop\n            crops = [crops[1]]\n\n        image_id = filename[:-4] # Remove '.jpg' part\n        hotel_id = dirname[75:]  # Remove IN_DIR part\n\n        for i, crop in enumerate(crops):\n            if random.random() > pct:\n                continue\n            \n            crop = crop.resize(SIZE, Image.ANTIALIAS)\n            name = image_id + str(i) + '.jpg'\n            crop.save(OUT_DIR + name)\n\n            df = df.append({\n                'hotel_id': hotel_id,\n                'image_id': name,\n            }, ignore_index=True)\n\n        return df","metadata":{"execution":{"iopub.status.busy":"2022-05-18T11:21:00.776419Z","iopub.execute_input":"2022-05-18T11:21:00.776885Z","iopub.status.idle":"2022-05-18T11:21:00.789764Z","shell.execute_reply.started":"2022-05-18T11:21:00.776846Z","shell.execute_reply":"2022-05-18T11:21:00.789056Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def load_images(dirname, filenames):\n    return [(Image.open(dirname + '/' + filename), filename) for filename in filenames]\n\ndef absolute_aspect_ratio(image):\n    w, h = image.size\n    if w > h:\n        # Image is in landscape mode\n        return w / h\n    else:\n        # Image is in portait mode\n        return h / w","metadata":{"execution":{"iopub.status.busy":"2022-05-18T11:21:02.037519Z","iopub.execute_input":"2022-05-18T11:21:02.037816Z","iopub.status.idle":"2022-05-18T11:21:02.045034Z","shell.execute_reply.started":"2022-05-18T11:21:02.037781Z","shell.execute_reply":"2022-05-18T11:21:02.043428Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = pd.DataFrame(columns=['hotel_id', 'image_id'])\n\nfor dirname, _, filenames in os.walk(IN_DIR):\n    if len(filenames) == 0:\n        continue\n    \n    print(f'Processing directory {dirname}')\n    \n    imgs = load_images(dirname, filenames)\n    ratios = [absolute_aspect_ratio(im) for (im, _) in imgs]\n    imgs = [tup for _, tup in sorted(zip(ratios, imgs), key=lambda pair: pair[0])]\n    imgs = imgs[::-1]\n    \n    df = generate_images(df, imgs, dirname, avg_max_crops_per_chain)","metadata":{"execution":{"iopub.status.busy":"2022-05-18T11:21:02.827669Z","iopub.execute_input":"2022-05-18T11:21:02.827966Z","iopub.status.idle":"2022-05-18T11:21:12.052992Z","shell.execute_reply.started":"2022-05-18T11:21:02.827934Z","shell.execute_reply":"2022-05-18T11:21:12.050211Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df.reset_index(inplace=True)\ndf.drop(columns=['index'], inplace=True)\ndf.head()","metadata":{"execution":{"iopub.status.busy":"2022-05-18T11:21:15.906824Z","iopub.execute_input":"2022-05-18T11:21:15.907935Z","iopub.status.idle":"2022-05-18T11:21:15.933934Z","shell.execute_reply.started":"2022-05-18T11:21:15.907865Z","shell.execute_reply":"2022-05-18T11:21:15.933023Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df.to_csv('train_df.csv')","metadata":{"execution":{"iopub.status.busy":"2022-05-18T11:20:36.052833Z","iopub.status.idle":"2022-05-18T11:20:36.053474Z","shell.execute_reply.started":"2022-05-18T11:20:36.053281Z","shell.execute_reply":"2022-05-18T11:20:36.053310Z"},"trusted":true},"execution_count":null,"outputs":[]}]}