{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[],"dockerImageVersionId":28755,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\npath = \"/kaggle/input/datasets/gopalbhattrai/pascal-voc-2012-dataset/VOC2012_train_val/VOC2012_train_val/JPEGImages/\"\nfiles = os.listdir(path)\nprint(f\"Total images: {len(files)}\")\nprint(files[:5])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-13T10:51:34.526370Z","iopub.execute_input":"2026-06-13T10:51:34.527054Z","iopub.status.idle":"2026-06-13T10:51:34.541126Z","shell.execute_reply.started":"2026-06-13T10:51:34.527020Z","shell.execute_reply":"2026-06-13T10:51:34.540131Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport shutil\nimport multiprocessing as mp\nfrom concurrent.futures import ProcessPoolExecutor\nfrom concurrent.futures import ThreadPoolExecutor\nfrom tqdm.auto import tqdm\nimport time\nfrom PIL import Image\n\nVOC_ROOT  = \"/kaggle/input/datasets/gopalbhattrai/pascal-voc-2012-dataset/VOC2012_train_val/VOC2012_train_val\"\nMASK_DIR  = os.path.join(VOC_ROOT, \"SegmentationClass\")\nIMAGE_DIR = os.path.join(VOC_ROOT, \"JPEGImages\")\n \nOUTPUT_DIR = \"/kaggle/working/control_dataset_confusion\"\nPLOT_DIR   = os.path.join(OUTPUT_DIR, \"plots\")\nBIN_DIR    = os.path.join(OUTPUT_DIR, \"bins\")\n \nfor d in [OUTPUT_DIR, PLOT_DIR, BIN_DIR]:\n    os.makedirs(d, exist_ok=True)\n \nSEED            = 42\nIMAGES_PER_BIN  = 100   # will adjust down if a bin is smaller\n\nnp.random.seed(SEED)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-13T21:20:01.500975Z","iopub.execute_input":"2026-06-13T21:20:01.501548Z","iopub.status.idle":"2026-06-13T21:20:01.508520Z","shell.execute_reply.started":"2026-06-13T21:20:01.501513Z","shell.execute_reply":"2026-06-13T21:20:01.507701Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"VOC_CLASSES = {\n    0: \"background\",\n    1: \"aeroplane\",\n    2: \"bicycle\",\n    3: \"bird\",\n    4: \"boat\",\n    5: \"bottle\",\n    6: \"bus\",\n    7: \"car\",\n    8: \"cat\",\n    9: \"chair\",\n    10: \"cow\",\n    11: \"diningtable\",\n    12: \"dog\",\n    13: \"horse\",\n    14: \"motorbike\",\n    15: \"person\",\n    16: \"pottedplant\",\n    17: \"sheep\",\n    18: \"sofa\",\n    19: \"train\",\n    20: \"tvmonitor\"\n}\nCONFUSABLE_PAIRS = [\n    # Named explicitly in Figure 5 caption\n    (15, 2),    # person <-> bicycle\n    (15, 14),   # person <-> motorbike\n    (18, 9),    # sofa <-> chair\n    (15, 9),    # person <-> chair (Figure 5 shows this)\n \n    # Named in paper discussion / Figure 5 examples\n    (8,  12),   # cat <-> dog\n    (10, 13),   # cow <-> horse\n    (2,  14),   # bicycle <-> motorbike\n    (9,  11),   # chair <-> diningtable\n    (15, 13),   # person <-> horse  (rider scenes)\n    (7,  6),    # car <-> bus\n    (3,  1),    # bird <-> aeroplane\n    (4,  1),    # boat <-> aeroplane\n    (15, 17),   # person <-> sheep  (Figure 5 example)\n    (15, 10),   # person <-> cow\n]\n \nPAIR_NAMES = {\n    (min(a,b), max(a,b)): f\"{VOC_CLASSES[a]} <-> {VOC_CLASSES[b]}\"\n    for a, b in CONFUSABLE_PAIRS\n}\n \n# normalise pairs so order doesn't matter\nCONFUSABLE_PAIRS = [(min(a,b), max(a,b)) for a, b in CONFUSABLE_PAIRS]\n \nprint(f\"Confusable pairs defined: {len(CONFUSABLE_PAIRS)}\")\nfor p in CONFUSABLE_PAIRS:\n    print(f\"  {PAIR_NAMES[p]}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-13T21:18:29.657371Z","iopub.execute_input":"2026-06-13T21:18:29.657795Z","iopub.status.idle":"2026-06-13T21:18:29.666225Z","shell.execute_reply.started":"2026-06-13T21:18:29.657766Z","shell.execute_reply":"2026-06-13T21:18:29.665576Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def assign_bin(score: int) -> str:\n    if score == 0:   return \"bin0\"\n    elif score == 1: return \"bin1\"\n    elif score == 2: return \"bin2\"\n    else:            return \"bin3plus\"\n \n \ndef process_mask(mask_path: str) -> dict:\n    mask    = np.array(Image.open(mask_path))\n    classes = set(np.unique(mask))\n    classes.discard(255)   # ignore void/boundary label\n \n    matched = []\n    for c1, c2 in CONFUSABLE_PAIRS:\n        if c1 in classes and c2 in classes:\n            matched.append(PAIR_NAMES[(c1, c2)])\n \n    score = len(matched)\n    return {\n        \"image_id\"       : os.path.basename(mask_path).replace(\".png\", \"\"),\n        \"confusion_score\": score,\n        \"bin\"            : assign_bin(score),\n        \"pairs\"          : \", \".join(matched),\n        \"num_classes\"    : len(classes)\n    }\n\nmask_paths = sorted([\n    os.path.join(MASK_DIR, f)\n    for f in os.listdir(MASK_DIR) if f.endswith(\".png\")\n])\nprint(f\"Total segmentation masks: {len(mask_paths)}\")\nstart = time.time()\nwith ThreadPoolExecutor(max_workers=mp.cpu_count()) as ex:\n    results = list(tqdm(ex.map(process_mask, mask_paths),total=len(mask_paths)))\n\ndf = pd.DataFrame(results)\nprint(\"Time = \", time.time()-start) \nprint(\"\\nConfusion Score Distribution:\")\nprint(df[\"confusion_score\"].value_counts().sort_index())\nprint(\"\\nBin Distribution:\")\nprint(df[\"bin\"].value_counts().sort_index())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-13T21:21:30.209226Z","iopub.execute_input":"2026-06-13T21:21:30.210009Z","iopub.status.idle":"2026-06-13T21:21:34.111284Z","shell.execute_reply.started":"2026-06-13T21:21:30.209974Z","shell.execute_reply":"2026-06-13T21:21:34.110524Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport shutil\nimport pandas as pd\n\nOUTPUT_DIR = \"/kaggle/working/final_control_dataset/\"\nIMAGE_SRC_DIR = \"/kaggle/input/datasets/gopalbhattrai/pascal-voc-2012-dataset/VOC2012_train_val/VOC2012_train_val/JPEGImages/\"\n\n#df = pd.DataFrame(output_rows) \ndownsampled_rows = []\n\nfor bin_name, group in df.groupby(\"bin\"):\n    sampled_group = group.sample(n=min(500, len(group)), random_state=42)\n    downsampled_rows.append(sampled_group)\n\nfinal_deliverable_df = pd.concat(downsampled_rows).reset_index(drop=True)\n\nfinal_output_rows = []\n\nfor idx, row in final_deliverable_df.iterrows():\n    src_file = os.path.join(IMAGE_SRC_DIR, row[\"image_id\"] + \".jpg\")\n    dst_dir = os.path.join(OUTPUT_DIR, row[\"bin\"])\n    os.makedirs(dst_dir, exist_ok=True)\n    dst_file = os.path.join(dst_dir, row[\"image_id\"] + \".jpg\")\n    \n    if os.path.exists(src_file):\n        shutil.copy2(src_file, dst_file)\n        final_output_rows.append({**row, \"final_image_path\": dst_file})\n\ndeliverable_meta_df = pd.DataFrame(final_output_rows)\ncsv_output_path = os.path.join(OUTPUT_DIR, \"final_control_dataset_manifest.csv\")\ndeliverable_meta_df.to_csv(csv_output_path, index=False)\n\nprint(f\"\\nSuccess! Final deliverable compiled with {len(deliverable_meta_df)} images.\")\nprint(f\"Manifest file saved to: {csv_output_path}\")\nprint(deliverable_meta_df[\"bin\"].value_counts())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-13T10:51:39.190954Z","iopub.execute_input":"2026-06-13T10:51:39.191399Z","iopub.status.idle":"2026-06-13T10:51:40.905007Z","shell.execute_reply.started":"2026-06-13T10:51:39.191363Z","shell.execute_reply":"2026-06-13T10:51:40.904045Z"}},"outputs":[],"execution_count":null}]}