{"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":113558,"databundleVersionId":14878066,"sourceType":"competition"}],"dockerImageVersionId":31192,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# EDA","metadata":{}},{"cell_type":"code","source":"import os\nimport numpy as np\nimport cv2\nimport matplotlib.pyplot as plt\nfrom glob import glob\nfrom skimage.measure import label, regionprops\nimport seaborn as sns\nimport pandas as pd\nimport random\nfrom skimage import exposure  \n\n\nsns.set(style='whitegrid')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-17T15:55:40.880432Z","iopub.execute_input":"2025-12-17T15:55:40.880859Z","iopub.status.idle":"2025-12-17T15:55:40.887988Z","shell.execute_reply.started":"2025-12-17T15:55:40.880818Z","shell.execute_reply":"2025-12-17T15:55:40.887064Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"BASE_DIR = \"/kaggle/input/recodai-luc-scientific-image-forgery-detection\"\ntrain_image_paths = sorted(glob(os.path.join(BASE_DIR, \"train_images\", \"*\", \"*.png\")))\ntrain_mask_paths = sorted(glob(os.path.join(BASE_DIR, \"train_masks\", \"*.npy\")))\ntest_image_paths = sorted(glob(os.path.join(BASE_DIR, \"test_images\", \"*\", \"*.png\")))\nprint(f\"Train images: {len(train_image_paths)}, Train masks: {len(train_mask_paths)}\")\nprint(f\"Test images: {len(test_image_paths)}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-17T15:55:40.896631Z","iopub.execute_input":"2025-12-17T15:55:40.896942Z","iopub.status.idle":"2025-12-17T15:55:40.933710Z","shell.execute_reply.started":"2025-12-17T15:55:40.896919Z","shell.execute_reply":"2025-12-17T15:55:40.932847Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def get_id(path):\n    return os.path.splitext(os.path.basename(path))[0]\n\nmask_map = {get_id(p): p for p in train_mask_paths}","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-17T15:55:40.935053Z","iopub.execute_input":"2025-12-17T15:55:40.935371Z","iopub.status.idle":"2025-12-17T15:55:40.946431Z","shell.execute_reply.started":"2025-12-17T15:55:40.935346Z","shell.execute_reply":"2025-12-17T15:55:40.945524Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"pairs = []\nfor img_path in train_image_paths:\n    cid = get_id(img_path)\n    if cid in mask_map:\n        mask_path = mask_map[cid]\n        has_forgery = True\n    else:\n        mask_path = None\n        has_forgery = False\n    pairs.append({\"img_path\": img_path, \"mask_path\": mask_path, \"has_forgery\": has_forgery})","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-17T15:55:40.947381Z","iopub.execute_input":"2025-12-17T15:55:40.947647Z","iopub.status.idle":"2025-12-17T15:55:40.977943Z","shell.execute_reply.started":"2025-12-17T15:55:40.947605Z","shell.execute_reply":"2025-12-17T15:55:40.976932Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"total_train = len(pairs)\nforged_count = sum(p['has_forgery'] for p in pairs)\nauthentic_count = total_train - forged_count\nauth_ratio = authentic_count / total_train if total_train > 0 else 0\n\nprint(f\"Total train images: {total_train}\")\nprint(f\"Forged images: {forged_count} ({forged_count / total_train:.2%})\")\nprint(f\"Authentic images: {authentic_count} ({auth_ratio:.2%})\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-17T15:55:40.979589Z","iopub.execute_input":"2025-12-17T15:55:40.979971Z","iopub.status.idle":"2025-12-17T15:55:41.002066Z","shell.execute_reply.started":"2025-12-17T15:55:40.979948Z","shell.execute_reply":"2025-12-17T15:55:41.001166Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"labels = ['Forged', 'Authentic']\nsizes = [forged_count, authentic_count]\ncolors = ['#ff9999', '#66b3ff']\nplt.figure(figsize=(6, 6))\nplt.pie(sizes, labels=labels, colors=colors, autopct='%1.1f%%', startangle=90)\nplt.title('Class Distribution in Train Set')\nplt.axis('equal')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-17T15:55:41.003003Z","iopub.execute_input":"2025-12-17T15:55:41.003249Z","iopub.status.idle":"2025-12-17T15:55:41.126146Z","shell.execute_reply.started":"2025-12-17T15:55:41.003229Z","shell.execute_reply":"2025-12-17T15:55:41.125275Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def load_mask(mask_path, img_shape):\n    H, W = img_shape[:2]\n    if H == 0 or W == 0:\n        return np.zeros((0, 0), dtype=np.uint8)\n    if mask_path is None:\n        return np.zeros((H, W), dtype=np.uint8)\n    try:\n        mask = np.load(mask_path)\n    except Exception as e:\n        print(f\"Error loading mask {mask_path}: {e}\")\n        return np.zeros((H, W), dtype=np.uint8)\n    if mask.size == 0:\n        return np.zeros((H, W), dtype=np.uint8)\n    if mask.ndim == 1 or mask.size != H * W:\n        return np.zeros((H, W), dtype=np.uint8)\n    else:\n        try:\n            mask = mask.reshape((H, W))\n        except:\n            return np.zeros((H, W), dtype=np.uint8)\n    mask = (mask > 0).astype(np.uint8)\n    return mask","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-17T15:55:41.127369Z","iopub.execute_input":"2025-12-17T15:55:41.127718Z","iopub.status.idle":"2025-12-17T15:55:41.138162Z","shell.execute_reply.started":"2025-12-17T15:55:41.127690Z","shell.execute_reply":"2025-12-17T15:55:41.137196Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"fg_ratios = []\nn_components = []\nimage_shapes = []  # (H, W, C)\nis_grayscale = []    \nmean_intensity = []   \n\nfor p in pairs:\n    img = cv2.imread(p[\"img_path\"])\n    if img is None or img.shape[0] == 0 or img.shape[1] == 0:\n        continue\n    image_shapes.append(img.shape)\n    \n  \n    if len(img.shape) == 2 or np.all(img[:,:,0] == img[:,:,1]) and np.all(img[:,:,1] == img[:,:,2]):\n        is_grayscale.append(True)\n        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n    else:\n        is_grayscale.append(False)\n        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n    \n\n    mean_intensity.append(np.mean(gray))\n    \n    if p[\"has_forgery\"]:\n        mask = load_mask(p[\"mask_path\"], img.shape)\n        fg_ratios.append(mask.mean())\n        labeled = label(mask)\n        props = regionprops(labeled)\n        n_components.append(len(props))\n\n\ndf_stats = pd.DataFrame({\n    'Foreground Ratio': fg_ratios,\n    'Num Components': n_components\n})\nprint(\"\\nSummary Stats for Forged Images:\")\nprint(df_stats.describe())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-17T15:55:41.140541Z","iopub.execute_input":"2025-12-17T15:55:41.141132Z","iopub.status.idle":"2025-12-17T16:00:47.378602Z","shell.execute_reply.started":"2025-12-17T15:55:41.141101Z","shell.execute_reply":"2025-12-17T16:00:47.377643Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.figure(figsize=(12, 5))\nsns.histplot(fg_ratios, bins=50, kde=True, color='red')\nplt.title(\"Distribution of Foreground Ratios in Forged Images\")\nplt.xlabel(\"Foreground Ratio\")\nplt.ylabel(\"Count\")\nplt.show()\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-17T16:00:47.380004Z","iopub.execute_input":"2025-12-17T16:00:47.380708Z","iopub.status.idle":"2025-12-17T16:00:47.759451Z","shell.execute_reply.started":"2025-12-17T16:00:47.380674Z","shell.execute_reply":"2025-12-17T16:00:47.758507Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#  num components\nplt.figure(figsize=(12, 5))\nsns.histplot(n_components, bins=20, kde=True, color='blue')\nplt.title(\"Distribution of Number of Connected Components in Forged Images\")\nplt.xlabel(\"Number of Components\")\nplt.ylabel(\"Count\")\nplt.show()\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-17T16:00:47.760384Z","iopub.execute_input":"2025-12-17T16:00:47.760706Z","iopub.status.idle":"2025-12-17T16:00:48.111609Z","shell.execute_reply.started":"2025-12-17T16:00:47.760683Z","shell.execute_reply":"2025-12-17T16:00:48.110323Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Scatter plot\nplt.figure(figsize=(10, 6))\nsns.scatterplot(x=fg_ratios, y=n_components, alpha=0.6, color='purple')\nplt.xlabel(\"Foreground Ratio\")\nplt.ylabel(\"Number of Components\")\nplt.title(\"Forged Images: Foreground Ratio vs Number of Components\")\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-17T16:00:48.112684Z","iopub.execute_input":"2025-12-17T16:00:48.113156Z","iopub.status.idle":"2025-12-17T16:00:48.396580Z","shell.execute_reply.started":"2025-12-17T16:00:48.113120Z","shell.execute_reply":"2025-12-17T16:00:48.395725Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def get_shapes(paths):\n    shapes = []\n    for path in paths:\n        img = cv2.imread(path)\n        if img is not None:\n            shapes.append(img.shape[:2])  # (H, W)\n    return shapes\n\ntrain_shapes = get_shapes(train_image_paths)\ntest_shapes = get_shapes(test_image_paths)\n\n\ndf_train_shapes = pd.DataFrame(train_shapes, columns=['Height', 'Width'])\ndf_test_shapes = pd.DataFrame(test_shapes, columns=['Height', 'Width'])\n\nprint(\"\\nTrain Image Shapes Summary:\")\nprint(df_train_shapes.describe())\nprint(\"\\nTest Image Shapes Summary:\")\nprint(df_test_shapes.describe())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-17T16:00:48.397548Z","iopub.execute_input":"2025-12-17T16:00:48.397866Z","iopub.status.idle":"2025-12-17T16:03:57.576684Z","shell.execute_reply.started":"2025-12-17T16:00:48.397835Z","shell.execute_reply":"2025-12-17T16:03:57.575651Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.figure(figsize=(12, 5))\nsns.histplot(df_train_shapes['Height'], bins=30, kde=True, color='green', label='Height')\nsns.histplot(df_train_shapes['Width'], bins=30, kde=True, color='orange', label='Width')\nplt.title(\"Distribution of Image Dimensions in Train Set\")\nplt.xlabel(\"Pixels\")\nplt.ylabel(\"Count\")\nplt.legend()\nplt.show()\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-17T16:03:57.577873Z","iopub.execute_input":"2025-12-17T16:03:57.578220Z","iopub.status.idle":"2025-12-17T16:03:58.118107Z","shell.execute_reply.started":"2025-12-17T16:03:57.578191Z","shell.execute_reply":"2025-12-17T16:03:58.117146Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"grayscale_ratio = sum(is_grayscale) / len(is_grayscale) if len(is_grayscale) > 0 else 0\nprint(f\"Grayscale images ratio: {grayscale_ratio:.2%}\")\n\nplt.figure(figsize=(12, 5))\nsns.histplot(mean_intensity, bins=50, kde=True, color='gray')\nplt.title(\"Distribution of Mean Image Intensity\")\nplt.xlabel(\"Mean Intensity (0-255)\")\nplt.ylabel(\"Count\")\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-17T16:03:58.119136Z","iopub.execute_input":"2025-12-17T16:03:58.119381Z","iopub.status.idle":"2025-12-17T16:03:58.813212Z","shell.execute_reply.started":"2025-12-17T16:03:58.119357Z","shell.execute_reply":"2025-12-17T16:03:58.812136Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def load_mask(mask_path, img_shape):\n    H, W = img_shape[:2]\n    if H == 0 or W == 0:\n        return np.zeros((0, 0), dtype=np.uint8)\n    if mask_path is None:\n        return np.zeros((H, W), dtype=np.uint8)\n    try:\n        mask = np.load(mask_path)\n    except:\n        return np.zeros((H, W), dtype=np.uint8)\n    if mask.size == 0:\n        return np.zeros((H, W), dtype=np.uint8)\n    if mask.ndim == 1 or mask.size != H * W:\n        mask = np.zeros((H, W), dtype=np.uint8)\n    else:\n        try:\n            mask = mask.reshape((H, W))\n        except:\n            mask = np.zeros((H, W), dtype=np.uint8)\n    mask = (mask > 0).astype(np.uint8)\n    return mask","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-17T16:03:58.814072Z","iopub.execute_input":"2025-12-17T16:03:58.814317Z","iopub.status.idle":"2025-12-17T16:03:58.822632Z","shell.execute_reply.started":"2025-12-17T16:03:58.814297Z","shell.execute_reply":"2025-12-17T16:03:58.821713Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def show_samples(pairs, n=20):\n    forged_samples = [p for p in pairs if p[\"has_forgery\"]]\n    authentic_samples = [p for p in pairs if not p[\"has_forgery\"]]\n    \n    # Random sample\n    forged_selected = random.sample(forged_samples, min(n//2, len(forged_samples)))\n    authentic_selected = random.sample(authentic_samples, min(n//2, len(authentic_samples)))\n    \n    samples = forged_selected + authentic_selected\n    random.shuffle(samples)  # shuffle برای تنوع\n    \n    rows = (n + 4) // 5  # 5 در هر ردیف\n    plt.figure(figsize=(20, 4 * rows))\n    for i, p in enumerate(samples):\n        img = cv2.imread(p[\"img_path\"])\n        if img is None:\n            continue\n        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n        mask = load_mask(p[\"mask_path\"], img.shape)\n        img_to_show = img.copy()\n        if p[\"has_forgery\"]:\n            overlay = img.copy()\n            overlay[mask == 1] = [255, 0, 0]  # red overlay\n            img_to_show = cv2.addWeighted(img, 0.7, overlay, 0.3, 0)\n        plt.subplot(rows, 5, i + 1)\n        plt.imshow(img_to_show)\n        plt.axis(\"off\")\n        plt.title(f\"{'Forged' if p['has_forgery'] else 'Authentic'} (ID: {get_id(p['img_path'])})\")\n    plt.tight_layout()\n    plt.show()\n\nshow_samples(pairs, n=20)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-17T16:03:58.824801Z","iopub.execute_input":"2025-12-17T16:03:58.825074Z","iopub.status.idle":"2025-12-17T16:04:01.730873Z","shell.execute_reply.started":"2025-12-17T16:03:58.825053Z","shell.execute_reply":"2025-12-17T16:04:01.729951Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"corr_matrix = df_stats.corr()\nplt.figure(figsize=(8, 6))\nsns.heatmap(corr_matrix, annot=True, cmap='coolwarm')\nplt.title(\"Correlation Matrix for Forged Stats\")\nplt.show()\n\n\nforged_intensity = [mean_intensity[i] for i, p in enumerate(pairs) if p[\"has_forgery\"]]\nauthentic_intensity = [mean_intensity[i] for i, p in enumerate(pairs) if not p[\"has_forgery\"]]\n\nplt.figure(figsize=(12, 5))\nsns.histplot(forged_intensity, bins=30, kde=True, color='red', label='Forged')\nsns.histplot(authentic_intensity, bins=30, kde=True, color='blue', label='Authentic')\nplt.title(\"Mean Intensity Distribution: Forged vs Authentic\")\nplt.xlabel(\"Mean Intensity\")\nplt.ylabel(\"Count\")\nplt.legend()\nplt.show()\n\nprint(\"EDA Complete! This provides a strong foundation for model development.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-17T16:04:01.731975Z","iopub.execute_input":"2025-12-17T16:04:01.732245Z","iopub.status.idle":"2025-12-17T16:04:02.422135Z","shell.execute_reply.started":"2025-12-17T16:04:01.732224Z","shell.execute_reply":"2025-12-17T16:04:02.421185Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}