{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.6.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":16880,"databundleVersionId":858837,"sourceType":"competition"}],"dockerImageVersionId":29844,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport cv2\nimport json\n\nDATA_PATH = \"/kaggle/input/deepfake-detection-challenge/train_sample_videos\"\n\nwith open(\"/kaggle/input/deepfake-detection-challenge/train_sample_videos/metadata.json\", \"r\") as f:\n    meta = json.load(f)\n\ndf = pd.DataFrame(meta).T.reset_index()\ndf.rename(columns={'index':'filename'}, inplace=True)\ndf.head()\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-09-24T22:32:33.218432Z","iopub.execute_input":"2025-09-24T22:32:33.218817Z","iopub.status.idle":"2025-09-24T22:32:33.313751Z","shell.execute_reply.started":"2025-09-24T22:32:33.218753Z","shell.execute_reply":"2025-09-24T22:32:33.312259Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def get_video_metadata(video_path):\n    cap = cv2.VideoCapture(video_path)\n    if not cap.isOpened():\n        return None\n    width  = cap.get(cv2.CAP_PROP_FRAME_WIDTH)\n    height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)\n    fps    = cap.get(cv2.CAP_PROP_FPS)\n    frames = cap.get(cv2.CAP_PROP_FRAME_COUNT)\n    duration = frames / fps if fps > 0 else 0\n    cap.release()\n    return width, height, fps, duration\n    \ndf_sample = df.sample(100, random_state=42).reset_index(drop=True)\n# df_sample.head()\n\nmeta_data = []\nfor i, row in df_sample.iterrows():\n    video_file = os.path.join(DATA_PATH, row[\"filename\"])\n    info = get_video_metadata(video_file)\n    if info:\n        width, height, fps, duration = info\n        meta_data.append([row[\"filename\"], row[\"label\"], width, height, fps, duration])\n\ndf_meta = pd.DataFrame(meta_data, columns=[\"filename\", \"label\", \"width\", \"height\", \"fps\", \"duration\"])\ndf_meta.head()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-24T22:32:33.316583Z","iopub.execute_input":"2025-09-24T22:32:33.317025Z","iopub.status.idle":"2025-09-24T22:32:35.797470Z","shell.execute_reply.started":"2025-09-24T22:32:33.316947Z","shell.execute_reply":"2025-09-24T22:32:35.796408Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Class distribution\nimport pandas as pd\nimport matplotlib.pyplot as plt\n\n\nmetadata = pd.read_json(\"/kaggle/input/deepfake-detection-challenge/train_sample_videos/metadata.json\").T\nmetadata.head()\n\nclass_counts = metadata['label'].value_counts()\n\n# Plot\nclass_counts.plot(kind='bar', color=['red', 'green'])\nplt.title(\"Class Distribution (Real vs Fake)\")\nplt.ylabel(\"Count\")\nplt.xlabel(\"Class\")\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-24T22:32:35.799023Z","iopub.execute_input":"2025-09-24T22:32:35.799339Z","iopub.status.idle":"2025-09-24T22:32:36.139599Z","shell.execute_reply.started":"2025-09-24T22:32:35.799283Z","shell.execute_reply":"2025-09-24T22:32:36.138273Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import cv2\nimport numpy as np\nfrom tqdm import tqdm\n\n\nvideo_paths = metadata.index  \n\nvideo_stats = []\n\nfor video in tqdm(video_paths):\n    path = f\"/kaggle/input/deepfake-detection-challenge/train_sample_videos/{video}\"\n    cap = cv2.VideoCapture(path)\n    if not cap.isOpened():\n        continue\n    \n    frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))\n    fps = cap.get(cv2.CAP_PROP_FPS)\n    width  = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))\n    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))\n    duration = frame_count / fps if fps > 0 else 0\n    bitrate = (frame_count * width * height) / duration if duration > 0 else 0\n    \n    video_stats.append([video, metadata.loc[video]['label'], width, height, fps, duration, bitrate])\n    cap.release()\n\ndf_stats = pd.DataFrame(video_stats, columns=[\"video\", \"label\", \"width\", \"height\", \"fps\", \"duration\", \"bitrate\"])\ndf_stats.head()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-24T22:32:36.141004Z","iopub.execute_input":"2025-09-24T22:32:36.141342Z","iopub.status.idle":"2025-09-24T22:32:46.137419Z","shell.execute_reply.started":"2025-09-24T22:32:36.141291Z","shell.execute_reply":"2025-09-24T22:32:46.136619Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from scipy.stats import ttest_ind\n\nfeatures = [\"width\", \"height\", \"fps\", \"duration\", \"bitrate\"]\n\nresults = {}\nfor feature in features:\n    real_vals = df_stats[df_stats[\"label\"] == \"REAL\"][feature]\n    fake_vals = df_stats[df_stats[\"label\"] == \"FAKE\"][feature]\n    stat, pval = ttest_ind(real_vals, fake_vals, equal_var=False, nan_policy='omit')\n    results[feature] = {\"real_mean\": real_vals.mean(), \"fake_mean\": fake_vals.mean(), \"p-value\": pval}\n\nresults_df = pd.DataFrame(results).T\nresults_df\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-24T22:32:46.140343Z","iopub.execute_input":"2025-09-24T22:32:46.140680Z","iopub.status.idle":"2025-09-24T22:32:46.176153Z","shell.execute_reply.started":"2025-09-24T22:32:46.140626Z","shell.execute_reply":"2025-09-24T22:32:46.174808Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import cv2\nimport os\n\ndef extract_frames(video_path, out_dir, num_frames=10):\n    os.makedirs(out_dir, exist_ok=True)\n    cap = cv2.VideoCapture(video_path)\n    frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))\n    step = max(frame_count // num_frames, 1)\n    i, saved = 0, 0\n    while cap.isOpened() and saved < num_frames:\n        ret, frame = cap.read()\n        if not ret:\n            break\n        if i % step == 0:\n            frame_path = os.path.join(out_dir, f\"frame_{saved}.jpg\")\n            cv2.imwrite(frame_path, frame)\n            saved += 1\n        i += 1\n    cap.release()\n\n\nextract_frames(\"/kaggle/input/deepfake-detection-challenge/train_sample_videos/akzbnazxtz.mp4\",\n               \"frames_real\", num_frames=5)\nextract_frames(\"/kaggle/input/deepfake-detection-challenge/train_sample_videos/aapnvogymq.mp4\",\n               \"frames_fake\", num_frames=5)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-24T22:32:46.180625Z","iopub.execute_input":"2025-09-24T22:32:46.181093Z","iopub.status.idle":"2025-09-24T22:32:50.758015Z","shell.execute_reply.started":"2025-09-24T22:32:46.181015Z","shell.execute_reply":"2025-09-24T22:32:50.756829Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install mahotas","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-24T22:32:50.759466Z","iopub.execute_input":"2025-09-24T22:32:50.759799Z","iopub.status.idle":"2025-09-24T22:32:57.180093Z","shell.execute_reply.started":"2025-09-24T22:32:50.759737Z","shell.execute_reply":"2025-09-24T22:32:57.178915Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Feature engineering\nimport numpy as np\nfrom skimage.feature import hog\nfrom skimage import color\nimport mahotas\nimport matplotlib.pyplot as plt\n\ndef compute_features(image_path):\n    img = cv2.imread(image_path)\n    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n\n    # Haralick Texture Features\n    haralick = mahotas.features.haralick(gray).mean(axis=0)\n\n    # HOG Features\n    hog_features, hog_img = hog(gray, visualize=True, block_norm='L2-Hys')\n\n    # Color Histogram (HSV)\n    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)\n    hist = cv2.calcHist([hsv], [0,1,2], None, [8,8,8], [0,180,0,256,0,256])\n    hist = cv2.normalize(hist, hist).flatten()\n\n    return {\"haralick\": haralick,\n            \"hog\": hog_features,\n            \"hog_img\": hog_img,\n            \"hist\": hist}\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-24T22:32:57.182413Z","iopub.execute_input":"2025-09-24T22:32:57.182889Z","iopub.status.idle":"2025-09-24T22:32:57.195114Z","shell.execute_reply.started":"2025-09-24T22:32:57.182792Z","shell.execute_reply":"2025-09-24T22:32:57.193958Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import glob\n\nreal_frame = glob.glob(\"frames_real/*.jpg\")[0]\nfake_frame = glob.glob(\"frames_fake/*.jpg\")[0]\n\nreal_feats = compute_features(real_frame)\nfake_feats = compute_features(fake_frame)\n\nfig, axs = plt.subplots(1,2, figsize=(12,6))\naxs[0].imshow(real_feats[\"hog_img\"], cmap=\"gray\")\naxs[0].set_title(\"HOG (Real)\")\naxs[1].imshow(fake_feats[\"hog_img\"], cmap=\"gray\")\naxs[1].set_title(\"HOG (Fake)\")\nplt.show()\n\n# Compare Color Histograms\nplt.plot(real_feats[\"hist\"][:50], label=\"Real\", color=\"blue\")\nplt.plot(fake_feats[\"hist\"][:50], label=\"Fake\", color=\"red\")\nplt.legend()\nplt.title(\"Color Histogram (HSV)\")\nplt.show()\n\nfeatures = range(len(real_feats[\"haralick\"]))\nplt.plot(features, real_feats[\"haralick\"], label=\"Real\", marker=\"o\")\nplt.plot(features, fake_feats[\"haralick\"], label=\"Fake\", marker=\"x\")\nplt.legend()\nplt.title(\"Haralick Texture Features\")\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-24T22:32:57.196995Z","iopub.execute_input":"2025-09-24T22:32:57.197404Z","iopub.status.idle":"2025-09-24T22:33:13.728622Z","shell.execute_reply.started":"2025-09-24T22:32:57.197342Z","shell.execute_reply":"2025-09-24T22:33:13.727643Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#  Outlier Detection\nimport pandas as pd\nimport numpy as np\nimport cv2\nimport os\nimport glob\n\n# Step 1: Collect metadata\ndef get_video_metadata(video_path):\n    cap = cv2.VideoCapture(video_path)\n    fps = cap.get(cv2.CAP_PROP_FPS)\n    frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))\n    \n    # Prevent division by zero\n    if fps <= 0:\n        fps = np.nan\n    \n    duration = frame_count / fps if fps and fps > 0 else np.nan\n    width  = cap.get(cv2.CAP_PROP_FRAME_WIDTH)\n    height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)\n    cap.release()\n    \n    return {\"video\": os.path.basename(video_path),\n            \"fps\": fps, \"duration\": duration,\n            \"width\": width, \"height\": height}\n\nvideo_list = glob.glob(\"/kaggle/input/deepfake-detection-challenge/train_sample_videos/*.mp4\")[:100]\n\n\nmetadata = pd.DataFrame([get_video_metadata(v) for v in video_list])\n\n# Drop rows with missing fps/duration\nmetadata = metadata.dropna(subset=[\"fps\", \"duration\"])\n\n\n# Step 2: Safe Z-score \ndef safe_zscore(series):\n    \"\"\"Return Z-scores safely even if std=0\"\"\"\n    if series.std() == 0 or pd.isna(series.std()):\n        return pd.Series([0]*len(series), index=series.index)\n    return (series - series.mean()) / series.std()\n\n# Apply to each numeric column\nfor col in [\"fps\", \"duration\", \"width\", \"height\"]:\n    metadata[f\"{col}_z\"] = safe_zscore(metadata[col])\n\n\n# Step 3: Outlier Detection\noutliers = metadata[\n    (metadata[\"fps_z\"].abs() > 2) |\n    (metadata[\"duration_z\"].abs() > 2) |\n    (metadata[\"width_z\"].abs() > 2) |\n    (metadata[\"height_z\"].abs() > 2)\n]\n\nmetadata, outliers\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-24T22:33:13.730069Z","iopub.execute_input":"2025-09-24T22:33:13.730406Z","iopub.status.idle":"2025-09-24T22:33:16.392757Z","shell.execute_reply.started":"2025-09-24T22:33:13.730346Z","shell.execute_reply":"2025-09-24T22:33:16.391727Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Temporal anomaly\ndef temporal_difference(video_path, num_frames=50):\n    cap = cv2.VideoCapture(video_path)\n    prev_frame = None\n    diffs = []\n    count = 0\n    while cap.isOpened() and count < num_frames:\n        ret, frame = cap.read()\n        if not ret:\n            break\n        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)\n        if prev_frame is not None:\n            diff = np.mean(cv2.absdiff(gray, prev_frame))\n            diffs.append(diff)\n        prev_frame = gray\n        count += 1\n    cap.release()\n    return diffs\n\nreal_diffs = temporal_difference(\"/kaggle/input/deepfake-detection-challenge/train_sample_videos/abarnvbtwb.mp4\")\nfake_diffs = temporal_difference(\"/kaggle/input/deepfake-detection-challenge/train_sample_videos/aagfhgtpmv.mp4\")\n\nplt.plot(real_diffs, label=\"Real\")\nplt.plot(fake_diffs, label=\"Fake\")\nplt.legend()\nplt.title(\"Temporal Frame Differences\")\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-24T22:33:16.394523Z","iopub.execute_input":"2025-09-24T22:33:16.395001Z","iopub.status.idle":"2025-09-24T22:33:18.029927Z","shell.execute_reply.started":"2025-09-24T22:33:16.394905Z","shell.execute_reply":"2025-09-24T22:33:18.028568Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install mahotas\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-24T22:33:18.031697Z","iopub.execute_input":"2025-09-24T22:33:18.032240Z","iopub.status.idle":"2025-09-24T22:33:24.731315Z","shell.execute_reply.started":"2025-09-24T22:33:18.032009Z","shell.execute_reply":"2025-09-24T22:33:24.730106Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import cv2\nimport os\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport mahotas\nfrom skimage.feature import hog, greycomatrix, greycoprops\nfrom skimage.color import rgb2gray\nfrom mahotas import features as mh_features \nfrom sklearn.decomposition import PCA\n\n# 1. Extract frames from videos\ndef extract_frames(video_path, frame_interval=15, out_dir=\"frames\"):\n    \"\"\"\n    Extracts every Nth frame from a video.\n    \"\"\"\n    os.makedirs(out_dir, exist_ok=True)\n    cap = cv2.VideoCapture(video_path)\n    frames = []\n    count = 0\n    success = True\n    \n    while success:\n        success, frame = cap.read()\n        if not success:\n            break\n        if count % frame_interval == 0:\n            frame_path = os.path.join(out_dir, f\"{os.path.basename(video_path)}_{count}.jpg\")\n            cv2.imwrite(frame_path, frame)\n            frames.append(frame_path)\n        count += 1\n    \n    cap.release()\n    return frames\n\n\n# 2. Feature Computation\n\ndef compute_haralick(image_gray):\n    \"\"\"\n    Compute Haralick features from grayscale image.\n    \"\"\"\n    return mh_features.haralick(image_gray).mean(axis=0)  # mean over directions\n\ndef compute_hog(image_gray):\n    \"\"\"\n    Compute HOG features.\n    \"\"\"\n    hog_features, hog_image = hog(image_gray, \n                                  orientations=9, \n                                  pixels_per_cell=(8, 8),\n                                  cells_per_block=(2, 2), \n                                  visualize=True,\n                                  block_norm='L2-Hys')\n    return hog_features, hog_image\n\ndef compute_color_hist(image):\n    \"\"\"\n    Compute normalized color histogram (RGB).\n    \"\"\"\n    chans = cv2.split(image)\n    hist_features = []\n    for chan in chans:\n        hist = cv2.calcHist([chan], [0], None, [32], [0, 256])\n        hist = cv2.normalize(hist, hist).flatten()\n        hist_features.extend(hist)\n    return np.array(hist_features)\n\n\n# 3. Example Usage\nreal_video = \"/kaggle/input/deepfake-detection-challenge/train_sample_videos/akzbnazxtz.mp4\"\nfake_video = \"/kaggle/input/deepfake-detection-challenge/train_sample_videos/adohikbdaz.mp4\"\n\nreal_frames = extract_frames(real_video, frame_interval=15, out_dir=\"frames/real\")\nfake_frames = extract_frames(fake_video, frame_interval=15, out_dir=\"frames/fake\")\n\n# Compute features for first frame of each\nsample_real = cv2.imread(real_frames[0])\nsample_fake = cv2.imread(fake_frames[0])\n\ngray_real = cv2.cvtColor(sample_real, cv2.COLOR_BGR2GRAY)\ngray_fake = cv2.cvtColor(sample_fake, cv2.COLOR_BGR2GRAY)\n\n# Haralick\nharalick_real = compute_haralick(gray_real)\nharalick_fake = compute_haralick(gray_fake)\n\n# HOG\nhog_real, hog_img_real = compute_hog(gray_real)\nhog_fake, hog_img_fake = compute_hog(gray_fake)\n\n# Color Histogram\ncolor_hist_real = compute_color_hist(sample_real)\ncolor_hist_fake = compute_color_hist(sample_fake)\n\n# 4. Visualization\nplt.figure(figsize=(20,15))\n\n# HOG visualization\nplt.subplot(1,2,1)\nplt.imshow(hog_img_real, cmap=\"gray\")\nplt.title(\"HOG - Real Frame\")\n\nplt.subplot(1,2,2)\nplt.imshow(hog_img_fake, cmap=\"gray\")\nplt.title(\"HOG - Fake Frame\")\nplt.show()\n\n# Color histograms\nplt.figure(figsize=(10,5))\nplt.plot(color_hist_real, label=\"Real\")\nplt.plot(color_hist_fake, label=\"Fake\")\nplt.title(\"Color Histogram Comparison\")\nplt.legend()\nplt.show()\n\n# Print Haralick features for inspection\nprint(\"Haralick (Real):\", haralick_real[:5])   # show first 5 values\nprint(\"Haralick (Fake):\", haralick_fake[:5])\n\n# Simple comparison plot (first 5 Haralick features)\nplt.figure(figsize=(8,5))\nplt.plot(haralick_real[:5], marker='o', label=\"Real\")\nplt.plot(haralick_fake[:5], marker='o', label=\"Fake\")\nplt.title(\"Haralick Texture Features\")\nplt.xlabel(\"Feature Index\")\nplt.ylabel(\"Value\")\nplt.legend()\nplt.show()\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-24T22:33:24.733667Z","iopub.execute_input":"2025-09-24T22:33:24.734021Z","iopub.status.idle":"2025-09-24T22:33:49.156216Z","shell.execute_reply.started":"2025-09-24T22:33:24.733960Z","shell.execute_reply":"2025-09-24T22:33:49.154961Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# PCA clusters\nimport cv2\nimport os\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom skimage.feature import hog\nfrom skimage.color import rgb2gray\nimport mahotas\nfrom sklearn.decomposition import PCA\nfrom sklearn.preprocessing import StandardScaler\n\n# Feature Computation Functions\ndef compute_haralick(image_gray):\n    return mahotas.features.haralick(image_gray).mean(axis=0)\n\ndef compute_hog(image_gray):\n    features, _ = hog(image_gray, orientations=9, pixels_per_cell=(8, 8),\n                      cells_per_block=(2, 2), visualize=True, block_norm='L2-Hys')\n    return features\n\ndef compute_color_hist(image):\n    chans = cv2.split(image)\n    hist_features = []\n    for chan in chans:\n        hist = cv2.calcHist([chan], [0], None, [32], [0, 256])\n        hist = cv2.normalize(hist, hist).flatten()\n        hist_features.extend(hist)\n    return np.array(hist_features)\n\n# Process Multiple Videos\ndef extract_features_from_video(video_path, label, frame_interval=20, max_frames=10):\n    cap = cv2.VideoCapture(video_path)\n    features = []\n    labels = []\n    count, extracted = 0, 0\n    \n    while cap.isOpened() and extracted < max_frames:\n        ret, frame = cap.read()\n        if not ret:\n            break\n        if count % frame_interval == 0:\n            gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)\n            # Compute features\n            haralick = compute_haralick(gray)\n            hog_feat = compute_hog(gray)\n            color_hist = compute_color_hist(frame)\n            # Concatenate all\n            combined = np.concatenate([haralick, hog_feat, color_hist])\n            features.append(combined)\n            labels.append(label)\n            extracted += 1\n        count += 1\n    \n    cap.release()\n    return features, labels\n\n# Example Usage with PCA\nreal_videos = [\"/kaggle/input/deepfake-detection-challenge/train_sample_videos/akzbnazxtz.mp4\",\n               \"/kaggle/input/deepfake-detection-challenge/train_sample_videos/aelfnikyqj.mp4\",\n              \"/kaggle/input/deepfake-detection-challenge/train_sample_videos/ahqqqilsxt.mp4\",\n              \"/kaggle/input/deepfake-detection-challenge/train_sample_videos/ajqslcypsw.mp4\"]\nfake_videos = [\"/kaggle/input/deepfake-detection-challenge/train_sample_videos/aelzhcnwgf.mp4\", \n               \"/kaggle/input/deepfake-detection-challenge/train_sample_videos/adylbeequz.mp4\",\n              \"/kaggle/input/deepfake-detection-challenge/train_sample_videos/acxwigylke.mp4\",\n              \"/kaggle/input/deepfake-detection-challenge/train_sample_videos/acxnxvbsxk.mp4\"]\n\nX, y = [], []\n\n# Extract from real videos\nfor rv in real_videos:\n    feats, labs = extract_features_from_video(rv, label=\"Real\")\n    X.extend(feats)\n    y.extend(labs)\n\n# Extract from fake videos\nfor fv in fake_videos:\n    feats, labs = extract_features_from_video(fv, label=\"Fake\")\n    X.extend(feats)\n    y.extend(labs)\n\nX = np.array(X)\n\n# Standardize before PCA\nX_scaled = StandardScaler().fit_transform(X)\n\n# PCA\npca = PCA(n_components=2)\nX_pca = pca.fit_transform(X_scaled)\n\n# PCA clusters\nplt.figure(figsize=(8,6))\nfor label, color in zip([\"Real\", \"Fake\"], [\"blue\", \"red\"]):\n    mask = np.array(y) == label\n    plt.scatter(X_pca[mask, 0], X_pca[mask, 1], label=label, alpha=0.7, c=color)\n\nplt.title(\"PCA Clustering of Real vs Fake Features\")\nplt.xlabel(\"Principal Component 1\")\nplt.ylabel(\"Principal Component 2\")\nplt.legend()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-24T23:02:01.810320Z","iopub.execute_input":"2025-09-24T23:02:01.810677Z","iopub.status.idle":"2025-09-24T23:12:35.848586Z","shell.execute_reply.started":"2025-09-24T23:02:01.810624Z","shell.execute_reply":"2025-09-24T23:12:35.847626Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import cv2\nimport numpy as np\nimport matplotlib.pyplot as plt\n\n# Optical Flow Function\ndef compute_optical_flow_stats(video_path, max_frames=200):\n    cap = cv2.VideoCapture(video_path)\n    \n    # Read the first frame\n    ret, frame1 = cap.read()\n    if not ret:\n        print(\"Error: Cannot read video\")\n        return\n    \n    prev_gray = cv2.cvtColor(frame1, cv2.COLOR_BGR2GRAY)\n    \n    magnitudes = []\n    variances = []\n    \n    frame_count = 0\n    \n    while True:\n        ret, frame2 = cap.read()\n        if not ret or frame_count >= max_frames:\n            break\n        \n        gray = cv2.cvtColor(frame2, cv2.COLOR_BGR2GRAY)\n        \n        # Compute dense optical flow (Farnebäck)\n        flow = cv2.calcOpticalFlowFarneback(prev_gray, gray, None,\n                                            0.5, 3, 15, 3, 5, 1.2, 0)\n        \n        # Extract flow magnitude and angle\n        mag, ang = cv2.cartToPolar(flow[...,0], flow[...,1])\n        \n        # Compute statistics\n        magnitudes.append(np.mean(mag))          # average speed\n        variances.append(np.var(mag))            # variance in speed (irregularity)\n        \n        prev_gray = gray\n        frame_count += 1\n    \n    cap.release()\n    \n    return magnitudes, variances\n\n# Example Usage\nreal_video = \"/kaggle/input/deepfake-detection-challenge/train_sample_videos/ahqqqilsxt.mp4\"\nfake_video = \"/kaggle/input/deepfake-detection-challenge/train_sample_videos/aelzhcnwgf.mp4\"\n\nreal_mag, real_var = compute_optical_flow_stats(real_video)\nfake_mag, fake_var = compute_optical_flow_stats(fake_video)\n\n# Plot Statistics\nplt.figure(figsize=(12,5))\n\n# Mean flow magnitude\nplt.subplot(1,2,1)\nplt.plot(real_mag, label=\"Real\", color=\"blue\")\nplt.plot(fake_mag, label=\"Fake\", color=\"red\")\nplt.title(\"Optical Flow Mean Magnitude over Frames\")\nplt.xlabel(\"Frame Index\")\nplt.ylabel(\"Mean Magnitude\")\nplt.legend()\n\n# Variance of flow magnitude\nplt.subplot(1,2,2)\nplt.plot(real_var, label=\"Real\", color=\"blue\")\nplt.plot(fake_var, label=\"Fake\", color=\"red\")\nplt.title(\"Optical Flow Variance over Frames\")\nplt.xlabel(\"Frame Index\")\nplt.ylabel(\"Variance of Magnitude\")\nplt.legend()\n\nplt.tight_layout()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-24T23:29:19.089081Z","iopub.execute_input":"2025-09-24T23:29:19.089440Z","iopub.status.idle":"2025-09-24T23:35:09.879978Z","shell.execute_reply.started":"2025-09-24T23:29:19.089388Z","shell.execute_reply":"2025-09-24T23:35:09.878974Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Isolation forest\nimport os, glob, cv2, json, subprocess\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom sklearn.preprocessing import StandardScaler\nfrom sklearn.ensemble import IsolationForest\n\n\nVIDEO_DIR = \"/kaggle/input/deepfake-detection-challenge/train_sample_videos\"\nEXTS = (\"*.mp4\", \"*.mov\", \"*.avi\")\n\ndef extract_metadata(video_path):\n    cap = cv2.VideoCapture(video_path)\n    if not cap.isOpened():\n        return None\n    fps = cap.get(cv2.CAP_PROP_FPS) or np.nan\n    frames = cap.get(cv2.CAP_PROP_FRAME_COUNT) or 0\n    width = cap.get(cv2.CAP_PROP_FRAME_WIDTH) or 0\n    height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT) or 0\n    duration = frames / fps if fps and fps > 0 else np.nan\n    cap.release()\n    return {\n        \"filename\": os.path.basename(video_path),\n        \"fps\": fps, \"duration\": duration,\n        \"width\": width, \"height\": height\n    }\n\nvideo_files = []\nfor ext in EXTS:\n    video_files.extend(glob.glob(os.path.join(VIDEO_DIR, ext)))\n\nrows = [extract_metadata(v) for v in video_files if extract_metadata(v) is not None]\ndf = pd.DataFrame(rows)\ndf[\"resolution_pixels\"] = df[\"width\"] * df[\"height\"]\n\n# Clean data: replace NaN/inf/0 with median\nfor col in [\"fps\", \"duration\", \"resolution_pixels\"]:\n    df[col] = pd.to_numeric(df[col], errors=\"coerce\")\n    df[col].replace([np.inf, -np.inf, 0], np.nan, inplace=True)\n    df[col].fillna(df[col].median(), inplace=True)\n\n# Isolation Forest\nfeatures = [\"fps\", \"duration\", \"resolution_pixels\"]\nX = df[features].values\nscaler = StandardScaler()\nX_scaled = scaler.fit_transform(X)\n\niso = IsolationForest(contamination=0.05, random_state=42, behaviour=\"new\")\ndf[\"iso_label\"] = iso.fit_predict(X_scaled)  # 1 = normal, -1 = outlier\ndf[\"iso_score\"] = iso.decision_function(X_scaled)\n\n# Show flagged outliers\nprint(df[df[\"iso_label\"] == -1][[\"filename\", \"fps\", \"duration\", \"resolution_pixels\", \"iso_score\"]].head())\n\n# Visualization: FPS vs Duration\nplt.figure(figsize=(8,6))\ncolors = df[\"iso_label\"].map({1:\"blue\",-1:\"red\"})\nplt.scatter(df[\"fps\"], df[\"duration\"], c=colors, s=60, edgecolor=\"k\", alpha=0.7)\nplt.xlabel(\"FPS\")\nplt.ylabel(\"Duration (s)\")\nplt.title(\"Isolation Forest: FPS vs Duration (Red = Outlier)\")\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-24T23:36:48.012091Z","iopub.execute_input":"2025-09-24T23:36:48.012459Z","iopub.status.idle":"2025-09-24T23:37:08.366548Z","shell.execute_reply.started":"2025-09-24T23:36:48.012408Z","shell.execute_reply":"2025-09-24T23:37:08.365614Z"}},"outputs":[],"execution_count":null}]}