{"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":"nvidiaTeslaT4","dataSources":[{"sourceId":19989,"databundleVersionId":1160143,"sourceType":"competition"}],"dockerImageVersionId":31260,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip install ultralytics==8.2.0\n!pip install opencv-python\n!pip install scikit-\n!pip install pillow\n!pip install ultralytics opencv-python tqdm scikit-learn --quiet","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**STEP 2 — IMPORT + AUTO PATH DATASET**","metadata":{}},{"cell_type":"code","source":"import os\nimport cv2\nimport time\nimport numpy as np\nfrom tqdm import tqdm\nfrom ultralytics import FastSAM\nfrom sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, confusion_matrix\n\n# AUTO DETECT DATASET PATH (KHUSUS KAGGLE)\nBASE_INPUT = \"/kaggle/input\"\n\ndataset_path = None\n\nfor folder in os.listdir(BASE_INPUT):\n    if \"wheat\" in folder.lower():\n        dataset_path = os.path.join(BASE_INPUT, folder)\n\nprint(\"Dataset found:\", dataset_path)\n\n# AUTO FIND IMAGE FOLDER\nINPUT_FOLDER = None\n\nfor root, dirs, files in os.walk(dataset_path):\n    if len(files) > 0:\n        if files[0].lower().endswith(\".jpg\"):\n            INPUT_FOLDER = root\n            break\n\nprint(\"Image folder:\", INPUT_FOLDER)\n\n# OUTPUT\nOUTPUT_FOLDER = \"/kaggle/working/crops\"\nos.makedirs(OUTPUT_FOLDER, exist_ok=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-10T19:23:57.23956Z","iopub.execute_input":"2026-02-10T19:23:57.240461Z","iopub.status.idle":"2026-02-10T19:23:57.949749Z","shell.execute_reply.started":"2026-02-10T19:23:57.240426Z","shell.execute_reply":"2026-02-10T19:23:57.948962Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**STEP 3 — FORCE CPU (ANTI CUDA ERROR)**","metadata":{}},{"cell_type":"code","source":"!pip install torch==2.3.1 torchvision==0.18.1 -q\n!pip install ultralytics==8.1.0 -q","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**STEP 4 — LOAD FASTSAM (ZERO-SHOT)**","metadata":{}},{"cell_type":"code","source":"from ultralytics import FastSAM\n\nDEVICE = \"cpu\"\n\nmodel_seg = FastSAM(\"FastSAM-s.pt\")\n\nprint(\"✅ FastSAM READY\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-10T19:24:03.549084Z","iopub.execute_input":"2026-02-10T19:24:03.549918Z","iopub.status.idle":"2026-02-10T19:24:03.60782Z","shell.execute_reply.started":"2026-02-10T19:24:03.549881Z","shell.execute_reply":"2026-02-10T19:24:03.607058Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**STEP 5 — ZERO-SHOT SEGMENTATION + AUTO CROP**","metadata":{}},{"cell_type":"code","source":"# # STEP 5 — ZERO-SHOT SEGMENTATION + AUTO CROP\n\n# LIMIT_IMAGE = 100   # ubah None jika mau full dataset\n\n# # Ambil list gambar dari folder input\n# image_list = os.listdir(INPUT_FOLDER)\n\n# print(\"Total image:\", len(image_list))\n\n# # Batasi jumlah gambar (opsional)\n# if LIMIT_IMAGE:\n#     image_list = image_list[:LIMIT_IMAGE]\n\n# inference_times = []\n\n# for img_name in tqdm(image_list):\n\n#     start = time.time()\n\n#     img_path = os.path.join(INPUT_FOLDER, img_name)\n#     image = cv2.imread(img_path)\n\n#     if image is None:\n#         continue\n\n#     results = model_seg.predict(image, device=DEVICE)\n\n#     if len(results) == 0:\n#         continue\n\n#     if results[0].masks is None:\n#         continue\n\n#     masks = results[0].masks.data\n\n#     for i, m in enumerate(masks):\n\n#         mask = m.cpu().numpy()\n#         mask = (mask * 255).astype(np.uint8)\n\n#         # Fix ukuran mask\n#         mask = cv2.resize(mask,(image.shape[1],image.shape[0]))\n\n#         masked = cv2.bitwise_and(image,image,mask=mask)\n\n#         x,y,w,h = cv2.boundingRect(mask)\n\n#         if w*h < 500:\n#             continue\n\n#         crop = masked[y:y+h, x:x+w]\n\n#         save_path = os.path.join(\n#             OUTPUT_FOLDER,\n#             f\"{img_name}_{i}.jpg\"\n#         )\n\n#         cv2.imwrite(save_path, crop)\n\n#     inference_times.append(time.time()-start)\n\n# print(\"Cropping selesai\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-10T19:26:46.220518Z","iopub.execute_input":"2026-02-10T19:26:46.221378Z","iopub.status.idle":"2026-02-10T19:26:55.945094Z","shell.execute_reply.started":"2026-02-10T19:26:46.221341Z","shell.execute_reply":"2026-02-10T19:26:55.944284Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"LIMIT_IMAGE = 100   # None jika mau full dataset\n\n# ===== LOAD IMAGE LIST =====\nimage_list = [f for f in os.listdir(INPUT_FOLDER) if f.endswith(\".jpg\")]\n\nprint(\"Total image ditemukan:\", len(image_list))\n\nif LIMIT_IMAGE:\n    image_list = image_list[:LIMIT_IMAGE]\n    print(\"Dipakai:\", len(image_list), \"image\")\n\n# ===== START ZERO SHOT =====\n\ninference_times = []\ntotal_crop = 0\n\nfor img_name in tqdm(image_list):\n\n    start = time.time()\n\n    img_path = os.path.join(INPUT_FOLDER, img_name)\n    image = cv2.imread(img_path)\n\n    if image is None:\n        continue\n\n    # ===== FASTSAM PREDICT =====\n    results = model_seg.predict(\n        image,\n        device=DEVICE,\n        verbose=False\n    )\n\n    if not results:\n        continue\n\n    if results[0].masks is None:\n        continue\n\n    masks = results[0].masks.data\n\n    for i, m in enumerate(masks):\n\n        mask = m.cpu().numpy()\n\n        # ===== FIX FORMAT MASK (ANTI ERROR OPENCV) =====\n        mask = (mask > 0.5).astype(np.uint8) * 255\n\n        mask = cv2.resize(\n            mask,\n            (image.shape[1], image.shape[0]),\n            interpolation=cv2.INTER_NEAREST\n        )\n\n        if mask.dtype != np.uint8:\n            mask = mask.astype(np.uint8)\n\n        masked = cv2.bitwise_and(image, image, mask=mask)\n\n        x, y, w, h = cv2.boundingRect(mask)\n\n        # Filter noise kecil\n        if w * h < 500:\n            continue\n\n        crop = masked[y:y+h, x:x+w]\n\n        save_path = os.path.join(\n            OUTPUT_FOLDER,\n            f\"{img_name}_{i}.jpg\"\n        )\n\n        cv2.imwrite(save_path, crop)\n        total_crop += 1\n\n    inference_times.append(time.time() - start)\n\nprint(\"\\n✅ Cropping selesai\")\nprint(\"Total crop:\", total_crop)\nprint(\"Avg inference time:\", np.mean(inference_times))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-10T20:11:09.16446Z","iopub.execute_input":"2026-02-10T20:11:09.165107Z","iopub.status.idle":"2026-02-10T20:11:19.084236Z","shell.execute_reply.started":"2026-02-10T20:11:09.16507Z","shell.execute_reply":"2026-02-10T20:11:19.083636Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**STEP 6 — AUTO CLASSIFICATION**","metadata":{}},{"cell_type":"code","source":"pred = []\ntrue = []\n\ncrop_list = os.listdir(OUTPUT_FOLDER)\n\nfor img in crop_list:\n\n    path = os.path.join(OUTPUT_FOLDER,img)\n    im = cv2.imread(path)\n\n    if im is None:\n        continue\n\n    h,w,_ = im.shape\n    area = h*w\n\n    # RULE CLASSIFIER (contoh penelitian)\n    if area > 5000:\n        label = 1   # wheat\n    else:\n        label = 0   # non-wheat\n\n    pred.append(label)\n\n    # dummy ground truth (karena zero-shot)\n    true.append(1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-10T20:11:35.254999Z","iopub.execute_input":"2026-02-10T20:11:35.255594Z","iopub.status.idle":"2026-02-10T20:11:35.312003Z","shell.execute_reply.started":"2026-02-10T20:11:35.25556Z","shell.execute_reply":"2026-02-10T20:11:35.311239Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**STEP 7 — EVALUASI METRIK**","metadata":{}},{"cell_type":"code","source":"acc = accuracy_score(true,pred)\nprec = precision_score(true,pred)\nrec = recall_score(true,pred)\nf1 = f1_score(true,pred)\n\ntn, fp, fn, tp = confusion_matrix(true,pred).ravel()\nspecificity = tn/(tn+fp+1e-6)\n\nprint(\"===== HASIL FINAL =====\")\n\nprint(\"Accuracy:\",acc)\nprint(\"Precision:\",prec)\nprint(\"Recall (Sensitivity):\",rec)\nprint(\"Specificity:\",specificity)\nprint(\"F1-score:\",f1)\n\nprint(\"Avg inference time:\", np.mean(inference_times))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-10T20:11:43.538437Z","iopub.execute_input":"2026-02-10T20:11:43.539064Z","iopub.status.idle":"2026-02-10T20:11:43.555074Z","shell.execute_reply.started":"2026-02-10T20:11:43.539032Z","shell.execute_reply":"2026-02-10T20:11:43.554368Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\n\nresults_table = pd.DataFrame([{\n\n    \"Model\": \"FastSAM (Zero-Shot)\",\n    \"Dataset\": \"Global Wheat Detection\",\n\n    \"Accuracy\": 0.5785582255083179,\n    \"Precision\": 1.0,\n    \"Recall (Sensitivity)\": 0.5785582255083179,\n    \"Specificity\": 0.0,\n    \"F1-Score\": 0.7330210772833724,\n    \"Avg Inference Time (sec)\": 0.9701665163040161\n\n}])\n\nresults_table","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-10T20:11:47.125402Z","iopub.execute_input":"2026-02-10T20:11:47.125712Z","iopub.status.idle":"2026-02-10T20:11:47.137868Z","shell.execute_reply.started":"2026-02-10T20:11:47.125671Z","shell.execute_reply":"2026-02-10T20:11:47.137206Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import shutil\n\nshutil.make_archive(\n    \"hasil_crop_zero_shot\",   # nama file zip\n    'zip',\n    \"/kaggle/working/crops\"  # folder hasil crop\n)\n\nprint(\"ZIP berhasil dibuat\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-10T20:11:51.364662Z","iopub.execute_input":"2026-02-10T20:11:51.365455Z","iopub.status.idle":"2026-02-10T20:11:51.470632Z","shell.execute_reply.started":"2026-02-10T20:11:51.365423Z","shell.execute_reply":"2026-02-10T20:11:51.470101Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"batch_size = 50\n\nfor i in range(0, len(image_list), batch_size):\n\n    batch_folder = f\"/kaggle/working/batch_{i}\"\n    os.makedirs(batch_folder, exist_ok=True)\n\n    # pindahkan hasil batch ke folder\n    # lalu zip","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-10T20:12:00.059166Z","iopub.execute_input":"2026-02-10T20:12:00.059729Z","iopub.status.idle":"2026-02-10T20:12:00.063656Z","shell.execute_reply.started":"2026-02-10T20:12:00.059671Z","shell.execute_reply":"2026-02-10T20:12:00.063034Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\n\nprint(os.listdir(\"/kaggle/working\"))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-10T20:12:11.28691Z","iopub.execute_input":"2026-02-10T20:12:11.287629Z","iopub.status.idle":"2026-02-10T20:12:11.291499Z","shell.execute_reply.started":"2026-02-10T20:12:11.287596Z","shell.execute_reply":"2026-02-10T20:12:11.290962Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!ls /kaggle/working","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-10T20:12:15.067561Z","iopub.execute_input":"2026-02-10T20:12:15.067874Z","iopub.status.idle":"2026-02-10T20:12:15.214895Z","shell.execute_reply.started":"2026-02-10T20:12:15.067848Z","shell.execute_reply":"2026-02-10T20:12:15.214021Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!zip -r /kaggle/working/hasil_crop_zero_shot.zip /kaggle/working/crops","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-10T20:12:22.870613Z","iopub.execute_input":"2026-02-10T20:12:22.871352Z","iopub.status.idle":"2026-02-10T20:12:23.119121Z","shell.execute_reply.started":"2026-02-10T20:12:22.871311Z","shell.execute_reply":"2026-02-10T20:12:23.118433Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"Isi working:\")\nprint(os.listdir(\"/kaggle/working\"))\n\nprint(\"Isi crops:\")\nprint(os.listdir(\"/kaggle/working/crops\")[:10])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-10T20:12:33.067344Z","iopub.execute_input":"2026-02-10T20:12:33.067911Z","iopub.status.idle":"2026-02-10T20:12:33.07346Z","shell.execute_reply.started":"2026-02-10T20:12:33.067876Z","shell.execute_reply":"2026-02-10T20:12:33.07285Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from IPython.display import FileLink\n\nFileLink('/kaggle/working/hasil_crop_zero_shot.zip')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-10T20:12:37.139407Z","iopub.execute_input":"2026-02-10T20:12:37.139724Z","iopub.status.idle":"2026-02-10T20:12:37.145428Z","shell.execute_reply.started":"2026-02-10T20:12:37.139675Z","shell.execute_reply":"2026-02-10T20:12:37.144741Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(len(os.listdir(\"/kaggle/working/crops\")))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-10T20:12:43.633414Z","iopub.execute_input":"2026-02-10T20:12:43.634197Z","iopub.status.idle":"2026-02-10T20:12:43.638794Z","shell.execute_reply.started":"2026-02-10T20:12:43.634164Z","shell.execute_reply":"2026-02-10T20:12:43.638054Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import shutil\n\nshutil.make_archive(\n    \"/kaggle/working/hasil_crop_zero_shot\",\n    'zip',\n    \"/kaggle/working/crops\"\n)\n\nprint(\"ZIP SUCCESS\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-10T20:12:46.126642Z","iopub.execute_input":"2026-02-10T20:12:46.127413Z","iopub.status.idle":"2026-02-10T20:12:46.233286Z","shell.execute_reply.started":"2026-02-10T20:12:46.127381Z","shell.execute_reply":"2026-02-10T20:12:46.232647Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}