{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":112509,"databundleVersionId":14254895,"sourceType":"competition"},{"sourceId":13760680,"sourceType":"datasetVersion","datasetId":8756792}],"dockerImageVersionId":31192,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport tensorflow as tf\nfrom tensorflow.keras.preprocessing.image import load_img, img_to_array\nimport json\nimport os\nimport warnings\nwarnings.filterwarnings('ignore')","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-11-17T04:38:15.299137Z","iopub.execute_input":"2025-11-17T04:38:15.300079Z","iopub.status.idle":"2025-11-17T04:38:15.304750Z","shell.execute_reply.started":"2025-11-17T04:38:15.300042Z","shell.execute_reply":"2025-11-17T04:38:15.303915Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model_path = '/kaggle/input/csirov2data/biomass_model_JP.keras'\ntarget_ranges_path = '/kaggle/input/csirov2data/target_ranges.json'\n\nif not os.path.exists(model_path):\n    raise FileNotFoundError(f\"Model file not found: {model_path}\")\nif not os.path.exists(target_ranges_path):\n    raise FileNotFoundError(f\"Target ranges file not found: {target_ranges_path}\")\n\nmodel = tf.keras.models.load_model(model_path)\nprint(\"Model loaded successfully\")\n\nwith open(target_ranges_path, 'r') as f:\n    target_ranges = json.load(f)\n\nprint(target_ranges)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-17T04:42:32.736129Z","iopub.execute_input":"2025-11-17T04:42:32.736571Z","iopub.status.idle":"2025-11-17T04:42:33.246596Z","shell.execute_reply.started":"2025-11-17T04:42:32.736545Z","shell.execute_reply":"2025-11-17T04:42:33.245546Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def extract_color_features(image_path, target_size=(2000, 1000)):\n    \"\"\"Extract color-based features from image pixels\"\"\"\n    try:\n        # Try different path formats for different environments\n        paths_to_try = f'/kaggle/input/csiro-biomass/test/{image_path}'\n        \n        \n        img = None\n        for path in paths_to_try:\n            try:\n                img = load_img(path, target_size=target_size)\n                break\n            except:\n                continue\n        \n        if img is None:\n            raise FileNotFoundError(f\"Could not load image: {image_path}\")\n            \n        img_array = img_to_array(img)\n        \n        img_hsv = tf.image.rgb_to_hsv(img_array / 255.0).numpy()\n        h, s, v = img_hsv[:, :, 0], img_hsv[:, :, 1], img_hsv[:, :, 2]\n        \n        total_pixels = target_size[0] * target_size[1]\n        \n        dead_dry_mask = ((s < 0.3) & (v > 0.4)) | ((h >= 0.05) & (h <= 0.15) & (s > 0.2) & (s < 0.6))\n        dead_dry_count = np.sum(dead_dry_mask)\n        \n        live_green_mask = (h >= 0.2) & (h <= 0.5) & (s > 0.25) & (v > 0.2)\n        live_green_count = np.sum(live_green_mask)\n        \n        color_other_count = total_pixels - dead_dry_count - live_green_count\n        \n        return {\n            'dead_dry': int(dead_dry_count),\n            'live_green': int(live_green_count), \n            'color_other': int(color_other_count)\n        }\n    except Exception as e:\n        total_pixels = target_size[0] * target_size[1]\n        return {\n            'dead_dry': total_pixels // 3,\n            'live_green': total_pixels // 3,\n            'color_other': total_pixels - (2 * (total_pixels // 3))\n        }\n\ndef load_and_preprocess_image(image_path, target_size=(2000, 1000)):\n    \"\"\"Load and preprocess image for model input\"\"\"\n    try:\n        # Try different path formats\n        paths_to_try = [\n            f'csiro-biomass/{image_path}',  # Local\n            f'/kaggle/input/csiro-biomass/test/{image_path}',  # Kaggle\n            f'test/{image_path}',  # Direct path\n            image_path  # As-is\n        ]\n        \n        img = None\n        for path in paths_to_try:\n            try:\n                img = load_img(path, target_size=target_size)\n                break\n            except:\n                continue\n                \n        if img is None:\n            raise FileNotFoundError(f\"Could not load image: {image_path}\")\n            \n        img_array = img_to_array(img) / 255.0\n        return img_array\n    except Exception as e:\n        return np.zeros(target_size + (3,))\n\ndef scale_predictions(sigmoid_predictions, target_ranges):\n    \"\"\"Manually scale sigmoid outputs (0-1) to actual target ranges\"\"\"\n    scaled_predictions = {}\n    target_names = ['Dry_Clover_g', 'Dry_Dead_g', 'Dry_Green_g']\n    \n    for i, target_name in enumerate(target_names):\n        sigmoid_val = sigmoid_predictions[i][0][0]  # Extract scalar value\n        \n        if target_ranges and target_name in target_ranges:\n            min_val = target_ranges[target_name]['min']\n            max_val = target_ranges[target_name]['max']\n            # Scale from 0-1 to actual range\n            scaled_val = min_val + sigmoid_val * (max_val - min_val)\n        else:\n            # Default scaling if no ranges\n            scaled_val = sigmoid_val * 300.0\n            \n        scaled_predictions[target_name] = float(scaled_val)\n    \n    return scaled_predictions","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-17T04:38:50.149227Z","iopub.execute_input":"2025-11-17T04:38:50.149601Z","iopub.status.idle":"2025-11-17T04:38:50.163382Z","shell.execute_reply.started":"2025-11-17T04:38:50.149576Z","shell.execute_reply":"2025-11-17T04:38:50.162340Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_paths = '/kaggle/input/csiro-biomass/test.csv'\n\ntest_df = None\nfor path in test_paths:\n    try:\n        test_df = pd.read_csv(test_paths)\n        break\n    except:\n        continue\n\nif test_df is None:\n    raise FileNotFoundError(\"Could not find test.csv file\")\n\nunique_test_images = test_df['image_path'].unique()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-17T04:40:07.558332Z","iopub.execute_input":"2025-11-17T04:40:07.559173Z","iopub.status.idle":"2025-11-17T04:40:07.599439Z","shell.execute_reply.started":"2025-11-17T04:40:07.559147Z","shell.execute_reply":"2025-11-17T04:40:07.598380Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"predictions = []\nall_target_names = ['Dry_Clover_g', 'Dry_Dead_g', 'Dry_Green_g', 'Dry_Total_g', 'GDM_g']\n\nfor idx, img_path in enumerate(unique_test_images):\n    try:\n        color_features = extract_color_features(img_path)\n        img = load_and_preprocess_image(img_path)\n        \n        img_batch = np.expand_dims(img, axis=0)\n        color_batch = np.expand_dims([color_features['dead_dry'], color_features['live_green'], color_features['color_other']], axis=0).astype(np.float32)\n        \n        pred = model.predict({'image_input': img_batch, 'color_input': color_batch}, verbose=0)\n        scaled_preds = scale_predictions(pred, target_ranges)\n        \n        dry_clover = scaled_preds['Dry_Clover_g']\n        dry_dead = scaled_preds['Dry_Dead_g']  \n        dry_green = scaled_preds['Dry_Green_g']\n        \n        dry_total = dry_clover + dry_dead + dry_green\n        gdm = dry_clover + dry_green\n        \n        target_values = [dry_clover, dry_dead, dry_green, dry_total, gdm]\n        base_id = img_path.split('/')[-1].replace('.jpg', '')\n        \n        for i, target_name in enumerate(all_target_names):\n            sample_id = f\"{base_id}__{target_name}\"\n            predictions.append({\n                'sample_id': sample_id,\n                'target': target_values[i]\n            })\n            \n    except Exception as e:\n        base_id = img_path.split('/')[-1].replace('.jpg', '')\n        for target_name in all_target_names:\n            sample_id = f\"{base_id}__{target_name}\"\n            predictions.append({\n                'sample_id': sample_id,\n                'target': 0.0\n            })","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-17T04:40:26.187757Z","iopub.execute_input":"2025-11-17T04:40:26.188123Z","iopub.status.idle":"2025-11-17T04:40:26.502501Z","shell.execute_reply.started":"2025-11-17T04:40:26.188099Z","shell.execute_reply":"2025-11-17T04:40:26.501379Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"submission_df = pd.DataFrame(predictions)\nsubmission_df.to_csv('submission.csv', index=False)\n\nprint(\"Submission file created successfully\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-17T04:40:30.734506Z","iopub.execute_input":"2025-11-17T04:40:30.735150Z","iopub.status.idle":"2025-11-17T04:40:30.747923Z","shell.execute_reply.started":"2025-11-17T04:40:30.735125Z","shell.execute_reply":"2025-11-17T04:40:30.747178Z"}},"outputs":[],"execution_count":null}]}