{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":19989,"databundleVersionId":1160143,"sourceType":"competition"},{"sourceId":11819160,"sourceType":"datasetVersion","datasetId":7413732},{"sourceId":11846715,"sourceType":"datasetVersion","datasetId":7413522},{"sourceId":11972859,"sourceType":"datasetVersion","datasetId":7452811},{"sourceId":11972956,"sourceType":"datasetVersion","datasetId":7529182}],"dockerImageVersionId":31040,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n\nimport numpy as np \nimport pandas as pd\nimport os\nimport cv2 # For image loading, resizing, and flipping\nimport glob\nfrom tqdm import tqdm # For progress bars, optional but nice\n\n# --- Package Installation ---\nKAGGLE_WHEELS_DIR = '/kaggle/input/ultralytics-whl-pkg'\nULTRALYTICS_THOP_WHL = os.path.join(KAGGLE_WHEELS_DIR, 'ultralytics_thop-2.0.14-py3-none-any.whl') \nULTRALYTICS_WHL = os.path.join(KAGGLE_WHEELS_DIR, 'ultralytics-8.3.133-py3-none-any.whl') \nENSEMBLE_BOXES_WHL = os.path.join(KAGGLE_WHEELS_DIR, 'ensemble_boxes-1.0.9-py3-none-any.whl')\n\nprint(f\"Installing {ULTRALYTICS_THOP_WHL}...\")\n!pip install {ULTRALYTICS_THOP_WHL} -q --no-deps\nprint(f\"Installing {ULTRALYTICS_WHL}...\")\n!pip install {ULTRALYTICS_WHL} -q --no-deps\nprint(f\"Installing {ENSEMBLE_BOXES_WHL}...\")\n!pip install {ENSEMBLE_BOXES_WHL} -q --no-deps\n\nfrom ultralytics import YOLO\nfrom ensemble_boxes import weighted_boxes_fusion\n\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-05-27T15:09:01.501521Z","iopub.execute_input":"2025-05-27T15:09:01.501710Z","iopub.status.idle":"2025-05-27T15:09:25.197160Z","shell.execute_reply.started":"2025-05-27T15:09:01.501693Z","shell.execute_reply":"2025-05-27T15:09:25.196330Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# --- Configuration for Kaggle Environment & Model ---\nKAGGLE_INPUT_DIR = '/kaggle/input/global-wheat-detection'\nKAGGLE_TEST_IMAGE_DIR = os.path.join(KAGGLE_INPUT_DIR, 'test')\nKAGGLE_MODEL_PATH = '/kaggle/input/gwhd-2020-best-weights-ever/FinalBestExtraData.pt' \n\nKAGGLE_WORKING_DIR = '/kaggle/working'\nKAGGLE_OUTPUT_SUBMISSION_FILE = os.path.join(KAGGLE_WORKING_DIR, 'submission.csv')\n\nIMAGE_WIDTH = 1024.0\nIMAGE_HEIGHT = 1024.0\n\n\nBASE_PREDICT_CONF = 0.01 \nWBF_IOU_THR = 0.55\nWBF_SKIP_BOX_THR = 0.25\nFINAL_SCORE_THR = 0.12\n\nprint(f\"Kaggle Test Image Dir: {KAGGLE_TEST_IMAGE_DIR}\")\nprint(f\"Kaggle Model Path: {KAGGLE_MODEL_PATH}\")\nprint(f\"Kaggle Submission File Path: {KAGGLE_OUTPUT_SUBMISSION_FILE}\")\nprint(f\"Using WBF IoU Thr: {WBF_IOU_THR}, WBF Skip Box Thr: {WBF_SKIP_BOX_THR}, Final Score Thr: {FINAL_SCORE_THR}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-27T15:09:25.198475Z","iopub.execute_input":"2025-05-27T15:09:25.198849Z","iopub.status.idle":"2025-05-27T15:09:25.204403Z","shell.execute_reply.started":"2025-05-27T15:09:25.198827Z","shell.execute_reply":"2025-05-27T15:09:25.203783Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# --- Helper Function for Box Conversion (same as before) ---\ndef yolo_normalized_xyxyn_to_submission_xywh(norm_boxes_xyxy, scores, img_w, img_h):\n    prediction_strings = []\n    for i in range(len(norm_boxes_xyxy)):\n        nx1, ny1, nx2, ny2 = norm_boxes_xyxy[i]\n        conf = scores[i]\n        x1_abs = nx1 * img_w; y1_abs = ny1 * img_h\n        x2_abs = nx2 * img_w; y2_abs = ny2 * img_h\n        abs_w = x2_abs - x1_abs; abs_h = y2_abs - y1_abs\n        x_min_final = max(0, int(round(x1_abs))); y_min_final = max(0, int(round(y1_abs)))\n        w_final = int(round(abs_w)); h_final = int(round(abs_h))\n        if x_min_final + w_final > img_w: w_final = int(img_w - x_min_final)\n        if y_min_final + h_final > img_h: h_final = int(img_h - y_min_final)\n        w_final = max(1, w_final); h_final = max(1, h_final)\n        prediction_strings.append(f\"{conf:.4f} {x_min_final} {y_min_final} {w_final} {h_final}\")\n    return prediction_strings\n\n# --- Main Logic (with TTA and WBF, same structure as before) ---\nsubmission_data = []\ntest_image_files = []\n\ntry:\n    model = YOLO(KAGGLE_MODEL_PATH)\n    print(\"Model loaded.\")\n\n    if os.path.exists(KAGGLE_TEST_IMAGE_DIR):\n        test_image_files = [f for f in os.listdir(KAGGLE_TEST_IMAGE_DIR) if f.lower().endswith(('.png', '.jpg', '.jpeg'))]\n    else:\n        print(f\"ERROR: Test image directory not found at {KAGGLE_TEST_IMAGE_DIR}\")\n\n    print(f\"Found {len(test_image_files)} images to process for submission.\")\n\n    for image_filename in tqdm(test_image_files, desc=\"Processing test images\"):\n        image_id = os.path.splitext(image_filename)[0]\n        img_path = os.path.join(KAGGLE_TEST_IMAGE_DIR, image_filename)\n        \n        tta_boxes_list_norm = [] \n        tta_scores_list = []   \n        tta_labels_list = []   \n\n        try:\n            img_bgr = cv2.imread(img_path)\n            if img_bgr is None:\n                print(f\"Warning: Failed to load image {img_path}. Appending empty prediction.\")\n                submission_data.append({'image_id': image_id, 'PredictionString': \"\"})\n                continue\n\n            img_resized_bgr = cv2.resize(img_bgr, (int(IMAGE_WIDTH), int(IMAGE_HEIGHT)))\n\n            for tta_idx in range(2): # 0: original, 1: hflip\n                img_to_predict = img_resized_bgr.copy()\n                if tta_idx == 1: \n                    img_to_predict = cv2.flip(img_to_predict, 1)\n\n                individual_results = model.predict(source=img_to_predict, imgsz=int(IMAGE_WIDTH), conf=BASE_PREDICT_CONF, verbose=False)\n                \n                current_tta_boxes_norm = []\n                current_tta_scores = []\n                \n                if individual_results and individual_results[0].boxes:\n                    norm_boxes_xyxy_tta_space = individual_results[0].boxes.xyxyn.cpu().numpy() \n                    confs = individual_results[0].boxes.conf.cpu().numpy()\n\n                    for i in range(len(norm_boxes_xyxy_tta_space)):\n                        nx1, ny1, nx2, ny2 = norm_boxes_xyxy_tta_space[i]\n                        if tta_idx == 1: \n                            nx1_orig = 1.0 - nx2; nx2_orig = 1.0 - nx1\n                            current_tta_boxes_norm.append([nx1_orig, ny1, nx2_orig, ny2])\n                        else: \n                            current_tta_boxes_norm.append([nx1, ny1, nx2, ny2])\n                        current_tta_scores.append(confs[i])\n                \n                if current_tta_boxes_norm: \n                    tta_boxes_list_norm.append(current_tta_boxes_norm)\n                    tta_scores_list.append(current_tta_scores)\n                    tta_labels_list.append([0] * len(current_tta_scores))\n            \n            final_prediction_string_parts = []\n            if tta_boxes_list_norm: \n                fused_boxes_norm, fused_scores, _ = weighted_boxes_fusion(\n                    tta_boxes_list_norm, tta_scores_list, tta_labels_list,\n                    iou_thr=WBF_IOU_THR, skip_box_thr=WBF_SKIP_BOX_THR\n                )\n                indices = fused_scores >= FINAL_SCORE_THR\n                final_fused_boxes_norm_filtered = fused_boxes_norm[indices]\n                final_fused_scores_filtered = fused_scores[indices]\n                \n                if len(final_fused_boxes_norm_filtered) > 0:\n                    final_prediction_string_parts = yolo_normalized_xyxyn_to_submission_xywh(\n                        final_fused_boxes_norm_filtered, final_fused_scores_filtered, IMAGE_WIDTH, IMAGE_HEIGHT\n                    )\n            \n            full_prediction_string = \" \".join(final_prediction_string_parts)\n            submission_data.append({'image_id': image_id, 'PredictionString': full_prediction_string})\n\n        except Exception as e_img_process:\n            print(f\"Error processing image {image_filename}: {e_img_process}\")\n            submission_data.append({'image_id': image_id, 'PredictionString': \"\"})\n\nexcept Exception as e_main:\n    print(f\"A critical error occurred in the main processing block: {e_main}\")\n    submission_data = [] \n\nfinally:\n    print(\"\\nExecuting finally block to ensure submission file is written.\")\n    if not submission_data and test_image_files:\n        print(\"INFO (finally): submission_data is empty but test_image_files were found. Populating with empty predictions.\")\n        for image_filename in test_image_files:\n            image_id = os.path.splitext(image_filename)[0]\n            if not any(d['image_id'] == image_id for d in submission_data):\n                submission_data.append({'image_id': image_id, 'PredictionString': \"\"})\n    \n    print(f\"INFO (finally): Number of records in submission_data before creating DataFrame: {len(submission_data)}\")\n    submission_df = pd.DataFrame(submission_data)\n\n    if not submission_df.empty:\n        print(f\"INFO (finally): Attempting to write submission_df (shape: {submission_df.shape}) to {KAGGLE_OUTPUT_SUBMISSION_FILE}\")\n        try:\n            submission_df.to_csv(KAGGLE_OUTPUT_SUBMISSION_FILE, index=False)\n            print(f\"INFO (finally): Successfully wrote submission_df to {KAGGLE_OUTPUT_SUBMISSION_FILE}\")\n            if os.path.exists(KAGGLE_OUTPUT_SUBMISSION_FILE):\n                print(f\"INFO (finally): File {KAGGLE_OUTPUT_SUBMISSION_FILE} confirmed to exist after writing.\")\n            else:\n                print(f\"CRITICAL_ERROR (finally): File {KAGGLE_OUTPUT_SUBMISSION_FILE} NOT FOUND after attempting to write submission_df!\")\n        except Exception as e_csv:\n            print(f\"CRITICAL_ERROR (finally): Failed to write submission_df to CSV: {e_csv}\")\n    else:\n        print(\"INFO (finally): submission_df is empty. Attempting to create fallback submission file.\")\n        sample_submission_path = os.path.join(KAGGLE_INPUT_DIR, 'sample_submission.csv')\n        if os.path.exists(sample_submission_path):\n            try:\n                sample_df = pd.read_csv(sample_submission_path)\n                empty_predictions = [{'image_id': img_id, 'PredictionString': \"\"} for img_id in sample_df['image_id']]\n                final_empty_df = pd.DataFrame(empty_predictions)\n                print(f\"INFO (finally): Attempting to write fallback (from sample) to {KAGGLE_OUTPUT_SUBMISSION_FILE}\")\n                final_empty_df.to_csv(KAGGLE_OUTPUT_SUBMISSION_FILE, index=False)\n                print(f\"INFO (finally): Successfully wrote fallback (from sample) to {KAGGLE_OUTPUT_SUBMISSION_FILE}\")\n            except Exception as e_sample:\n                print(f\"CRITICAL_ERROR (finally): Error with sample_submission fallback: {e_sample}. Creating header-only file.\")\n                pd.DataFrame(columns=['image_id', 'PredictionString']).to_csv(KAGGLE_OUTPUT_SUBMISSION_FILE, index=False)\n        else:\n            print(\"INFO (finally): sample_submission.csv not found. Creating header-only submission file.\")\n            pd.DataFrame(columns=['image_id', 'PredictionString']).to_csv(KAGGLE_OUTPUT_SUBMISSION_FILE, index=False)\n            print(f\"INFO (finally): Successfully wrote header-only file to {KAGGLE_OUTPUT_SUBMISSION_FILE}\")\n\n    if os.path.exists(KAGGLE_OUTPUT_SUBMISSION_FILE):\n        print(f\"FINAL_CONFIRMATION: {KAGGLE_OUTPUT_SUBMISSION_FILE} exists at the end of the finally block.\")\n    else:\n        print(f\"FINAL_CRITICAL_ERROR: {KAGGLE_OUTPUT_SUBMISSION_FILE} DOES NOT EXIST at the end of the finally block.\")\n        \n    print(\"\\nNotebook execution finished (from finally block).\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-27T15:09:25.205289Z","iopub.execute_input":"2025-05-27T15:09:25.206007Z","iopub.status.idle":"2025-05-27T15:09:38.219402Z","shell.execute_reply.started":"2025-05-27T15:09:25.205981Z","shell.execute_reply":"2025-05-27T15:09:38.218492Z"}},"outputs":[],"execution_count":null}]}