{"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"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":125981,"databundleVersionId":14910697,"sourceType":"competition"},{"sourceId":288463578,"sourceType":"kernelVersion"},{"sourceId":699947,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":531061,"modelId":544920}],"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import tensorflow as tf\nimport numpy as np\nimport os\n\n# Load your classifier\nclassifier = tf.keras.models.load_model(\"/kaggle/input/map-rec/keras/default/1/map_recognition.keras\")\n\n# Setup Data Pipeline (Crucial for 10k images)\ntest_ds = tf.keras.utils.image_dataset_from_directory(\n    '/kaggle/input/the-blind-flight-synapse-drive-ps-1/SynapseDrive_Dataset/test/images/',\n    labels=None, \n    image_size=(256, 256), # Match your CNN\n    batch_size=8, \n    shuffle=False\n)\n\n# Get all file paths in the exact order the dataset will read them\nfile_paths = test_ds.file_paths\n\n# Run batch prediction\npreds = classifier.predict(test_ds)\nclass_indices = np.argmax(preds, axis=1)\n\n# Route paths into three lists\ndesert_files = [file_paths[i] for i, cls in enumerate(class_indices) if cls == 0]\nforest_files = [file_paths[i] for i, cls in enumerate(class_indices) if cls == 1]\nlab_files = [file_paths[i] for i, cls in enumerate(class_indices) if cls == 2]","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"%pip install ultralytics","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch, gc\ngc.collect()\ntorch.cuda.empty_cache()\n\nimport os\nimport json\nimport heapq\nimport pandas as pd\nimport numpy as np\nfrom ultralytics import YOLO\nfrom itertools import islice\nimport gc\n\ndef chunked(iterable, size):\n    it = iter(iterable)\n    while True:\n        batch = list(islice(it, size))\n        if not batch:\n            break\n        yield batch\n\n# 1. Helper Functions\ndef heuristic(a, b):\n    # Manhattan distance\n    return abs(a[0] - b[0]) + abs(a[1] - b[1])\n\ndef astar(grid, start, goal):\n    rows, cols = 20, 20\n    INF = float('inf')\n    dist = [[INF]*cols for _ in range(rows)]\n    parent = {}\n    pq = []\n\n    dist[start[0]][start[1]] = 0\n    # Priority queue stores (f_score, g_score, (r, c))\n    heapq.heappush(pq, (heuristic(start, goal), 0, start))\n\n    while pq:\n        _, cur_cost, (r, c) = heapq.heappop(pq)\n\n        if (r, c) == goal:\n            break\n\n        if cur_cost > dist[r][c]:\n            continue\n\n        for dr, dc in [(1,0), (-1,0), (0,1), (0,-1)]:\n            nr, nc = r + dr, c + dc\n\n            if 0 <= nr < rows and 0 <= nc < cols:\n                cell_val = grid[nr][nc]\n                if cell_val <0: continue # Wall\n                \n                new_cost = cur_cost + cell_val\n                if new_cost < dist[nr][nc]:\n                    dist[nr][nc] = new_cost\n                    parent[(nr, nc)] = (r, c)\n                    priority = new_cost + heuristic((nr, nc), goal)\n                    heapq.heappush(pq, (priority, new_cost, (nr, nc)))\n\n    if goal not in parent:\n        s=''\n        x=goal[1]-start[1]\n        y=goal[0]-start[0]\n        if x<0:\n            s=s+'l'*abs(x)\n        else:\n            s=s+'r'*abs(x)\n        if y<0:\n            s=s+'u'*abs(x)\n        else:\n            s=s+'d'*abs(x) \n        return s\n    # 2. Path Reconstruction & Correct Direction Mapping\n    path = []\n    cur = goal\n    while cur != start:\n        path.append(cur)\n        cur = parent[cur]\n    path.append(start)\n    path.reverse() # Start to Goal\n\n    # Mapping matrix movements to characters\n    # Row +1 = down, Row -1 = up, Col +1 = right, Col -1 = left\n    DIR_MAP = {(1, 0): 'd', (-1, 0): 'u', (0, 1): 'r', (0, -1): 'l'}\n    \n    directions = ''\n    for i in range(len(path) - 1):\n        r1, c1 = path[i]\n        r2, c2 = path[i+1]\n        move = (r2 - r1, c2 - c1)\n        directions += DIR_MAP.get(move, '')\n        \n    return directions\n\n# 3. Processing Function\ndef process_yolo(model_path, image_list, output_file):\n    if not image_list: return\n    \n    yolo_model = YOLO(model_path)\n    # stream=True is efficient for large datasets\n    \n    D = {\n        'rover': 1.2, 'sand': 1.2, 'quicksand': 3.7, 'cactus': -1, \n        'rocks': -1, 'dirt': 1.5, 'puddle': 2.8, 'startship': 1.5, \n        'floor': 1.0, 'glue': 3.0, 'drone': 1.0, 'wall': -1, 'tree':-1, 'plasma':-1\n    }\n\n    for result in yolo_model.predict(source=image_list, stream=False, max_det=400, cache=False, workers=0, batch=1):\n        img_name = os.path.basename(result.path)\n        all_data = []\n        \n        # Build detection list\n        for box in result.boxes:\n            all_data.append({\n                \"class\": yolo_model.names[int(box.cls[0])],\n                \"xmax\": float(box.xyxy[0][2]),\n                \"ymax\": float(box.xyxy[0][3])\n            })\n\n        if not all_data: continue\n        \n        # Sort and Group into Grid (20x20 logic)\n        df = pd.DataFrame(all_data).sort_values(by='ymax').reset_index(drop=True)\n        \n        img_h = 640 \n        tolerance = (img_h / 20) * 0.5 \n        \n        rows_list = []\n        current_row = [df.iloc[0].to_dict()]\n        \n        for i in range(1, len(df)):\n            if abs(df.iloc[i]['ymax'] - current_row[-1]['ymax']) < tolerance:\n                current_row.append(df.iloc[i].to_dict())\n            else:\n                rows_list.append(sorted(current_row, key=lambda x: x['xmax']))\n                current_row = [df.iloc[i].to_dict()]\n        rows_list.append(sorted(current_row, key=lambda x: x['xmax']))\n\n        # Create Matrix\n        matrix = np.full((20, 20), 1.0, dtype=float) # Default to 1.0 cost\n        start, goal = (0, 0), (19, 19)\n        start_found=False\n        goal_found= False\n        for r_idx, row_data in enumerate(rows_list):\n            if r_idx >= 20: break\n            for c_idx, obj in enumerate(row_data):\n                if c_idx >= 20: break\n                \n                cls_name = obj['class']\n                if cls_name == 'goal':\n                    if goal_found==False:\n                        goal = (r_idx, c_idx)\n                        matrix[r_idx, c_idx] = 1.0\n                        goal_found=True\n                elif cls_name in ['rover', 'startship', 'drone']:\n                    if start_found==False:\n                        start = (r_idx, c_idx)\n                        matrix[r_idx, c_idx] = D[cls_name]\n                        start_found=True\n                else:\n                    matrix[r_idx, c_idx] = D[cls_name]\n\n        # Apply Boost from JSON\n        # Logic assumes a specific folder structure for velocity JSONs\n        try:\n            js_path = result.path.replace('/images/', '/velocities/').replace('.png', '.json')\n            with open(js_path, 'r') as f:\n                boost_data = json.load(f)\n                boost_array = np.array(boost_data[\"boost\"])\n                matrix = matrix - boost_array\n        except Exception:\n            pass # Skip if JSON is missing\n\n        # Calculate Path\n        ans = astar(matrix, start, goal)\n        \n        # Write to results file\n        output_file.write(f\"{img_name.replace('.png', '')},{ans}\\n\")\n\n# 4. Execution\n# Open file once to handle all model runs\nCHUNK_SIZE = 20 # SAFE: 50–100 recommended for YOLO-11x + 400 objs\n\nwith open('results.csv', 'w') as F:\n\n    # ---- DESERT ----\n    for i, chunk in enumerate(chunked(desert_files, CHUNK_SIZE)):\n        print(f\"[DESERT] Chunk {i+1}\")\n        process_yolo(\n            \"/kaggle/input/the-blind-flight/runs/detect/des/weights/best.pt\",\n            chunk,\n            F\n        )\n\n    # ---- FOREST ----\n    for i, chunk in enumerate(chunked(forest_files, CHUNK_SIZE)):\n        print(f\"[FOREST] Chunk {i+1}\")\n        process_yolo(\n            \"/kaggle/input/the-blind-flight/runs/detect/forest/weights/best.pt\",\n            chunk,\n            F\n        )\n\n    # ---- LAB ----\n    for i, chunk in enumerate(chunked(lab_files, CHUNK_SIZE)):\n        print(f\"[LAB] Chunk {i+1}\")\n        process_yolo(\n            \"/kaggle/input/the-blind-flight/runs/detect/lab/weights/best.pt\",\n            chunk,\n            F\n        )\n# 1. Load the CSV as strings to prevent immediate stripping\ndf = pd.read_csv('results.csv', header=None, dtype={0: str})\n\n# 2. Pad column 0 with zeros until it is 4 characters long\n# '1' becomes '0001', '12' becomes '0012', etc.\ndf[0] = df[0].str.zfill(4)\n\n# 3. Sort by the padded strings (now they sort correctly!)\ndf_sorted = df.sort_values(by=0)\n\n# 4. Save back to CSV\ndf_sorted.to_csv('results.csv', index=False, header=False)","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}