Skripsi_Patric/coba.ipynb
2026-02-11 11:01:55 +07:00

588 lines
21 KiB
Plaintext

{
"cells": [
{
"cell_type": "code",
"execution_count": 6,
"id": "ddc93ea2",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Classes: ['Kaleng', 'Residu', 'botol_plastik_PET_bening2', 'botol_plastik_PET_bewarna']\n",
"✅ Model loaded\n",
"\n",
"🧠 Prediction: botol_plastik_PET_bening2\n",
"📊 Confidence: 83.07%\n"
]
}
],
"source": [
"import torch\n",
"import torch.nn as nn\n",
"from torchvision import models, transforms\n",
"from PIL import Image\n",
"\n",
"# ==========================================\n",
"# CONFIG\n",
"# ==========================================\n",
"MODEL_PATH = 'model_sampah_final_3.pth'\n",
"LABEL_PATH = 'labels.txt'\n",
"IMG_PATH = '20260204_145002.jpg'\n",
"\n",
"DEVICE = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
"\n",
"# ==========================================\n",
"# LOAD LABELS\n",
"# ==========================================\n",
"with open(LABEL_PATH, 'r') as f:\n",
" class_names = [line.strip() for line in f.readlines()]\n",
"\n",
"print(\"Classes:\", class_names)\n",
"\n",
"# ==========================================\n",
"# LOAD MODEL\n",
"# ==========================================\n",
"model = models.mobilenet_v2(weights=None)\n",
"num_ftrs = model.classifier[1].in_features\n",
"model.classifier[1] = nn.Linear(num_ftrs, len(class_names))\n",
"\n",
"model.load_state_dict(torch.load(MODEL_PATH, map_location=DEVICE))\n",
"model.to(DEVICE)\n",
"model.eval()\n",
"\n",
"print(\"✅ Model loaded\")\n",
"\n",
"# ==========================================\n",
"# PREPROCESS (SAME AS TRAINING)\n",
"# ==========================================\n",
"transform = transforms.Compose([\n",
" transforms.Resize((224, 224)),\n",
" transforms.ToTensor(),\n",
" transforms.Normalize(\n",
" mean=[0.485, 0.456, 0.406],\n",
" std=[0.229, 0.224, 0.225]\n",
" )\n",
"])\n",
"\n",
"# ==========================================\n",
"# LOAD IMAGE\n",
"# ==========================================\n",
"img = Image.open(IMG_PATH).convert(\"RGB\")\n",
"input_tensor = transform(img).unsqueeze(0).to(DEVICE)\n",
"\n",
"# ==========================================\n",
"# INFERENCE\n",
"# ==========================================\n",
"with torch.no_grad():\n",
" outputs = model(input_tensor)\n",
" probs = torch.softmax(outputs, dim=1)\n",
" confidence, pred = torch.max(probs, 1)\n",
"\n",
"# ==========================================\n",
"# RESULT\n",
"# ==========================================\n",
"label = class_names[pred.item()]\n",
"score = confidence.item()\n",
"\n",
"print(f\"\\n🧠 Prediction: {label}\")\n",
"print(f\"📊 Confidence: {score*100:.2f}%\")\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "17588856",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Folder 'data_gambar' berhasil dibuat!\n",
"\n",
"--- INSTRUKSI ---\n",
"Tekan 'S' untuk menyimpan gambar (Crop)\n",
"Tekan 'Q' untuk keluar\n",
"Berhasil disimpan: data_gambar/gambar_20260204_142759.jpg\n"
]
}
],
"source": [
"import cv2\n",
"import os\n",
"import time\n",
"\n",
"# --- KONFIGURASI ---\n",
"NAMA_FOLDER = \"data_gambar\" # Nama folder penyimpanan\n",
"UKURAN_BOX = 300 # Ukuran kotak ROI (piksel)\n",
"\n",
"# 1. CEK & BUAT FOLDER JIKA BELUM ADA\n",
"if not os.path.exists(NAMA_FOLDER):\n",
" os.makedirs(NAMA_FOLDER)\n",
" print(f\"Folder '{NAMA_FOLDER}' berhasil dibuat!\")\n",
"else:\n",
" print(f\"Folder '{NAMA_FOLDER}' sudah ada. Gambar akan disimpan di sana.\")\n",
"\n",
"# 2. SETUP KAMERA\n",
"cap = cv2.VideoCapture(0)\n",
"\n",
"print(\"\\n--- INSTRUKSI ---\")\n",
"print(\"Tekan 'S' untuk menyimpan gambar (Crop)\")\n",
"print(\"Tekan 'Q' untuk keluar\")\n",
"\n",
"while True:\n",
" ret, frame = cap.read()\n",
" if not ret:\n",
" print(\"Gagal membaca kamera\")\n",
" break\n",
"\n",
" # Flip frame (efek cermin)\n",
" frame = cv2.flip(frame, 1)\n",
"\n",
" # 3. HITUNG KOORDINAT ROI (TENGAH)\n",
" height, width, _ = frame.shape\n",
" x1 = (width - UKURAN_BOX) // 2\n",
" y1 = (height - UKURAN_BOX) // 2\n",
" x2 = x1 + UKURAN_BOX\n",
" y2 = y1 + UKURAN_BOX\n",
"\n",
" # 4. GAMBAR KOTAK PANDUAN (HIJAU)\n",
" # Ini hanya visualisasi, tidak ikut tersimpan saat di-crop nanti\n",
" cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)\n",
" \n",
" # Tambahkan teks instruksi di layar\n",
" cv2.putText(frame, \"Tekan 'S' untuk Simpan\", (x1, y2 + 25), \n",
" cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 1)\n",
"\n",
" # Tampilkan layar\n",
" cv2.imshow('Kamera Pengumpul Data', frame)\n",
"\n",
" # 5. BACA TOMBOL KEYBOARD\n",
" key = cv2.waitKey(1) & 0xFF\n",
"\n",
" # --- LOGIKA SIMPAN (CROP) ---\n",
" if key == ord('s') or key == ord('S'):\n",
" # Ambil potongan gambar asli (bersih tanpa garis kotak hijau)\n",
" # Kita ambil dari koordinat yang sudah dihitung di atas\n",
" roi_crop = frame[y1:y2, x1:x2]\n",
"\n",
" # Buat nama file unik (berdasarkan waktu detik ini)\n",
" timestamp = time.strftime(\"%Y%m%d_%H%M%S\")\n",
" filename = f\"{NAMA_FOLDER}/gambar_{timestamp}.jpg\"\n",
"\n",
" # Simpan ke folder\n",
" cv2.imwrite(filename, roi_crop)\n",
" print(f\"Berhasil disimpan: {filename}\")\n",
" \n",
" # Efek visual sesaat (layar berkedip putih sedikit tanda tersimpan) - Opsional\n",
" cv2.putText(frame, \"TERSIMPAN!\", (x1, y1-10), \n",
" cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)\n",
" cv2.imshow('Kamera Pengumpul Data', frame)\n",
" cv2.waitKey(200) # Jeda sebentar biar tulisan terbaca\n",
"\n",
" # Keluar program\n",
" elif key == ord('q'):\n",
" break\n",
"\n",
"cap.release()\n",
"cv2.destroyAllWindows()"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "724ac841",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Sedang memuat model... (tunggu sebentar)\n",
"Model siap!\n"
]
}
],
"source": [
"import cv2\n",
"import numpy as np\n",
"import tensorflow as tf\n",
"from tensorflow.keras.applications.mobilenet_v2 import MobileNetV2, preprocess_input, decode_predictions\n",
"from tensorflow.keras.preprocessing import image\n",
"\n",
"# 1. INISIALISASI MODEL\n",
"print(\"Sedang memuat model... (tunggu sebentar)\")\n",
"model = MobileNetV2(weights='imagenet', include_top=True)\n",
"print(\"Model siap!\")\n",
"\n",
"# 2. SETUP KAMERA\n",
"cap = cv2.VideoCapture(0) \n",
"\n",
"# Ukuran kotak ROI\n",
"BOX_SIZE = 300 \n",
"\n",
"while True:\n",
" ret, frame = cap.read()\n",
" if not ret:\n",
" break\n",
"\n",
" # Flip frame (efek cermin)\n",
" frame = cv2.flip(frame, 1)\n",
"\n",
" # Ambil ukuran frame\n",
" height, width, _ = frame.shape\n",
" \n",
" # Hitung koordinat tengah untuk kotak hijau\n",
" x1 = (width - BOX_SIZE) // 2\n",
" y1 = (height - BOX_SIZE) // 2\n",
" x2 = x1 + BOX_SIZE\n",
" y2 = y1 + BOX_SIZE\n",
"\n",
" # --- PROSES AI (Latar Belakang) ---\n",
" # Kita tetap perlu crop gambar untuk diserahkan ke AI,\n",
" # tapi tidak kita tempel/tampilkan ke layar utama.\n",
" roi_frame = frame[y1:y2, x1:x2]\n",
"\n",
" if roi_frame.size != 0:\n",
" # Resize ke 224x224 (Wajib untuk MobileNet)\n",
" img_input = cv2.resize(roi_frame, (224, 224))\n",
" \n",
" # Konversi ke array & preprocess\n",
" img_array = image.img_to_array(img_input)\n",
" img_array = np.expand_dims(img_array, axis=0)\n",
" img_array = preprocess_input(img_array)\n",
"\n",
" # Prediksi\n",
" preds = model.predict(img_array, verbose=0)\n",
" results = decode_predictions(preds, top=1)[0]\n",
" \n",
" # Ambil Label & Akurasi\n",
" label = results[0][1]\n",
" confidence = results[0][2] * 100\n",
"\n",
" # Tampilkan Teks Hasil Prediksi di atas kotak\n",
" text_display = f\"{label}: {confidence:.1f}%\"\n",
" cv2.putText(frame, text_display, (x1, y1 - 10), \n",
" cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)\n",
"\n",
" # --- VISUALISASI UTAMA ---\n",
" # Hanya gambar kotak hijau panduan\n",
" cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)\n",
" \n",
" # Tampilkan layar utama saja\n",
" cv2.imshow('MobileNetV2 Clean View', frame)\n",
"\n",
" if cv2.waitKey(1) & 0xFF == ord('q'):\n",
" break\n",
"\n",
"cap.release()\n",
"cv2.destroyAllWindows()"
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "95017f76",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Memulai proses download ke folder 'dataset_botol_bewarna_bing'...\n",
"\n",
"--> Sedang mencari gambar: Super O2\n",
"[%] Downloading Images to g:\\My Drive\\Smart-Bin\\dataset\\dataset_botol_bewarna_bing\\Super O2\n",
"[!] Issue getting: https://img.21food.com/img/product/2012/10/25/indogalung-01510470.jpg\n",
"[!] Error:: Remote end closed connection without response\n",
"[Error]Invalid image, not saving https://lookaside.fbsbx.com/lookaside/crawler/media/?media_id=4116299515060023\n",
"\n",
"[!] Issue getting: https://lookaside.fbsbx.com/lookaside/crawler/media/?media_id=4116299515060023\n",
"[!] Error:: Invalid image, not saving https://lookaside.fbsbx.com/lookaside/crawler/media/?media_id=4116299515060023\n",
"\n",
"[Error]Invalid image, not saving https://down-id.img.susercontent.com/file/039e5682e363425a1b87b8a725a4253e\n",
"\n",
"[!] Issue getting: https://down-id.img.susercontent.com/file/039e5682e363425a1b87b8a725a4253e\n",
"[!] Error:: Invalid image, not saving https://down-id.img.susercontent.com/file/039e5682e363425a1b87b8a725a4253e\n",
"\n",
"[Error]Invalid image, not saving https://cf.shopee.co.id/file/734aeebfee8922e2c5ec88523cb5e6e5_tn\n",
"\n",
"[!] Issue getting: https://cf.shopee.co.id/file/734aeebfee8922e2c5ec88523cb5e6e5_tn\n",
"[!] Error:: Invalid image, not saving https://cf.shopee.co.id/file/734aeebfee8922e2c5ec88523cb5e6e5_tn\n",
"\n",
"[Error]Invalid image, not saving https://down-id.img.susercontent.com/file/9bd8bd58dc85b83e4944981ce2f97e73\n",
"\n",
"[!] Issue getting: https://down-id.img.susercontent.com/file/9bd8bd58dc85b83e4944981ce2f97e73\n",
"[!] Error:: Invalid image, not saving https://down-id.img.susercontent.com/file/9bd8bd58dc85b83e4944981ce2f97e73\n",
"\n",
"[!] Issue getting: https://ceklist.id/wp-content/uploads/2023/12/2858-super-o2-air-mineral-sportivo-600ml-1-370x370.jpg\n",
"[!] Error:: <urlopen error [WinError 10060] A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond>\n",
"[Error]Invalid image, not saving https://down-id.img.susercontent.com/file/sg-11134201-23010-r89m6d1to1lv22\n",
"\n",
"[!] Issue getting: https://down-id.img.susercontent.com/file/sg-11134201-23010-r89m6d1to1lv22\n",
"[!] Error:: Invalid image, not saving https://down-id.img.susercontent.com/file/sg-11134201-23010-r89m6d1to1lv22\n",
"\n",
"[Error]Invalid image, not saving https://down-id.img.susercontent.com/file/734aeebfee8922e2c5ec88523cb5e6e5\n",
"\n",
"[!] Issue getting: https://down-id.img.susercontent.com/file/734aeebfee8922e2c5ec88523cb5e6e5\n",
"[!] Error:: Invalid image, not saving https://down-id.img.susercontent.com/file/734aeebfee8922e2c5ec88523cb5e6e5\n",
"\n",
"[Error]Invalid image, not saving https://down-id.img.susercontent.com/file/0859ac0c9a420144d06c20bd2a16d154\n",
"\n",
"[!] Issue getting: https://down-id.img.susercontent.com/file/0859ac0c9a420144d06c20bd2a16d154\n",
"[!] Error:: Invalid image, not saving https://down-id.img.susercontent.com/file/0859ac0c9a420144d06c20bd2a16d154\n",
"\n",
"\n",
"\n",
"[%] Done. Downloaded 50 images.\n",
" Selesai download Super O2!\n",
"\n",
"========================================\n",
"SEMUA SELESAI!\n",
"Cek folder 'dataset_botol_bewarna_bing' di komputer Anda.\n"
]
}
],
"source": [
"from bing_image_downloader import downloader\n",
"import os\n",
"\n",
"# --- KONFIGURASI ---\n",
"# 1. Tentukan folder penyimpanan utama\n",
"NAMA_FOLDER_UTAMA = \"dataset_botol_bewarna_bing\"\n",
"\n",
"# 2. Tentukan kata kunci benda yang mau dicari\n",
"# Format: \"Kata Kunci\"\n",
"daftar_pencarian = [\n",
" \"Super O2\"\n",
"]\n",
"\n",
"# 3. Berapa banyak gambar per benda?\n",
"JUMLAH_GAMBAR = 50 # Jangan terlalu banyak dulu untuk tes (max 100-200 aman)\n",
"\n",
"# --- MULAI DOWNLOAD ---\n",
"print(f\"Memulai proses download ke folder '{NAMA_FOLDER_UTAMA}'...\\n\")\n",
"\n",
"for kata_kunci in daftar_pencarian:\n",
" print(f\"--> Sedang mencari gambar: {kata_kunci}\")\n",
" \n",
" downloader.download(\n",
" kata_kunci, \n",
" limit=JUMLAH_GAMBAR, \n",
" output_dir=NAMA_FOLDER_UTAMA, \n",
" adult_filter_off=True, # Matikan filter konten dewasa (aman untuk objek umum)\n",
" force_replace=False, \n",
" timeout=60, \n",
" verbose=False\n",
" )\n",
" print(f\" Selesai download {kata_kunci}!\\n\")\n",
"\n",
"print(\"=\"*40)\n",
"print(\"SEMUA SELESAI!\")\n",
"print(f\"Cek folder '{NAMA_FOLDER_UTAMA}' di komputer Anda.\")"
]
},
{
"cell_type": "code",
"execution_count": 23,
"id": "643a9a12",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Ditemukan 339 gambar asli.\n",
"Memproses dengan Threading...\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
" 27%|██▋ | 90/339 [04:21<04:26, 1.07s/it] c:\\Users\\MSI-PC\\miniconda3\\envs\\skripsi\\lib\\site-packages\\PIL\\Image.py:1034: UserWarning: Palette images with Transparency expressed in bytes should be converted to RGBA images\n",
" warnings.warn(\n",
"100%|██████████| 339/339 [06:42<00:00, 1.19s/it]"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"SUKSES!\n",
"Cek hasil di folder: dataset_augmented/botol_plastik_PET_bewarna\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"\n"
]
}
],
"source": [
"import os\n",
"import cv2\n",
"import numpy as np\n",
"from tensorflow.keras.preprocessing.image import ImageDataGenerator, img_to_array, load_img\n",
"# GANTI DARI ProcessPoolExecutor KE ThreadPoolExecutor\n",
"from concurrent.futures import ThreadPoolExecutor \n",
"from tqdm import tqdm \n",
"\n",
"# --- KONFIGURASI ---\n",
"FOLDER_SUMBER = \"botol_plastik_PET_bewarna2\"\n",
"FOLDER_HASIL = \"dataset_augmented/botol_plastik_PET_bewarna\"\n",
"JUMLAH_COPY = 5\n",
"NAMA_BASE = \"botol_pet\"\n",
"# Threading lebih ringan, kita bisa set angka aman misal 4 atau 8 worker\n",
"MAX_WORKERS = 4 \n",
"\n",
"if not os.path.exists(FOLDER_HASIL):\n",
" os.makedirs(FOLDER_HASIL)\n",
"\n",
"# Fungsi Worker \n",
"def proses_gambar_spesifik(data):\n",
" filepath, index_awal = data\n",
" \n",
" try:\n",
" # Load gambar\n",
" img = load_img(filepath)\n",
" x = img_to_array(img)\n",
" x = x.reshape((1,) + x.shape)\n",
"\n",
" # Definisikan ImageDataGenerator DI DALAM fungsi agar thread-safe\n",
" datagen = ImageDataGenerator(\n",
" rotation_range=30,\n",
" width_shift_range=0.2,\n",
" height_shift_range=0.2,\n",
" shear_range=0.2,\n",
" zoom_range=0.2,\n",
" horizontal_flip=True,\n",
" fill_mode='nearest'\n",
" )\n",
" \n",
" # Loop generate gambar\n",
" i = 0\n",
" for batch in datagen.flow(x, batch_size=1):\n",
" gambar_aug = batch[0].astype('uint8') \n",
" gambar_aug = cv2.cvtColor(gambar_aug, cv2.COLOR_RGB2BGR)\n",
" \n",
" nomor_urut = index_awal + i\n",
" nama_file_baru = f\"{NAMA_BASE}_{nomor_urut:05d}.jpg\"\n",
" path_simpan = os.path.join(FOLDER_HASIL, nama_file_baru)\n",
" \n",
" cv2.imwrite(path_simpan, gambar_aug)\n",
" \n",
" i += 1\n",
" if i >= JUMLAH_COPY:\n",
" break\n",
" \n",
" except Exception as e:\n",
" print(f\"Error pada {filepath}: {e}\")\n",
"\n",
"# --- MAIN PROGRAM ---\n",
"if __name__ == '__main__':\n",
" semua_file = [f for f in os.listdir(FOLDER_SUMBER) \n",
" if f.lower().endswith(('.png', '.jpg', '.jpeg'))]\n",
" semua_file.sort()\n",
" \n",
" print(f\"Ditemukan {len(semua_file)} gambar asli.\")\n",
" print(f\"Memproses dengan Threading...\")\n",
"\n",
" tasks = []\n",
" counter = 1\n",
" \n",
" for nama_file in semua_file:\n",
" full_path = os.path.join(FOLDER_SUMBER, nama_file)\n",
" tasks.append((full_path, counter))\n",
" counter += JUMLAH_COPY\n",
"\n",
" # GUNAKAN ThreadPoolExecutor\n",
" with ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor:\n",
" list(tqdm(executor.map(proses_gambar_spesifik, tasks), total=len(tasks)))\n",
"\n",
" print(\"\\nSUKSES!\")\n",
" print(f\"Cek hasil di folder: {FOLDER_HASIL}\")"
]
},
{
"cell_type": "code",
"execution_count": 24,
"id": "f865eb1c",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Ditemukan 1695 file. Memulai rename...\n",
"Selesai! Semua file sudah direname.\n"
]
}
],
"source": [
"import os\n",
"\n",
"# --- KONFIGURASI ---\n",
"FOLDER_TARGET = \"dataset_augmented/botol_plastik_PET_bewarna\" # Ganti dengan nama foldermu\n",
"NAMA_BARU = \"botol_pet_bewarna\" # Awalan nama file baru\n",
"\n",
"# 1. Ambil semua file gambar\n",
"files = [f for f in os.listdir(FOLDER_TARGET) \n",
" if f.lower().endswith(('.png', '.jpg', '.jpeg'))]\n",
"\n",
"# 2. Urutkan dulu (biar tidak acak)\n",
"files.sort()\n",
"\n",
"print(f\"Ditemukan {len(files)} file. Memulai rename...\")\n",
"\n",
"# 3. Proses Rename\n",
"for index, nama_file_lama in enumerate(files):\n",
" # Ambil ekstensi file asli (.jpg atau .png)\n",
" ekstensi = os.path.splitext(nama_file_lama)[1]\n",
" \n",
" # Buat nama baru dengan format 5 digit angka (00001)\n",
" # index + 1 agar mulai dari 1, bukan 0\n",
" nama_file_baru = f\"{NAMA_BARU}_{index + 1:05d}{ekstensi}\"\n",
" \n",
" # Gabungkan dengan path folder\n",
" path_lama = os.path.join(FOLDER_TARGET, nama_file_lama)\n",
" path_baru = os.path.join(FOLDER_TARGET, nama_file_baru)\n",
" \n",
" # Lakukan rename\n",
" try:\n",
" os.rename(path_lama, path_baru)\n",
" except OSError as e:\n",
" print(f\"Error pada {nama_file_lama}: {e}\")\n",
"\n",
"print(\"Selesai! Semua file sudah direname.\")"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "skripsi",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.19"
}
},
"nbformat": 4,
"nbformat_minor": 5
}