{"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":"none","dataSources":[{"sourceId":19991,"databundleVersionId":1117522,"sourceType":"competition"},{"sourceId":2078376,"sourceType":"datasetVersion","datasetId":1245748},{"sourceId":4043617,"sourceType":"datasetVersion","datasetId":2395063},{"sourceId":8013000,"sourceType":"datasetVersion","datasetId":4720723},{"sourceId":12358068,"sourceType":"datasetVersion","datasetId":7791226},{"sourceId":12394717,"sourceType":"datasetVersion","datasetId":7807100}],"dockerImageVersionId":31040,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"##Train on stego imagesdataset-lsb-jpg-using lr\nimport numpy as np\nimport os\nfrom skimage.io import imread\nfrom skimage.color import rgb2gray\nfrom skimage.feature import hog, local_binary_pattern\nfrom PIL import Image\nfrom tqdm import tqdm\nimport pywt\ndef extract_hog(img):\n    return hog(img, orientations=9, pixels_per_cell=(8, 8),\n               cells_per_block=(2, 2), block_norm='L2-Hys', visualize=False)\n\ndef extract_lbp(img):\n    lbp = local_binary_pattern(img, P=8, R=1, method='uniform')\n    (hist, _) = np.histogram(lbp.ravel(), bins=np.arange(0, 10), density=True)\n    return hist\n\ndef extract_bitplane_stats(img):\n    bit_planes = [(img >> i) & 1 for i in range(8)]\n    return np.array([np.mean(p) for p in bit_planes] + [np.std(p) for p in bit_planes])\n\ndef extract_color_stats(img_rgb):\n    means = np.mean(img_rgb, axis=(0, 1))\n    stds = np.std(img_rgb, axis=(0, 1))\n    return np.concatenate([means, stds])\n\ndef extract_wavelet(img):\n    coeffs = pywt.dwt2(img, 'haar')\n    cA, (cH, cV, cD) = coeffs\n    return np.concatenate([cA.ravel()[:100], cH.ravel()[:100], cV.ravel()[:100], cD.ravel()[:100]])\ndef extract_all_features(image_path):\n    try:\n        img = imread(image_path)\n        if img.ndim == 2:\n            gray = img\n            rgb = np.stack((img,)*3, axis=-1)\n        elif img.shape[2] == 3:\n            gray = rgb2gray(img)\n            rgb = img\n        elif img.shape[2] == 4:\n            img = np.array(Image.open(image_path).convert(\"RGB\"))\n            gray = rgb2gray(img)\n            rgb = img\n        else:\n            return None\n\n        gray = gray.astype(float)\n\n        hog_feat = extract_hog(gray)\n        lbp_uint8 = (gray * 255).astype(np.uint8)\n        lbp_feat = extract_lbp(lbp_uint8)\n\n        bitplane_feat = extract_bitplane_stats((gray * 255).astype(np.uint8))\n        color_feat = extract_color_stats(rgb)\n        wavelet_feat = extract_wavelet(gray)\n\n        full_feature = np.concatenate([hog_feat, lbp_feat, bitplane_feat, color_feat, wavelet_feat])\n        return full_feature\n    except Exception as e:\n        print(f\"Error with {image_path}: {e}\")\n        return None\nclean_path = \"/kaggle/input/stegoimagesdataset/test/test/clean\"\nstego_path = \"/kaggle/input/stegoimagesdataset/test/test/stego\"\nclean_images = sorted(os.listdir(clean_path))\nstego_images = sorted(os.listdir(stego_path))\n\nfeatures_clean = []\nfeatures_stego = []\n\nprint(\"Extracting clean image features...\")\nfor img in tqdm(clean_images):\n    feat = extract_all_features(os.path.join(clean_path, img))\n    if feat is not None:\n        features_clean.append(feat)\nfeatures_clean = np.array(features_clean)\nnp.save(\"/kaggle/working/features_clean.npy\", features_clean)\nprint(\"✅ Features saved. Clean:\", features_clean.shape)\n\nprint(\"Extracting stego image features...\")\nfor img in tqdm(stego_images):\n    feat = extract_all_features(os.path.join(stego_path, img))\n    if feat is not None:\n        features_stego.append(feat)\n\nfeatures_stego = np.array(features_stego)\nnp.save(\"/kaggle/working/features_stego.npy\", features_stego)\n\nprint(\"✅ Features saved. Stego:\", features_stego.shape)\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.linear_model import LogisticRegression\nfrom sklearn.metrics import classification_report, accuracy_score\nimport joblib\n\n# === Load your feature files ===\nfeatures_clean = np.load(\"/kaggle/input/features-for-stego/features_clean.npy\")\nfeatures_stego = np.load(\"/kaggle/input/features-for-stego/features_stego.npy\")\n\n# === Labels ===\nlabels_clean = np.zeros(len(features_clean))  # 0 = clean\nlabels_stego = np.ones(len(features_stego))   # 1 = stego\n\n# === Combine Features and Labels ===\nX = np.vstack((features_clean, features_stego))\ny = np.concatenate((labels_clean, labels_stego))\n\n# === Train/Test Split ===\nX_train, X_test, y_train, y_test = train_test_split(\n    X, y, test_size=0.3, random_state=42, stratify=y\n)\n\n# === Train Logistic Regression ===\nprint(\"Training Logistic Regression on full feature set...\")\nmodel = LogisticRegression(max_iter=1000, solver='liblinear')  # liblinear works better for small/mid-size sets\nmodel.fit(X_train, y_train)\n\n# === Evaluate ===\ny_pred = model.predict(X_test)\nacc = accuracy_score(y_test, y_pred)\nprint(f\"\\n✅ Logistic Regression Accuracy: {acc:.4f}\")\nprint(\"\\nClassification Report:\\n\", classification_report(y_test, y_pred, digits=4))\n\n# === Save the trained model ===\njoblib.dump(model, \"/kaggle/working/stego_feature_model.pkl\")\nprint(\"\\n✅ Model saved to: /kaggle/working/stego_feature_model.pkl\")\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#test on directory\n\nimport numpy as np\nimport joblib\nimport os\nimport pywt\nfrom skimage.color import rgb2gray\nfrom skimage.feature import hog, local_binary_pattern\nfrom skimage.io import imread\nfrom PIL import Image\nfrom tqdm import tqdm\nfrom joblib import Parallel, delayed\n\n# === Load the trained model ===\nmodel = joblib.load(\"/kaggle/input/batch-70/stego_feature_model.pkl\")\nprint(\"✅ Model loaded.\")\n\n# === Feature extraction functions ===\ndef extract_all_features(image_path):\n    try:\n        img = imread(image_path)\n        if img.ndim == 2:\n            gray = img\n            rgb = np.stack((img,)*3, axis=-1)\n        elif img.shape[2] == 3:\n            gray = rgb2gray(img)\n            rgb = img\n        elif img.shape[2] == 4:\n            img = np.array(Image.open(image_path).convert(\"RGB\"))\n            gray = rgb2gray(img)\n            rgb = img\n        else:\n            return None\n\n        gray = gray.astype(float)\n        lbp_uint8 = (gray * 255).astype(np.uint8)\n\n        # HOG\n        hog_feat = hog(gray, orientations=9, pixels_per_cell=(8, 8),\n                       cells_per_block=(2, 2), block_norm='L2-Hys', visualize=False)\n\n        # LBP\n        lbp = local_binary_pattern(lbp_uint8, P=8, R=1, method='uniform')\n        lbp_feat, _ = np.histogram(lbp.ravel(), bins=np.arange(0, 10), density=True)\n\n        # Bit-plane\n        bitplanes = [(lbp_uint8 >> i) & 1 for i in range(8)]\n        bp_feat = np.array([np.mean(b) for b in bitplanes] + [np.std(b) for b in bitplanes])\n\n        # Color\n        means = np.mean(rgb, axis=(0, 1))\n        stds = np.std(rgb, axis=(0, 1))\n        color_feat = np.concatenate([means, stds])\n\n        # Wavelet\n        cA, (cH, cV, cD) = pywt.dwt2(gray, 'haar')\n        wav_feat = np.concatenate([cA.ravel()[:100], cH.ravel()[:100],\n                                   cV.ravel()[:100], cD.ravel()[:100]])\n\n        return np.concatenate([hog_feat, lbp_feat, bp_feat, color_feat, wav_feat])\n    except:\n        return None\n\n# === Main prediction function ===\ndef predict_stego_in_directory_fast(directory_path, n_jobs=4):\n    image_paths = [os.path.join(directory_path, fname)\n                   for fname in os.listdir(directory_path)\n                   if fname.lower().endswith((\".png\", \".jpg\", \".jpeg\", \".bmp\", \".tiff\"))]\n\n    print(f\"📁 Found {len(image_paths)} images in: {directory_path}\")\n    print(\"⚙️  Extracting features in parallel...\")\n\n    # Parallel feature extraction\n    features = Parallel(n_jobs=n_jobs)(\n        delayed(extract_all_features)(img_path) for img_path in tqdm(image_paths)\n    )\n\n    valid_features = []\n    valid_paths = []\n\n    for feat, path in zip(features, image_paths):\n        if feat is not None:\n            valid_features.append(feat)\n            valid_paths.append(path)\n\n    if not valid_features:\n        print(\"❌ No valid features extracted. Exiting.\")\n        return\n\n    X = np.vstack(valid_features)\n    print(f\"✅ Valid feature vectors: {len(X)}\")\n\n    print(\"🔍 Running predictions...\")\n    preds = model.predict(X)\n\n    # Final stats\n    total = len(preds)\n    stego = np.sum(preds == 1)\n    cover = np.sum(preds == 0)\n\n    print(\"\\n===== 📊 Final Report =====\")\n    print(f\"📁 Directory: {directory_path}\")\n    print(f\"🖼️ Total Valid Images: {total}\")\n    print(f\"🕵️ Stego Images Detected: {stego}\")\n    print(f\"✅ Clean (Cover) Images: {cover}\")\n    print(f\"📈 Stego Ratio: {stego/total:.4f}\")\n\n# === 🏁 Run the test ===\nyour_test_directory = \"/kaggle/input/alaska2-image-steganalysis/JMiPOD\"  # or \"Cover\"\npredict_stego_in_directory_fast(your_test_directory, n_jobs=4)\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#train on alaska\n\nimport os\nimport numpy as np\nfrom sklearn.linear_model import SGDClassifier\nfrom sklearn.preprocessing import StandardScaler\nfrom sklearn.pipeline import make_pipeline\nfrom sklearn.metrics import accuracy_score, classification_report\nimport joblib\nfrom tqdm import tqdm\nfrom joblib import Parallel, delayed\n\n# ── 0) FEATURE EXTRACTION ─────────────────────────────────────────────────\nimport pywt\nimport cv2\nfrom skimage.color import rgb2gray\nfrom skimage.feature import hog, local_binary_pattern\nfrom skimage.io import imread\nfrom PIL import Image\n\ndef extract_all_features(image_path):\n    \"\"\"HOG + LBP + bit‑plane + color + wavelet features.\"\"\"\n    img = imread(image_path)\n    if img is None:\n        return None\n\n    # grayscale + rgb copy\n    if img.ndim == 2:\n        gray = img\n        rgb  = np.stack((img,)*3, axis=-1)\n    elif img.shape[2] == 4:\n        img  = np.array(Image.open(image_path).convert(\"RGB\"))\n        gray = rgb2gray(img)\n        rgb  = img\n    else:\n        gray = rgb2gray(img)\n        rgb  = img\n\n    gray = (gray * 255).astype(np.uint8)\n\n    # HOG\n    hog_feat = hog(gray, orientations=9, pixels_per_cell=(8,8),\n                   cells_per_block=(2,2), block_norm='L2-Hys', visualize=False)\n\n    # LBP\n    lbp = local_binary_pattern(gray, P=8, R=1, method='uniform')\n    lbp_feat, _ = np.histogram(lbp.ravel(), bins=np.arange(0,10), density=True)\n\n    # Bit‑planes\n    bitplanes = [(gray >> i) & 1 for i in range(8)]\n    bp_feat   = np.array([np.mean(b) for b in bitplanes] +\n                         [np.std(b)  for b in bitplanes])\n\n    # Color stats\n    means = np.mean(rgb, axis=(0,1))\n    stds  = np.std(rgb, axis=(0,1))\n    color_feat = np.concatenate([means, stds])\n\n    # Wavelet\n    cA,(cH,cV,cD) = pywt.dwt2(gray, 'haar')\n    wav_feat = np.concatenate([\n        cA.ravel()[:100], cH.ravel()[:100],\n        cV.ravel()[:100], cD.ravel()[:100]\n    ])\n\n    return np.concatenate([hog_feat, lbp_feat, bp_feat, color_feat, wav_feat])\n\n# ── 1) COLLECT & SPLIT PATHS ───────────────────────────────────────────────\nbase      = \"/kaggle/input/alaska2-image-steganalysis\"\nclean_dir = os.path.join(base, \"Cover\")       # ~75k clean\nstego_dirs = [os.path.join(base, d)            # ~75k each\n              for d in [\"JMiPOD\", \"JUNIWARD\", \"UERD\"]]\n\npaths, labels = [], []\nfor fn in os.listdir(clean_dir):\n    paths.append(os.path.join(clean_dir, fn)); labels.append(0)\nfor sd in stego_dirs:\n    for fn in os.listdir(sd):\n        paths.append(os.path.join(sd, fn)); labels.append(1)\n\npaths  = np.array(paths)\nlabels = np.array(labels)\nperm   = np.random.RandomState(42).permutation(len(paths))\npaths, labels = paths[perm], labels[perm]\n\n# 70/30 train/test\nsplit_idx    = int(0.7 * len(paths))\ntrain_paths  = paths[:split_idx];  train_labels  = labels[:split_idx]\ntest_paths   = paths[split_idx:];  test_labels   = labels[split_idx:]\n\nprint(f\"→ TRAIN on {len(train_paths)} images, TEST on {len(test_paths)} images\")\n\n# ── 2) BUILD ONLINE LOGISTIC REGRESSION PIPELINE ─────────────────────────\npipeline = make_pipeline(\n    StandardScaler(),\n    SGDClassifier(\n        loss=\"log_loss\",       # logistic regression\n        max_iter=1,            # one epoch per partial_fit\n        warm_start=True,\n        learning_rate=\"optimal\",\n        random_state=42\n    )\n)\nclasses = np.array([0,1])\n\n# ── 3) BATCH STREAM WITH PARALLEL FEATURE EXTRACTION ─────────────────────\nBATCH_SIZE = 2000\nN_JOBS     = 4\n\ndef batch_stream(paths, labels, batch_size, n_jobs=4):\n    \"\"\"Yield (X_batch, y_batch) with parallel feature extraction.\"\"\"\n    for i in range(0, len(paths), batch_size):\n        batch_p = paths[i:i+batch_size]\n        batch_l = labels[i:i+batch_size]\n        feats = Parallel(n_jobs=n_jobs, backend=\"threading\")(\n            delayed(extract_all_features)(p) for p in batch_p\n        )\n        # filter out failures\n        Xb = np.vstack([f for f in feats if f is not None])\n        yb = np.array([l for f,l in zip(feats, batch_l) if f is not None])\n        if len(yb):\n            yield Xb, yb\n\n# ── 4) TRAIN WITH PARTIAL_FIT ────────────────────────────────────────────\nfirst = True\nCHECKPOINT_EVERY = 10  # save after every 5 partial_fit calls\nbatch_count = 0\n\nfor Xb, yb in tqdm(batch_stream(train_paths, train_labels, BATCH_SIZE, N_JOBS),\n                   total=(len(train_paths)//BATCH_SIZE)+1, desc=\"Training\"):\n    if first:\n        pipeline.named_steps['sgdclassifier'].partial_fit(Xb, yb, classes=classes)\n        first = False\n    else:\n        pipeline.named_steps['sgdclassifier'].partial_fit(Xb, yb)\n    batch_count += 1\n\n    # checkpoint\n    if batch_count % CHECKPOINT_EVERY == 0:\n        joblib.dump(pipeline, f\"/kaggle/working/checkpoint_batch{batch_count}.pkl\")\n        print(f\"⏺️ Checkpoint saved at batch {batch_count}\")\n\n# ── 5) SAVE FINAL MODEL ─────────────────────────────────────────────────\njoblib.dump(pipeline, \"/kaggle/working/alaska_sgd_lr_pipeline1.pkl\")\nprint(\"✅ Model saved to /kaggle/working/alaska_sgd_lr_pipeline1.pkl\")\n\n# ── 6) EVALUATE ON TEST SET ──────────────────────────────────────────────\ny_true, y_pred = [], []\nfor Xb, yb in tqdm(batch_stream(test_paths, test_labels, BATCH_SIZE, N_JOBS),\n                   total=(len(test_paths)//BATCH_SIZE)+1, desc=\"Testing\"):\n    preds = pipeline.predict(Xb)\n    y_true.extend(yb); y_pred.extend(preds)\n\nprint(\"\\nTest Accuracy:\", accuracy_score(y_true, y_pred))\nprint(classification_report(y_true, y_pred, digits=4))\n","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}