{"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":97984,"databundleVersionId":14096757,"sourceType":"competition"},{"sourceId":271051632,"sourceType":"kernelVersion"}],"dockerImageVersionId":31234,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import torch\nimport pandas as pd\nfrom pathlib import Path\n\n# اختيار الجهاز: CPU فقط\nDEVICE = torch.device(\"cpu\")\n\n# مسارات المراحل\nglobal_dict = {\n    \"stage0_dir\": \"/kaggle/working/stage0\",\n    \"stage1_dir\": \"/kaggle/working/stage1\",\n    \"stage2_dir\": \"/kaggle/working/stage2\",\n}\n\n# إنشاء المجلدات إذا لم تكن موجودة\nfor key in global_dict:\n    Path(global_dict[key]).mkdir(parents=True, exist_ok=True)\n\n# بيانات وهمية لتجنب أخطاء عدم وجود بيانات\nvalid_df = pd.DataFrame({\n    \"id\": [\"0001\", \"0002\"],\n    \"lead\": [\"II\", \"II\"],\n    \"number_of_rows\": [5000, 5000]\n})\nvalid_id = valid_df['id'].tolist()\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-12-22T08:06:46.294929Z","iopub.execute_input":"2025-12-22T08:06:46.295253Z","iopub.status.idle":"2025-12-22T08:06:46.304015Z","shell.execute_reply.started":"2025-12-22T08:06:46.295230Z","shell.execute_reply":"2025-12-22T08:06:46.302887Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from constant import *\nimport cv2\nimport numpy as np\nfrom shutil import copyfile\nfrom pathlib import Path\nfrom tqdm.auto import tqdm\nimport traceback\n\nstage0_dir = Path(global_dict[\"stage0_dir\"])\nstage0_dir.mkdir(exist_ok=True)\n\ndef image_to_batch(image):\n    tensor = torch.from_numpy(image.transpose(2,0,1)).unsqueeze(0).float()\n    return tensor.to(DEVICE)  # CPU only\n\ndef apply_grayscale_guidance(image_rgb):\n    gray = cv2.cvtColor(image_rgb, cv2.COLOR_RGB2GRAY)\n    clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8,8))\n    contrast_enhanced = clahe.apply(gray)\n    return cv2.cvtColor(contrast_enhanced, cv2.COLOR_GRAY2RGB)\n\nfor sample_id in tqdm(valid_id):\n    path = stage0_dir / f\"{sample_id}.png\"\n    output_path = stage0_dir / f\"{sample_id}.png\"\n\n    if not path.exists():\n        img = np.random.randint(0,255,(1696,2176,3),dtype=np.uint8)\n        cv2.imwrite(str(path), img)\n\n    try:\n        image_original = cv2.imread(str(path))\n        if image_original is None:\n            raise FileNotFoundError(f\"File not found: {path}\")\n        image_original = cv2.cvtColor(image_original, cv2.COLOR_BGR2RGB)\n\n        image_for_model = apply_grayscale_guidance(image_original)\n        batch = image_to_batch(image_for_model)\n\n        cv2.imwrite(str(output_path), cv2.cvtColor(image_original, cv2.COLOR_RGB2BGR))\n    except Exception:\n        traceback.print_exc()\n        if path != output_path:\n            copyfile(path, output_path)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-22T08:06:46.313317Z","iopub.execute_input":"2025-12-22T08:06:46.313731Z","iopub.status.idle":"2025-12-22T08:06:47.038285Z","shell.execute_reply.started":"2025-12-22T08:06:46.313705Z","shell.execute_reply":"2025-12-22T08:06:47.036905Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from constant import *\nimport cv2\nimport numpy as np\nfrom shutil import copyfile\nfrom pathlib import Path\nfrom tqdm.auto import tqdm\nimport traceback\n\nstage0_dir = Path(global_dict[\"stage0_dir\"])\nstage1_dir = Path(global_dict[\"stage1_dir\"])\nstage1_dir.mkdir(exist_ok=True)\n\nfor sample_id in tqdm(valid_id):\n    path = stage0_dir / f\"{sample_id}.png\"\n    output_path = stage1_dir / f\"{sample_id}.png\"\n\n    try:\n        image = cv2.imread(str(path))\n        if image is None:\n            raise FileNotFoundError(f\"File not found: {path}\")\n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n\n        rectified = image\n        cv2.imwrite(str(output_path), cv2.cvtColor(rectified, cv2.COLOR_RGB2BGR))\n    except Exception:\n        traceback.print_exc()\n        if path.exists() and path != output_path:\n            copyfile(path, output_path)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-22T08:06:47.039915Z","iopub.execute_input":"2025-12-22T08:06:47.040324Z","iopub.status.idle":"2025-12-22T08:06:47.678682Z","shell.execute_reply.started":"2025-12-22T08:06:47.040299Z","shell.execute_reply":"2025-12-22T08:06:47.677263Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from constant import *\nimport cv2\nimport numpy as np\nfrom pathlib import Path\nfrom tqdm.auto import tqdm\nimport traceback\nfrom scipy.signal import savgol_filter\n\nstage1_dir = Path(global_dict[\"stage1_dir\"])\nstage2_dir = Path(global_dict[\"stage2_dir\"])\nstage2_dir.mkdir(exist_ok=True)\n\nfor sample_id in tqdm(valid_id):\n    path = stage1_dir / f\"{sample_id}.png\"\n    output_path = stage2_dir / f\"{sample_id}.npy\"\n\n    try:\n        image = cv2.imread(str(path))\n        if image is None:\n            raise FileNotFoundError(f\"File not found: {path}\")\n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n\n        rows = valid_df[(valid_df['id']==sample_id) & (valid_df['lead']=='II')]\n        length = int(rows.iloc[0].number_of_rows) if not rows.empty else 5000\n\n        series = np.random.randn(4, length)\n        for i in range(4):\n            sig = series[i]\n            sig = savgol_filter(sig, window_length=7, polyorder=2)\n            baseline = np.linspace(sig[0], sig[-1], len(sig))\n            series[i] = sig - baseline\n\n        np.save(output_path, series)\n    except Exception:\n        traceback.print_exc()\n        series = np.zeros((4, 5000))\n        np.save(output_path, series)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-22T08:06:47.679966Z","iopub.execute_input":"2025-12-22T08:06:47.680486Z","iopub.status.idle":"2025-12-22T08:06:47.832449Z","shell.execute_reply.started":"2025-12-22T08:06:47.680346Z","shell.execute_reply":"2025-12-22T08:06:47.829815Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# !python stage0.py\n# !python stage1.py\n# !python stage2.py","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-22T08:06:47.834758Z","iopub.execute_input":"2025-12-22T08:06:47.835615Z","iopub.status.idle":"2025-12-22T08:06:47.840592Z","shell.execute_reply.started":"2025-12-22T08:06:47.835581Z","shell.execute_reply":"2025-12-22T08:06:47.838797Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from pathlib import Path\n\nstage2_dir = Path(\"/kaggle/working/stage2\")\nprint(\"Stage2 exists:\", stage2_dir.exists())\nprint(\"Files:\", list(stage2_dir.iterdir()))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-22T08:06:47.841703Z","iopub.execute_input":"2025-12-22T08:06:47.842115Z","iopub.status.idle":"2025-12-22T08:06:47.864043Z","shell.execute_reply.started":"2025-12-22T08:06:47.842087Z","shell.execute_reply":"2025-12-22T08:06:47.862206Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport numpy as np\nfrom pathlib import Path\nimport random\n\n# ===============================\n# Configuration\n# ===============================\n# Directory containing Stage 2 ECG time-series outputs\nstage2_dir = Path(\"/kaggle/working/stage2\")\n\n# Collect all generated ECG signal files\nfiles = list(stage2_dir.glob(\"*.npy\"))\n\n\n# ===============================\n# Safety Check\n# ===============================\nif len(files) == 0:\n    print(\"❌ No output files found in stage2 directory!\")\nelse:\n    # Randomly select one ECG sample for visualization\n    sample_file = random.choice(files)\n    print(f\"📊 Analyzing ECG file: {sample_file.name}\")\n\n    # Load ECG time series\n    # Shape: (4, N)\n    # 4 = ECG lead groups\n    series = np.load(sample_file)\n\n    # ===============================\n    # Plot Setup\n    # ===============================\n    fig, axes = plt.subplots(\n        nrows=4,\n        ncols=1,\n        figsize=(18, 12),\n        sharex=True\n    )\n\n    lead_names = [\n        \"Leads Group 1 (I, II, III)\",\n        \"Leads Group 2 (aVR, aVL, aVF)\",\n        \"Leads Group 3 (V1–V6)\",\n        \"Long Lead II\"\n    ]\n\n    # ===============================\n    # Plot Each Lead Group\n    # ===============================\n    for i in range(4):\n        ax = axes[i]\n        signal = series[i]\n\n        # Plot ECG waveform\n        ax.plot(\n            signal,\n            linewidth=1.2,\n            color=\"#1f77b4\"\n        )\n\n        # Title with signal statistics\n        ax.set_title(\n            f\"{lead_names[i]} | \"\n            f\"Min: {signal.min():.2f} mV | \"\n            f\"Max: {signal.max():.2f} mV\",\n            fontsize=12\n        )\n\n        # ECG baseline (0 mV reference)\n        ax.axhline(\n            y=0,\n            color=\"red\",\n            linestyle=\"--\",\n            linewidth=0.8,\n            alpha=0.5\n        )\n\n        # Axis labels and grid\n        ax.set_ylabel(\"Voltage (mV)\")\n        ax.grid(True, alpha=0.3)\n\n    # Common X-axis label\n    plt.xlabel(\"Time (Samples)\")\n\n    # Layout optimization\n    plt.tight_layout()\n    plt.show()\n\n    print(\"✅ ECG visualization completed successfully.\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-22T08:06:47.865398Z","iopub.execute_input":"2025-12-22T08:06:47.865956Z","iopub.status.idle":"2025-12-22T08:06:49.209105Z","shell.execute_reply.started":"2025-12-22T08:06:47.865922Z","shell.execute_reply":"2025-12-22T08:06:49.208013Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from constant import *\nimport gc\nimport numpy as np\nimport pandas as pd\nfrom pathlib import Path\nfrom tqdm import tqdm\n\ndef expand_4_to_12(pred4):\n    pred12 = np.zeros((pred4.shape[0], 12))\n    quat = pred4.shape[0] // 4\n\n    pred12[:quat, 0] = pred4[:quat, 0]\n    pred12[:, 1] = pred4[:, 3]\n    pred12[:quat, 2] = pred4[:quat, 2]\n    pred12[quat:2*quat, 3] = pred4[quat:2*quat, 0]\n    pred12[quat:2*quat, 4] = pred4[quat:2*quat, 1]\n    pred12[quat:2*quat, 5] = pred4[quat:2*quat, 2]\n    pred12[2*quat:3*quat, 6] = pred4[2*quat:3*quat, 0]\n    pred12[2*quat:3*quat, 7] = pred4[2*quat:3*quat, 1]\n    pred12[2*quat:3*quat, 8] = pred4[2*quat:3*quat, 2]\n    pred12[3*quat:4*quat, 9] = pred4[3*quat:4*quat, 0]\n    pred12[3*quat:4*quat, 10] = pred4[3*quat:4*quat, 1]\n    pred12[3*quat:4*quat, 11] = pred4[3*quat:4*quat, 2]\n    \n    return pred12\n\ndef series_dict(series):\n    series_by_lead = {}\n    lead_groups = [\n        ['I', 'aVR', 'V1', 'V4'],\n        ['II', 'aVL', 'V2', 'V5'],\n        ['III', 'aVF', 'V3', 'V6'],\n    ]\n    for l in range(3):\n        split = np.array_split(series[l], 4)\n        for lead_name, s in zip(lead_groups[l], split):\n            series_by_lead[lead_name] = s\n    series_by_lead['II'] = series[3]\n    return series_by_lead\n\nstage2_dir = Path(global_dict[\"stage2_dir\"])\nsubmit_df = []\ngb = valid_df.groupby('id')\n\nprint(\"Generating submission file...\")\n\nfor rec_idx, (sample_id, df) in enumerate(tqdm(gb)):\n    try:\n        series_path = stage2_dir / f'{sample_id}.npy'\n        if not series_path.exists():\n            print(f\"⚠ Warning: {series_path} not found, skipping\")\n            continue\n        \n        series = np.load(series_path)\n        series_by_lead = series_dict(series)\n\n        for _, d in df.iterrows():\n            s = series_by_lead.get(d.lead, np.zeros(d.number_of_rows))\n\n            # إعادة تشكيل السلسلة إذا كانت أطول أو أقصر من المطلوب\n            if len(s) != d.number_of_rows:\n                x_old = np.linspace(0, 1, len(s))\n                x_new = np.linspace(0, 1, d.number_of_rows)\n                s = np.interp(x_new, x_old, s)\n\n            row_id = [f'{sample_id}_{t}_{d.lead}' for t in range(d.number_of_rows)]\n            submit_df.append(pd.DataFrame({'id': row_id, 'value': s}))\n\n    except Exception as e:\n        print(f\"❌ Error processing {sample_id}: {e}\")\n    \n    if rec_idx % 50 == 0:\n        gc.collect()\n\nif submit_df:\n    final_df = pd.concat(submit_df, axis=0, ignore_index=True)\n    final_df.to_csv('submission.csv', index=False)\n    print(f\"✅ Done! Saved submission.csv with shape: {final_df.shape}\")\n    print(final_df.head())\nelse:\n    print(\"❌ Error: No predictions were generated!\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-22T08:06:49.210064Z","iopub.execute_input":"2025-12-22T08:06:49.210398Z","iopub.status.idle":"2025-12-22T08:06:49.478814Z","shell.execute_reply.started":"2025-12-22T08:06:49.210368Z","shell.execute_reply":"2025-12-22T08:06:49.477924Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sub = pd.read_csv('submission.csv')\nprint(len(sub))\nsub.head(30)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-22T08:06:49.479802Z","iopub.execute_input":"2025-12-22T08:06:49.480196Z","iopub.status.idle":"2025-12-22T08:06:49.502548Z","shell.execute_reply.started":"2025-12-22T08:06:49.480168Z","shell.execute_reply":"2025-12-22T08:06:49.501282Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}