import streamlit as st import joblib import numpy as np import cv2 from PIL import Image import os from skimage.feature import local_binary_pattern, graycomatrix, graycoprops # --- KONFIGURASI HALAMAN --- st.set_page_config(page_title="Weather Classifier", layout="wide") # --- FUNGSI LOAD MODEL --- @st.cache_resource def load_models(algorithm): try: # Sesuaikan path ini dengan struktur foldermu base_path = "model" if algorithm == 'SVM': # Pastikan nama file di dalam folder model/svm/ sesuai dengan yang ada model_path = os.path.join(base_path, "svm/svm_model_optimal_80_20.joblib") scaler_path = os.path.join(base_path, "svm/scaler_svm.joblib") le_path = os.path.join(base_path, "svm/label_encoder.joblib") model = joblib.load(model_path) scaler = joblib.load(scaler_path) le = joblib.load(le_path) elif algorithm == 'XGBoost': # Pastikan nama file di dalam folder model/xgboost/ sesuai model_path = os.path.join(base_path, "xgboost/xgb_model_optimal.joblib") le_path = os.path.join(base_path, "xgboost/label_encoder_xgb.joblib") model = joblib.load(model_path) scaler = None le = joblib.load(le_path) return model, scaler, le except Exception as e: st.error(f"Error loading model files: {e}") return None, None, None # --- FUNGSI EKSTRAKSI FITUR (GLCM, LBP, HSV) --- def extract_features_final(image_pil): img_np = np.array(image_pil.convert('RGB')) # Resize (Samakan dengan training, misal 128x128 atau 224x224) img_np = cv2.resize(img_np, (224, 224)) # Preprocessing hsv_image = cv2.cvtColor(img_np, cv2.COLOR_RGB2HSV) h = hsv_image[:, :, 0] s = hsv_image[:, :, 1] gray = cv2.cvtColor(img_np, cv2.COLOR_RGB2GRAY) clahe_builder = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8)) gray_clahe = clahe_builder.apply(gray) # Ekstraksi Fitur hist_h = cv2.calcHist([h], [0], None, [8], [0, 256]).flatten() hist_s = cv2.calcHist([s], [0], None, [8], [0, 256]).flatten() lbp = local_binary_pattern(gray_clahe, P=8, R=1, method='uniform') lbp_hist, _ = np.histogram(lbp.ravel(), bins=np.arange(0, 10), range=(0, 9)) lbp_hist = lbp_hist.astype('float') lbp_hist /= (lbp_hist.sum() + 1e-6) glcm = graycomatrix(gray_clahe, distances=[1], angles=[0], symmetric=True, normed=True) contrast = graycoprops(glcm, 'contrast')[0, 0] energy = graycoprops(glcm, 'energy')[0, 0] homogeneity = graycoprops(glcm, 'homogeneity')[0, 0] features = np.hstack([hist_h, hist_s, lbp_hist, contrast, energy, homogeneity]) return features.reshape(1, -1) # --- UI UTAMA (WEATHER THEME) --- st.title("☁️ Weather Classification App 🌦️") st.write("Klasifikasi Cuaca (Cloudy, Rainy, Shine, Sunrise) menggunakan SVM & XGBoost") algo_choice = st.sidebar.selectbox("Pilih Algoritma:", ["SVM", "XGBoost"]) uploaded_file = st.file_uploader("Upload foto cuaca...", type=["jpg", "png", "jpeg"]) if uploaded_file is not None: image = Image.open(uploaded_file) col1, col2 = st.columns(2) with col1: st.image(image, caption='Gambar Diupload', use_column_width=True) if st.button("Tebak Cuaca"): with st.spinner("Sedang menganalisis tekstur & warna langit..."): model, scaler, le = load_models(algo_choice) if model: try: features = extract_features_final(image) if scaler: features = scaler.transform(features) prediction_index = model.predict(features)[0] # Label otomatis menyesuaikan (Cloudy/Rainy/dll) dari file label_encoder label = le.inverse_transform([prediction_index])[0] with col2: st.success(f"### Prediksi: {label}") st.info(f"Model: {algo_choice}") except Exception as e: st.error(f"Error: {e}")