{"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.12.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat_minor":4,"nbformat":4,"cells":[{"id":"b2bd65c3-5cda-45ff-b2a2-5eccb686e8c6","cell_type":"markdown","source":"# Segmentasi Citra dengan Mask R-CNN (COCO 2017 Dataset)\n\nNotebook ini melakukan **segmentasi instance** pada **satu citra** menggunakan model\n**Mask R-CNN (ResNet-50 FPN)** yang sudah dilatih (pretrained) pada dataset COCO.\n\n## Cara menjalankan di Kaggle\n1. **Add Input** → cari dan tambahkan dataset **COCO 2017 Dataset** (panel kanan).\n2. Buka **Settings** (panel kanan) → nyalakan **Internet → On**\n   *(wajib, agar bobot model pretrained ~170 MB bisa diunduh).*\n3. Jalankan semua sel (Run All).\n4. Hasil tersimpan di `/kaggle/working/hasil_segmentasi.jpg` (lihat tab **Output**).","metadata":{}},{"id":"433e1c23-8ad5-46a8-a426-8ff432153610","cell_type":"markdown","source":"## 1. Import library","metadata":{}},{"id":"1d070cc2-afcb-4095-a282-6f5dea277f52","cell_type":"code","source":"import os\nimport glob\nimport random\nimport torch\nfrom torchvision.transforms import functional as F\nfrom torchvision.models.detection import maskrcnn_resnet50_fpn, MaskRCNN_ResNet50_FPN_Weights\nimport numpy as np\nimport cv2\nfrom PIL import Image\nimport matplotlib.pyplot as plt\n\nprint('Torch version :', torch.__version__)\nprint('CUDA tersedia :', torch.cuda.is_available())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-24T13:28:18.293447Z","iopub.execute_input":"2026-06-24T13:28:18.295354Z","iopub.status.idle":"2026-06-24T13:28:18.308185Z","shell.execute_reply.started":"2026-06-24T13:28:18.295242Z","shell.execute_reply":"2026-06-24T13:28:18.307111Z"}},"outputs":[],"execution_count":null},{"id":"77b43e4f-9680-4b96-84b7-5f692d465cd6","cell_type":"markdown","source":"## 2. Cari folder gambar otomatis di `/kaggle/input/`\n\nPath umum dataset COCO 2017 di Kaggle:\n`/kaggle/input/coco-2017-dataset/coco2017/val2017/`\n\nKode di bawah akan mencari sendiri folder gambarnya, jadi tetap jalan walau nama\ndataset yang Anda attach sedikit berbeda.","metadata":{}},{"id":"2551c0e8-ede8-4716-8682-ac40c28a59e2","cell_type":"code","source":"INPUT_DIR = '/kaggle/input'\n\n# Folder yang biasa dipakai (val2017 diutamakan karena lebih kecil)\npreferred = ['val2017', 'train2017', 'images', 'test2017']\n\nimage_folder = None\nfor p in preferred:\n    matches = glob.glob(f'{INPUT_DIR}/**/{p}', recursive=True)\n    if matches:\n        image_folder = matches[0]\n        break\n\n# Cadangan: cari folder mana pun yang berisi file gambar\nif image_folder is None:\n    for root, dirs, files in os.walk(INPUT_DIR):\n        if any(f.lower().endswith(('.jpg', '.jpeg', '.png')) for f in files):\n            image_folder = root\n            break\n\nprint('Folder gambar yang dipakai:', image_folder)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-24T13:28:18.310531Z","iopub.execute_input":"2026-06-24T13:28:18.311429Z","iopub.status.idle":"2026-06-24T13:29:15.785995Z","shell.execute_reply.started":"2026-06-24T13:28:18.311396Z","shell.execute_reply":"2026-06-24T13:29:15.785060Z"}},"outputs":[],"execution_count":null},{"id":"861e83ba-2fb8-49ec-8a67-36f9a1c13017","cell_type":"markdown","source":"## 3. Ambil SATU citra saja","metadata":{}},{"id":"b7dc70db-f3d9-4498-8cb1-370dbad4278a","cell_type":"code","source":"image_files = []\nfor ext in ('*.jpg', '*.jpeg', '*.png'):\n    image_files.extend(glob.glob(os.path.join(image_folder, ext)))\n\nassert len(image_files) > 0, 'Tidak ada gambar ditemukan! Pastikan dataset sudah di-attach.'\n\n# Pilih satu gambar secara acak.\n# Untuk memilih file tertentu, ganti baris di bawah, contoh:\n# IMAGE_PATH = os.path.join(image_folder, '000000039769.jpg')\nrandom.seed(0)\nIMAGE_PATH = random.choice(image_files)\nprint('Citra yang dipakai:', IMAGE_PATH)\n\n# Tampilkan citra asli\nimg_preview = Image.open(IMAGE_PATH).convert('RGB')\nplt.figure(figsize=(8, 6))\nplt.imshow(img_preview)\nplt.axis('off')\nplt.title('Citra Asli')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-24T13:29:15.787279Z","iopub.execute_input":"2026-06-24T13:29:15.787756Z","iopub.status.idle":"2026-06-24T13:29:16.098783Z","shell.execute_reply.started":"2026-06-24T13:29:15.787728Z","shell.execute_reply":"2026-06-24T13:29:16.097674Z"}},"outputs":[],"execution_count":null},{"id":"d851857a-d972-483c-b47c-97bc4da1e2dc","cell_type":"markdown","source":"## 4. Daftar kelas COCO (80 kelas + background)","metadata":{}},{"id":"b04812f1-9bca-4cf1-8efd-15577eb14917","cell_type":"code","source":"COCO_CLASSES = [\n    '__background__', 'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus',\n    'train', 'truck', 'boat', 'traffic light', 'fire hydrant', 'N/A', 'stop sign',\n    'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow',\n    'elephant', 'bear', 'zebra', 'giraffe', 'N/A', 'backpack', 'umbrella', 'N/A',\n    'N/A', 'handbag', 'tie', 'suitcase', 'frisbee', 'skis', 'snowboard', 'sports ball',\n    'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', 'tennis racket',\n    'bottle', 'N/A', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana',\n    'apple', 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut',\n    'cake', 'chair', 'couch', 'potted plant', 'bed', 'N/A', 'dining table', 'N/A',\n    'N/A', 'toilet', 'N/A', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone',\n    'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'N/A', 'book', 'clock',\n    'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'\n]\nprint('Jumlah kelas:', len(COCO_CLASSES))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-24T13:29:16.100265Z","iopub.execute_input":"2026-06-24T13:29:16.100721Z","iopub.status.idle":"2026-06-24T13:29:16.111628Z","shell.execute_reply.started":"2026-06-24T13:29:16.100673Z","shell.execute_reply":"2026-06-24T13:29:16.110411Z"}},"outputs":[],"execution_count":null},{"id":"be783128-275c-4dab-873a-776f71b7607c","cell_type":"markdown","source":"## 5. Muat model Mask R-CNN pretrained\n\n> Saat pertama dijalankan, torchvision mengunduh bobot model (~170 MB).\n> **Pastikan Internet sudah ON** di Settings notebook.","metadata":{}},{"id":"f10aa6e0-60e8-4f0d-9cc2-821d781a374e","cell_type":"code","source":"device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\nprint('Device:', device)\n\nweights = MaskRCNN_ResNet50_FPN_Weights.DEFAULT\nmodel = maskrcnn_resnet50_fpn(weights=weights)\nmodel.eval()\nmodel.to(device)\nprint('Model siap.')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-24T13:29:16.114213Z","iopub.execute_input":"2026-06-24T13:29:16.114653Z","iopub.status.idle":"2026-06-24T13:29:16.819067Z","shell.execute_reply.started":"2026-06-24T13:29:16.114622Z","shell.execute_reply":"2026-06-24T13:29:16.817895Z"}},"outputs":[],"execution_count":null},{"id":"a5670dad-99bb-4ee6-a933-b8a4ac2c8ff8","cell_type":"markdown","source":"## 6. Lakukan prediksi (inferensi)","metadata":{}},{"id":"c609f976-0b39-4462-8093-4db283fbc3ff","cell_type":"code","source":"image = Image.open(IMAGE_PATH).convert('RGB')\nimg_tensor = F.to_tensor(image).to(device)\n\nwith torch.no_grad():\n    prediction = model([img_tensor])[0]\n\nprint('Total kandidat objek:', len(prediction['scores']))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-24T13:29:16.820261Z","iopub.execute_input":"2026-06-24T13:29:16.820518Z","iopub.status.idle":"2026-06-24T13:29:21.308958Z","shell.execute_reply.started":"2026-06-24T13:29:16.820494Z","shell.execute_reply":"2026-06-24T13:29:21.307802Z"}},"outputs":[],"execution_count":null},{"id":"93aa9c12-a378-4ea6-a802-8f6b430c3233","cell_type":"markdown","source":"## 7. Visualisasi & simpan hasil\n\n`THRESHOLD` mengatur ambang kepercayaan: makin tinggi = makin sedikit objek tapi makin yakin.","metadata":{}},{"id":"670007d5-ab4c-4db3-937e-e0bcac5df468","cell_type":"code","source":"THRESHOLD = 0.5\n\nimg_np = np.array(image).copy()\nnp.random.seed(42)\n\njumlah_objek = 0\nfor i in range(len(prediction['scores'])):\n    score = prediction['scores'][i].item()\n    if score < THRESHOLD:\n        continue\n    jumlah_objek += 1\n\n    label = COCO_CLASSES[prediction['labels'][i].item()]\n    mask = prediction['masks'][i, 0].cpu().numpy() > 0.5\n    color = np.random.randint(0, 255, size=3, dtype=np.uint8)\n\n    # Tempelkan mask berwarna (semi-transparan)\n    img_np[mask] = img_np[mask] * 0.5 + color * 0.5\n\n    # Bounding box + label\n    box = prediction['boxes'][i].cpu().numpy().astype(int)\n    cv2.rectangle(img_np, (box[0], box[1]), (box[2], box[3]), color.tolist(), 2)\n    cv2.putText(img_np, f'{label} {score:.2f}', (box[0], max(box[1] - 8, 12)),\n                cv2.FONT_HERSHEY_SIMPLEX, 0.6, color.tolist(), 2)\n\nprint(f'Objek terdeteksi (score >= {THRESHOLD}): {jumlah_objek}')\n\nplt.figure(figsize=(12, 8))\nplt.imshow(img_np)\nplt.axis('off')\nplt.title('Hasil Segmentasi Mask R-CNN')\nplt.show()\n\n# Simpan ke folder output Kaggle\noutput_path = '/kaggle/working/hasil_segmentasi.jpg'\ncv2.imwrite(output_path, cv2.cvtColor(img_np, cv2.COLOR_RGB2BGR))\nprint('Hasil disimpan ke:', output_path)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-24T13:29:21.310440Z","iopub.execute_input":"2026-06-24T13:29:21.310769Z","iopub.status.idle":"2026-06-24T13:29:21.750697Z","shell.execute_reply.started":"2026-06-24T13:29:21.310742Z","shell.execute_reply":"2026-06-24T13:29:21.749120Z"}},"outputs":[],"execution_count":null}]}