{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":129750,"databundleVersionId":15563344,"isSourceIdPinned":false,"sourceType":"competition"},{"sourceId":14851400,"sourceType":"datasetVersion","datasetId":9499320},{"sourceId":297676757,"sourceType":"kernelVersion"}],"dockerImageVersionId":31261,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# Install Ultralytics (YOLO)\n!pip install -q ultralytics\nimport os\nimport pandas as pd\nimport numpy as np\nfrom ultralytics import YOLO\nimport yaml\nfrom tqdm.notebook import tqdm","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-15T19:57:51.590524Z","iopub.execute_input":"2026-02-15T19:57:51.590709Z","iopub.status.idle":"2026-02-15T19:58:04.943536Z","shell.execute_reply.started":"2026-02-15T19:57:51.590689Z","shell.execute_reply":"2026-02-15T19:58:04.942913Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"yolo_model = YOLO(\"/kaggle/input/datasets/lightningv08/dal-shemagh-yolo-models/yolo11n50.pt\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-15T20:00:34.615726Z","iopub.execute_input":"2026-02-15T20:00:34.616817Z","iopub.status.idle":"2026-02-15T20:00:34.768522Z","shell.execute_reply.started":"2026-02-15T20:00:34.616768Z","shell.execute_reply":"2026-02-15T20:00:34.767891Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import glob\n\n# 2. Пути к тестовым изображениям\ntest_images = glob.glob('/kaggle/input/competitions/dal-shemagh-detection-challenge/images/test/*.jpg')\nsubmission_data = []\n\n# 3. Функция расчёта IoU (без изменений)\ndef calculate_iou(box1, box2):\n    \"\"\"\n    box1, box2: [x, y, w, h] в относительных координатах (0..1)\n    \"\"\"\n    b1_x1, b1_x2 = box1[0] - box1[2]/2, box1[0] + box1[2]/2\n    b1_y1, b1_y2 = box1[1] - box1[3]/2, box1[1] + box1[3]/2\n    b2_x1, b2_x2 = box2[0] - box2[2]/2, box2[0] + box2[2]/2\n    b2_y1, b2_y2 = box2[1] - box2[3]/2, box2[1] + box2[3]/2\n\n    inter_x1 = max(b1_x1, b2_x1)\n    inter_y1 = max(b1_y1, b2_y1)\n    inter_x2 = min(b1_x2, b2_x2)\n    inter_y2 = min(b1_y2, b2_y2)\n\n    inter_area = max(0, inter_x2 - inter_x1) * max(0, inter_y2 - inter_y1)\n    b1_area = (b1_x2 - b1_x1) * (b1_y2 - b1_y1)\n    b2_area = (b2_x2 - b2_x1) * (b2_y2 - b2_y1)\n    union_area = b1_area + b2_area - inter_area\n    return inter_area / union_area if union_area > 0 else 0\n\n# 4. Основной цикл инференса\nprint(f\"Обрабатывается {len(test_images)} изображений...\")\n\nfor img_path in tqdm(test_images):\n    filename = os.path.basename(img_path)\n\n    # Инференс\n    results = yolo_model.predict(img_path, conf=0.25, verbose=False)[0]\n\n    prediction_strings = []\n    person_boxes = []\n    shemagh_boxes = []\n\n    if len(results.boxes) == 0:\n        prediction_str = \"-\"\n        right_place = 0\n    else:\n        for box in results.boxes:\n            cls = int(box.cls[0])\n            conf = float(box.conf[0])\n            x, y, w, h = box.xywhn[0].tolist()\n\n            prediction_strings.append(f\"{cls} {conf:.4f} {x:.4f} {y:.4f} {w:.4f} {h:.4f}\")\n\n            if cls == 0:\n                person_boxes.append([x, y, w, h])\n            elif cls == 1:\n                shemagh_boxes.append([x, y, w, h])\n\n        prediction_str = \" \".join(prediction_strings)\n\n        # ---------- УЛУЧШЕННАЯ ЛОГИКА right_place (минимальные изменения) ----------\n        right_place = 0\n        if person_boxes and shemagh_boxes:\n            best_iou = 0.0\n            best_pair = None\n\n            # 1. Ищем наилучшую пару (человек, платок) по IoU\n            for p_idx, p_box in enumerate(person_boxes):\n                for s_idx, s_box in enumerate(shemagh_boxes):\n                    iou = calculate_iou(p_box, s_box)  # порядок не важен\n                    if iou > best_iou:\n                        best_iou = iou\n                        best_pair = (p_idx, s_idx)\n\n            if best_pair is not None:\n                p_box = person_boxes[best_pair[0]]\n                s_box = shemagh_boxes[best_pair[1]]\n\n                # 2. Критерии правильного размещения\n                iou_threshold = 0.02        # можно подобрать (0.07..0.15)\n                vertical_threshold = 0.0    # центр платка выше центра человека (y↑ вниз, значит s_y < p_y)\n                min_area_ratio = 0.4\n\n                iou_ok = best_iou > iou_threshold\n                vertical_ok = s_box[1] < p_box[1] - vertical_threshold\n                area_ratio = (s_box[2] * s_box[3]) / (p_box[2] * p_box[3])\n                size_ok = area_ratio > min_area_ratio\n\n                # Итоговое решение: IoU + вертикальное положение (можно добавить size_ok при необходимости)\n                if iou_ok and size_ok:   # и, опционально, size_ok\n                    right_place = 1\n        # --------------------------------------------------------------------------\n\n    submission_data.append([filename, right_place, prediction_str])\n\n# 5. Сохранение результата\ndf_sub = pd.DataFrame(submission_data, columns=['filename', 'right_place', 'prediction_string'])\ndf_sub.to_csv('submission.csv', index=False)\n\nprint(\"submission.csv успешно создан!\")\nprint(df_sub.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-15T20:00:34.769759Z","iopub.execute_input":"2026-02-15T20:00:34.770034Z","iopub.status.idle":"2026-02-15T20:00:46.900044Z","shell.execute_reply.started":"2026-02-15T20:00:34.770008Z","shell.execute_reply":"2026-02-15T20:00:46.899303Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}