pidoko/textureClassification
0
1import logging2from typing import Tuple3import numpy as np4import pandas as pd5import cv26import matplotlib.pyplot as plt7import seaborn as sns8from pathlib import Path9from sklearn.model_selection import train_test_split, GridSearchCV10from sklearn.preprocessing import StandardScaler11from sklearn.ensemble import RandomForestClassifier12from sklearn.svm import SVC13from sklearn.neighbors import KNeighborsClassifier14from sklearn.linear_model import LogisticRegression15from sklearn.metrics import accuracy_score, classification_report, confusion_matrix16import gradio as gr17from config import OUTPUT_DIR, IMAGE_SIZE, DISTANCES, ANGLES, LBP_RADIUS, LBP_POINTS, LBP_METHOD18 19# Setup Logging20logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")21 22# Paths to feature datasets23glcm_csv_path = Path(OUTPUT_DIR) / "texture_features_glcm.csv"24lbp_csv_path = Path(OUTPUT_DIR) / "texture_features_lbp.csv"25 26 27def load_datasets() -> Tuple[pd.DataFrame, pd.DataFrame]:28 """Load GLCM and LBP datasets separately with validation."""29 if not glcm_csv_path.exists() or not lbp_csv_path.exists():30 raise FileNotFoundError("One or both dataset files (GLCM or LBP) are missing.")31 32 df_glcm = pd.read_csv(glcm_csv_path)33 df_lbp = pd.read_csv(lbp_csv_path)34 35 return df_glcm, df_lbp36 37 38def preprocess_data(df: pd.DataFrame):39 """Splits data into train/test sets and applies standardization."""40 X = df.drop(columns=["label"])41 y = df["label"]42 43 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42, stratify=y)44 45 scaler = StandardScaler()46 X_train_scaled = scaler.fit_transform(X_train)47 X_test_scaled = scaler.transform(X_test)48 49 return X_train_scaled, X_test_scaled, y_train, y_test, scaler50 51 52def train_models(X_train, y_train):53 """Trains multiple classifiers using GridSearchCV."""54 param_grids = {55 "Random Forest": {56 "model": RandomForestClassifier(random_state=42),57 "params": {"n_estimators": [50, 100, 200], "max_depth": [None, 10, 20]},58 },59 "SVM": {60 "model": SVC(random_state=42),61 "params": {"C": [0.1, 1, 10], "kernel": ["linear", "rbf"]},62 },63 "k-NN": {64 "model": KNeighborsClassifier(),65 "params": {"n_neighbors": [3, 5, 7], "weights": ["uniform", "distance"]},66 },67 "Logistic Regression": {68 "model": LogisticRegression(max_iter=1000, random_state=42),69 "params": {"C": [0.1, 1, 10]},70 },71 }72 73 best_models = {}74 confusion_matrices = {}75 76 for name, config in param_grids.items():77 logging.info(f"Training {name}...")78 grid_search = GridSearchCV(config["model"], config["params"], cv=5, scoring="accuracy", n_jobs=-1)79 grid_search.fit(X_train, y_train)80 81 best_models[name] = grid_search.best_estimator_82 83 return best_models84 85 86def plot_confusion_matrices(y_test, models, X_test, filename_prefix):87 """Plots and saves confusion matrices for multiple models."""88 for name, model in models.items():89 y_pred = model.predict(X_test)90 cm = confusion_matrix(y_test, y_pred)91 92 plt.figure(figsize=(6, 5))93 sns.heatmap(cm, annot=True, fmt="d", cmap="Blues", xticklabels=np.unique(y_test), yticklabels=np.unique(y_test))94 plt.title(f"Confusion Matrix - {name}")95 plt.xlabel("Predicted")96 plt.ylabel("Actual")97 98 output_path = Path(OUTPUT_DIR) / f"{filename_prefix}_conf_matrix_{name}.png"99 plt.savefig(output_path)100 plt.close()101 102 logging.info(f"Confusion matrix for {name} saved to {output_path}")103 104 105def classify_texture(image, feature_type, model_name):106 """Classifies an input image using the selected feature type and model."""107 image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)108 image = cv2.equalizeHist(image)109 image = cv2.resize(image, IMAGE_SIZE)110 111 if feature_type == "GLCM":112 from feature import compute_glcm_features # Import only when needed113 114 features = compute_glcm_features(image).reshape(1, -1)115 features = scaler_glcm.transform(features)116 prediction = best_models_glcm[model_name].predict(features)[0]117 118 elif feature_type == "LBP":119 from feature import compute_lbp_features120 121 features = compute_lbp_features(image).reshape(1, -1)122 features = scaler_lbp.transform(features)123 prediction = best_models_lbp[model_name].predict(features)[0]124 125 return prediction126 127try:128 # Load datasets129 df_glcm, df_lbp = load_datasets()130 131 # Preprocess GLCM and LBP datasets132 X_train_glcm, X_test_glcm, y_train_glcm, y_test_glcm, scaler_glcm = preprocess_data(df_glcm)133 X_train_lbp, X_test_lbp, y_train_lbp, y_test_lbp, scaler_lbp = preprocess_data(df_lbp)134 135 # Train models separately for GLCM and LBP136 best_models_glcm = train_models(X_train_glcm, y_train_glcm)137 best_models_lbp = train_models(X_train_lbp, y_train_lbp)138 139 # Plot confusion matrices140 plot_confusion_matrices(y_test_glcm, best_models_glcm, X_test_glcm, "GLCM")141 plot_confusion_matrices(y_test_lbp, best_models_lbp, X_test_lbp, "LBP")142 143 # Define Hugging Face App Title144 title = "Texture Classification Using GLCM and LBP"145 146 title += "\n\nUpload image of a texture, choose a feature extraction method, and pick a classifier to predict."147 148 title += "\n\nAppropriate image has little to no noise (only relevant texture)"149 150 # Define path to sample images151 sample_images = [152 ["sample_images/wood1.jpg", "GLCM", "SVM"],153 ["sample_images/brick1.jpg", "LBP", "Random Forest"],154 ["sample_images/stone1.jpg", "GLCM", "k-NN"]155 ]156 157 # Gradio Interface158 interface = gr.Interface(159 fn=classify_texture,160 inputs=[161 gr.Image(type="numpy"),162 gr.Radio(["GLCM", "LBP"], label="Feature Type"),163 gr.Dropdown(choices=list(best_models_glcm.keys()), label="Select Classifier"),164 ],165 outputs=gr.Label(),166 title=title,167 examples=sample_images168 )169 170 logging.info("Launching Gradio interface...")171 interface.launch()172 173except Exception as e:174 logging.error(f"An error occurred: {e}")175 exit(1)176 