# %% [markdown] # # 🧠 Face Recognition Pipeline: Mandiri, Lengkap & Visual # Ini adalah perpaduan kode yang **sangat sederhana** (mengambil 100 frame tanpa crop), # ditambah dengan **Gambar Pendukung (Visualisasi Matplotlib)** agar outputnya tidak sekadar # teks melainkan bisa Anda lihat perubahan bentuk wajahnya per langkah! # %% [markdown] # ## Tahap 1: Persiapan Library # %% import cv2 import os import numpy as np import matplotlib.pyplot as plt from sklearn.svm import SVC from sklearn.preprocessing import StandardScaler from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score print("✅ Library ter-load dengan baik!") # %% [markdown] # ## Tahap 2: Ektraksi 100 Frame dari Video Asli 🎥 (Tanpa Potong Wajah) # %% VIDEO_DIR = r"C:\xampp\htdocs\mpg-hris\storage\app\private\face_videos" kumpulan_gambar_mentah = {} print("🎬 Membaca video enrollment...\n") for user_id in sorted(os.listdir(VIDEO_DIR)): video_path = os.path.join(VIDEO_DIR, user_id, "enrollment.mp4") if not os.path.exists(video_path): continue cap = cv2.VideoCapture(video_path) gambar_dikumpulkan = [] while len(gambar_dikumpulkan) < 100: ret, frame = cap.read() if not ret: break gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) frame_kecil = cv2.resize(gray, (128, 128)) # Dikecilkan langsung gambar_dikumpulkan.append(frame_kecil) # [BARU] Simpan langsung ke folder, agar Anda bisa lihat filenya! simpan_folder = f"hasil_1_ekstrak_asli/user_{user_id}" os.makedirs(simpan_folder, exist_ok=True) # Menulis foto ke harddisk cv2.imwrite(f"{simpan_folder}/frame_{len(gambar_dikumpulkan)}.jpg", frame_kecil) cap.release() kumpulan_gambar_mentah[user_id] = gambar_dikumpulkan print(f" 👤 User {user_id}: Berhasil mengambil {len(gambar_dikumpulkan)} gambar utuh.") # %% [markdown] # ## 📸 Mari Kita Intip Dulu Gambarnya! # Berikut adalah bagaimana rupa 1 gambar contoh dari video (karena tanpa proses # crop/potong letak wajah, gambarnya sangat lebar dengan background-nya dominan) # %% # Tampilkan 4 user pertama fig, axes = plt.subplots(1, 4, figsize=(15, 4)) user_terurut = list(kumpulan_gambar_mentah.keys()) for i, ax in enumerate(axes): if i < len(user_terurut): contoh_user = user_terurut[i] contoh_foto = kumpulan_gambar_mentah[contoh_user][10] # Ambil frame ke 10 ax.imshow(contoh_foto, cmap='gray') ax.set_title(f"Frame Asli User {contoh_user}", fontsize=12, fontweight='bold') ax.axis('off') plt.tight_layout() plt.show() # %% [markdown] # ## Tahap 3: Fungsi Pola Jadi Angka (Algoritma LBP) 🔢 # %% def ubah_wajah_jadi_angka_lbp(gambar): """ 1. Filter CLAHE: Terangkan bagian wajah yg kena bayangan/gelap. 2. LBP (Radius 1): Sandi tekstur dengan membandingkan 8 titik berdekatan. 3. Jadikan histogram. """ clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8)) gambar_jelas = clahe.apply(gambar) tinggi, lebar = gambar_jelas.shape pola_lbp = np.zeros((tinggi, lebar), dtype=np.uint8) for y in range(1, tinggi-1): for x in range(1, lebar-1): pusat = gambar_jelas[y, x] biner = 0 biner |= (gambar_jelas[y-1, x-1] >= pusat) << 7 biner |= (gambar_jelas[y-1, x] >= pusat) << 6 biner |= (gambar_jelas[y-1, x+1] >= pusat) << 5 biner |= (gambar_jelas[y, x+1] >= pusat) << 4 biner |= (gambar_jelas[y+1, x+1] >= pusat) << 3 biner |= (gambar_jelas[y+1, x] >= pusat) << 2 biner |= (gambar_jelas[y+1, x-1] >= pusat) << 1 biner |= (gambar_jelas[y, x-1] >= pusat) << 0 pola_lbp[y, x] = biner histogram,_ = np.histogram(pola_lbp, bins=256, range=(0, 256), density=True) # Supaya bisa dilihat untuk chart, saya return pola_lbp nya juga (Tapi histogram yg utama!) return histogram, gambar_jelas, pola_lbp print("✅ Fungsi ekstraksi LBP sudah dibuat!") # %% [markdown] # ## 📸 Mari Kita Intip BAGAIMANA LBP Bekerja (Proses Sulapnya) # Apa yang terjadi pada gambar kalau dimasukkan ke fungsi LBP di atas? # %% contoh_foto = kumpulan_gambar_mentah[user_terurut[0]][10] hist, efek_clahe, efek_lbp = ubah_wajah_jadi_angka_lbp(contoh_foto) fig, axes = plt.subplots(1, 3, figsize=(15, 5)) # Foto 1: Original axes[0].imshow(contoh_foto, cmap='gray') axes[0].set_title("1. Hitam Putih Original", fontsize=12) # Foto 2: Setelah CLAHE axes[1].imshow(efek_clahe, cmap='gray') axes[1].set_title("2. Efek CLAHE (Pinggiran Menonjol)", fontsize=12) # Foto 3: Hasil Akhir matriks LBP axes[2].imshow(efek_lbp, cmap='gray') axes[2].set_title("3. Sandi Tekstur LBP", fontsize=12) for ax in axes: ax.axis('off') plt.tight_layout() plt.show() # Kemudian ini histogram dari LBP (Bentuk Akhirnya Berupa Grafik/Angka 256 elemen) plt.figure(figsize=(12, 3)) plt.plot(hist, color='blue', linewidth=2) plt.title(f"4. Dan Inilah Histogram/Angka Akhirnya yang Dikirim ke Otak SVM", fontsize=12) plt.xlabel("Kode LBP (0 - 255)") plt.ylabel("Berapa Kali Muncul") plt.fill_between(range(256), hist, color='blue', alpha=0.3) plt.show() # %% [markdown] # ## Tahap 4: Proses Ratusan Gambar Sekaligus 🔄 # %% X_all = [] # Simpan hasil array angkanya y_all = [] # Simpan User ID print("⚙️ Tolong ditunggu, mengolah seluruh gambar menjadi Array Matriks LBP...") for user_id, daftar_foto in kumpulan_gambar_mentah.items(): counter_foto = 1 # Penghitung nama file for foto in daftar_foto: fitur_angka, efek_clahe, efek_lbp = ubah_wajah_jadi_angka_lbp(foto) # [BARU] Menyimpan foto hasil operasi komputer ke folder! folder_clahe = f"hasil_2_clahe/user_{user_id}" folder_lbp = f"hasil_3_lbp/user_{user_id}" os.makedirs(folder_clahe, exist_ok=True) os.makedirs(folder_lbp, exist_ok=True) cv2.imwrite(f"{folder_clahe}/clahe_{counter_foto}.jpg", efek_clahe) cv2.imwrite(f"{folder_lbp}/lbp_{counter_foto}.jpg", efek_lbp) counter_foto += 1 X_all.append(fitur_angka) y_all.append(user_id) X = np.array(X_all) y = np.array(y_all) print(f"✅ Otak buatan memiliki {len(X)} sampel matriks utuh!") # %% [markdown] # ## Tahap 5: Belajar (Training 80% Data ke SVM) 🎓 # Mari kita bedah *"Jeroan"* mesin ini! Karena selama ini selesainya terlalu instan/cepat, # kita akan menyalakan mode `verbose=True` agar mesin melaporkan jurnal perhitungannya ke kita. # Serta kita gunakan trik `PCA` untuk menekan 256 angka abstrak tadi jadi grafik kordinat 2D (X dan Y) # yang bisa dilihat mata manusia! # %% from sklearn.decomposition import PCA X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) X_test_scaled = scaler.transform(X_test) print(f"🧠 AI (SVM) mulai menghafal rumus batas untuk {len(X_train)} gambar Training...") print("=================== ISI KEPALA MESIN (LIBSVM LOG) ===================") # verbose=True = Tampilkan seluruh hitungan angka kalibrasi matematisnya ai_model = SVC(kernel='rbf', C=5, verbose=True) ai_model.fit(X_train_scaled, y_train) print("=====================================================================") print(f"✅ Selesai Menghafal!") # %% [markdown] # ## 📸 Visualisasi Dimensi Belajar Komputer (PCA) # Komputer menganalisa grafik dari 256 sudut/dimensi secara bersamaan. # Manusia hanya mampu melihat 2 Dimensi (kiri-kanan X, atas-bawah Y). # Berikut adalah bagaimana komputer membuat "wilayah zona wajah" dari setiap User. # %% # Paksa padatkan 256 fitur LBP menjadi hanya 2 fitur untuk bisa dipajang pca = PCA(n_components=2) X_train_2d = pca.fit_transform(X_train_scaled) plt.figure(figsize=(10, 6)) colors = ['crimson', 'forestgreen', 'royalblue', 'orange', 'purple', 'black'] user_unik = np.unique(y_train) for idx, user_vid in enumerate(user_unik): mask = (y_train == user_vid) plt.scatter(X_train_2d[mask, 0], X_train_2d[mask, 1], c=colors[idx % len(colors)], label=f"Zona Wajah {user_vid}", alpha=0.8, edgecolors='k', s=60) # Tambahkan Judul & Aksesoris plt.title("Visualisasi Peta Memori Otak SVM Setelah Training", fontsize=14, fontweight='bold') plt.xlabel("Dimensi Pola Pipi & Mata (Disederhanakan)") plt.ylabel("Dimensi Pola Rahang & Bibir (Disederhanakan)") plt.legend() plt.grid(True, linestyle='--', alpha=0.5) # Bikin kotak merah batas agar terlihat seperti area pemisah (Decision Boundary) plt.axvline(x=0, color='grey', linewidth=1) plt.axhline(y=0, color='grey', linewidth=1) plt.show() # %% [markdown] # ## Tahap 6: Ujian AI (Testing Ulang ke 20% Data) 📝 # %% jawaban_ai = ai_model.predict(X_test_scaled) akurasi = accuracy_score(y_test, jawaban_ai) # Supaya menarik, kita tampilkan pakai Plot! # Kita hitung dulu akurasi per User user_unik = np.unique(y_test) akurasi_tiap_user = {} for u in user_unik: benar = sum(1 for asli, tebak in zip(y_test, jawaban_ai) if asli == u and tebak == u) total_ujian = sum(1 for asli in y_test if asli == u) akurasi_tiap_user[u] = (benar / total_ujian) * 100 if total_ujian > 0 else 0 plt.figure(figsize=(8, 4)) bars = plt.bar(akurasi_tiap_user.keys(), akurasi_tiap_user.values(), color=['red','green','blue','orange']) plt.title(f"Akurasi Test Keseluruhan: {akurasi*100:.2f} %", fontsize=14, fontweight='bold') plt.xlabel("ID Pegawai") plt.ylabel("Akurasi (%)") plt.ylim(0, 110) # Tambah text persen di atas tiap batang grafiknya for bar in bars: plt.text(bar.get_x() + bar.get_width()/2 - 0.15, bar.get_height() + 2, f"{bar.get_height():.0f}%", fontweight='bold') plt.show() print("\nDetail Singkat (10 Tebakan Pertama):") for i in range(min(10, len(y_test))): kunci = y_test[i] tebakan = jawaban_ai[i] if kunci == tebakan: print(f"[{i+1:02d}] Asli: User {kunci:<3} \t|Tebakan: User {tebakan:<3} ✅") else: print(f"[{i+1:02d}] Asli: User {kunci:<3} \t|Tebakan: User {tebakan:<3} ❌")